O que significa int argc, char * argv []?

508

Em muitos IDE e compiladores C ++, quando gera a função principal para você, fica assim:

int main(int argc, char *argv[])

Quando codifico C ++ sem um IDE, apenas com um compilador de linha de comando, digito:

int main()

sem nenhum parâmetro. O que isso significa e é vital para o meu programa?

Greg Treleaven
fonte
47
Se o seu programa vai ignorar os argumentos da linha de comando, o que você escreve está bem. Se o seu programa precisar processar argumentos de linha de comando, o IDE estará fazendo isso corretamente.
Jonathan Leffler
30
Uma dica para hackers: tente declarar int main(int argc, char* argv[], char* envp[])e imprimir o último argumento. ;)
ulidtko
7
@ulidtko não é bom que você está ensinando os novatos para introduzir vulnerabilidade em seus programas;)
Gab是好人
13
@Gab Como a impressão simples de variáveis ​​de ambiente leva à vulnerabilidade? Apenas não passe as strings contaminadas literalmente para system()chamadas, consultas de banco de dados, etc. Como sempre, com a entrada do usuário.
ulidtko
2
@ulidtko Interessante .. Você pode explicar por que não precisa passar seqüências de caracteres contaminadas, consultas de banco de dados, etc. enquanto usa char **envpargumento?
Master James

Respostas:

651

argve argcé como os argumentos da linha de comando são transmitidos para main()C e C ++.

argcserá o número de cadeias apontadas por argv. (Na prática) será 1 mais o número de argumentos, pois praticamente todas as implementações incluirão o nome do programa na matriz.

As variáveis ​​são nomeadas argc( contagem de argumentos ) e argv( vetor de argumento ) por convenção, mas podem receber qualquer identificador válido: int main(int num_args, char** arg_strings)é igualmente válido.

Eles também podem ser omitidos inteiramente, produzindo int main(), se você não pretende processar argumentos da linha de comandos.

Tente o seguinte programa:

#include <iostream>

int main(int argc, char** argv) {
    std::cout << "Have " << argc << " arguments:" << std::endl;
    for (int i = 0; i < argc; ++i) {
        std::cout << argv[i] << std::endl;
    }
}

Executá-lo com ./test a1 b2 c3saída

Have 4 arguments:
./test
a1
b2
c3
magro
fonte
8
argcpode ser 0; nesse caso, argvpode ser NULL. É permitido pelo AFAIK padrão. Nunca ouvi falar de um sistema que faça isso na prática, mas certamente poderia existir e não estaria violando nenhum padrão.
Chuck
77
@ Chuck: Como "O valor de argv[argc]deve ser 0" (C ++ 03 §3.6.1 / 2), argvnão pode ser nulo.
James McNellis
20
@ Chuck: C (pelo menos C99) tem o mesmo requisito.
James McNellis
2
Penso que devo acrescentar que isso é o mesmo na maioria dos sistemas, embora sejam abstraídos algumas vezes. Por exemplo, em Pascal / Delphi / Lazarus, você obtém; ParamStr e ParamCount (se a memória me servir bem). Meu argumento é que, quando você (se alguma vez) escreve aplicativos nativos em outros idiomas / arquivos, há uma boa chance de que o descrito acima seja definido para você usar, e eles funcionam perfeitamente da mesma maneira (lista de contagem / string) em todos os sistemas que suportam eles.
Christian
8
@ EmilVikström Não, esse é um erro sério que provavelmente resulta em um segfault. *NULLdefinitivamente não é igual a NULL.
meagar
52

argcé o número de argumentos que estão sendo passados ​​para o seu programa a partir da linha de comando e argvé a matriz de argumentos.

Você pode percorrer os argumentos sabendo o número deles, como:

for(int i = 0; i < argc; i++)
{
    // argv[i] is the argument at index i
}
John Boker
fonte
19

Suponha que você execute seu programa assim (usando shsintaxe):

myprog arg1 arg2 'arg 3'

Se você declarou seu principal como int main(int argc, char *argv[]), então (na maioria dos ambientes), você main()será chamado como se fosse:

p = { "myprog", "arg1", "arg2", "arg 3", NULL };
exit(main(4, p));

No entanto, se você declarou seu principal como int main(), ele será chamado de algo como

exit(main());

e você não passa os argumentos.

Duas coisas adicionais a serem observadas:

  1. Essas são as únicas duas assinaturas com mandato padrão para main. Se uma plataforma específica aceita argumentos extras ou um tipo de retorno diferente, é uma extensão e não deve ser invocada em um programa portátil.
  2. *argv[]e **argvsão exatamente equivalentes, para que você possa escrever int main(int argc, char *argv[])como int main(int argc, char **argv).
Toby Speight
fonte
2
Se estamos sendo técnicos, basic.start.main/2permite explicitamente versões adicionais definidas pela implementação main(), desde que a implementação forneça as duas versões predefinidas. Portanto, eles não são exatamente não-conformes. O mais comum é envp, que é tão bem conhecido em C e C ++ que é literalmente a primeira entrada na secção J.5 (extensões comuns) do padrão C .
Justin Time - Restabelece Monica
1
Obrigado pelo bom pedantismo @ Justin. Resposta atualizada para ser mais correta.
Toby Speight
Não faço ideia - sugiro que você crie um exemplo mínimo reproduzível e pergunte (assumindo que o processo não seja suficiente para ajudá-lo a responder você mesmo).
precisa
9

Os parâmetros para mainrepresentar os parâmetros da linha de comandos fornecidos ao programa quando ele foi iniciado. O argcparâmetro representa o número de argumentos da linha de comando e char *argv[]é uma matriz de seqüências de caracteres (ponteiros de caracteres) representando os argumentos individuais fornecidos na linha de comando.

BlueMonkMN
fonte
2
Argv [] sempre tem argv [arg] como um ponteiro nulo. e Argv [0] é sempre o (caminho completo) / executableName como uma cadeia de caracteres terminada em nul
user3629249
3
@ user3629249: Não necessariamente; argv[0]é o que o programa que iniciou o programa C deu como argv[0]. No caso do Bash, geralmente é (talvez sempre) o nome do caminho do executável, mas o Bash não é o único programa que executa outros programas. É permissisble, embora excêntrica, para usar: char *args[] = { "cat", "/dev/null", "/etc/passwd", 0 }; execv("/bin/ls", args);. Em muitos sistemas, o valor visto pelo programa como argv[0]será cat, mesmo que o executável seja /bin/ls.
Jonathan Leffler
7

A mainfunção pode ter dois parâmetros, argce argv. argcé um intparâmetro inteiro ( ) e é o número de argumentos passados ​​para o programa.

O nome do programa é sempre o primeiro argumento; portanto, haverá pelo menos um argumento para um programa e o valor mínimo de argcserá um. Mas se um programa tiver dois argumentos, o valor de argcserá três.

O parâmetro argvaponta para uma matriz de cadeias e é chamado de vetor de argumento . É uma matriz de cadeias unidimensionais de argumentos de função.

moshtagh
fonte
5
int main();

Esta é uma declaração simples. Não pode aceitar nenhum argumento de linha de comando.

int main(int argc, char* argv[]);

Esta declaração é usada quando seu programa deve receber argumentos de linha de comando. Quando executado assim:

myprogram arg1 arg2 arg3

argc, ou Contagem de argumentos, será definido como 4 (quatro argumentos) e argv, ou Vetores de argumentos, serão preenchidos com ponteiros de seqüência de caracteres para "meuprograma", "arg1", "arg2" e "arg3". A chamada do programa ( myprogram) está incluída nos argumentos!

Como alternativa, você pode usar:

int main(int argc, char** argv);

Isso também é válido.

Há outro parâmetro que você pode adicionar:

int main (int argc, char *argv[], char *envp[])

O envpparâmetro também contém variáveis ​​de ambiente. Cada entrada segue este formato:

VARIABLENAME=VariableValue

como isso:

SHELL=/bin/bash    

A lista de variáveis ​​de ambiente é terminada por nulo.

IMPORTANTE: NÃO use qualquer argvou envpvalores diretamente em chamadas para system()! Essa é uma enorme falha de segurança, pois usuários mal-intencionados podem definir variáveis ​​de ambiente para comandos da linha de comando e (potencialmente) causar danos enormes. Em geral, apenas não use system(). Quase sempre há uma solução melhor implementada através das bibliotecas C.

adrian
fonte
3

O primeiro parâmetro é o número de argumentos fornecidos e o segundo parâmetro é uma lista de cadeias que representam esses argumentos.

Nick Gerakines
fonte
7
a primeira entrada em argv [0] é o nome do programa, não um argumento
user3629249
@ user3629249 Nome do programa com o caminho do programa. ;)
Master James
1

Ambos

int main(int argc, char *argv[]);
int main();

são definições legais do ponto de entrada para um programa C ou C ++. Stroustrup: As Perguntas frequentes sobre estilo e técnica C ++ detalham algumas das variações possíveis ou legais para sua função principal.

Chris Becke
fonte
4
Pode querer anular ... int main()==> int main(void)... para compatibilidade e legibilidade. Não sei se todas as versões mais antigas do C permitem que funções void tenham uma lista de parâmetros vazia na declaração.
Dllnmc
1
@dylnmc isso não dá nenhum ganho de legibilidade e é exatamente equivalente em todas as versões do C ++. Somente em C isso tem diferença, mas apenas nas declarações, não na definição.
Ruslan
@Ruslan Desculpe, eu postei isso quando eu estava apenas aprendendo C, e eu poderia ter lido que em versões muito antigas de C voidé necessário. Não me cite, e agora sei que é um comentário um pouco tolo. Não pode doer, no entanto.
Dllnmc
e se argc <3 retornar um erro? o que poderia dar errado?
AVI