Menu

Argumentos de linha de comando em C: argc, argv e como tratá-los com segurança

Como um programa em C lê sua linha de comando - a anatomia de argc e argv, percorrer os argumentos, o que argv[0] guarda, converter números com strtol em vez de atoi, e uma pequena calculadora que junta tudo.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Todo programa que você roda a partir de um terminal pode receber argumentos: gcc -Wall hello.c -o hello passa quatro deles. Seus próprios programas em C leem os seus por meio de dois parâmetros da main, e esse é o mecanismo inteiro - nenhuma chamada de biblioteca, nenhuma preparação.

A assinatura

Até agora todo exemplo nestes docs usou int main(void). A outra forma padrão recebe a linha de comando:

int main(int argc, char *argv[]) {
    /* ... */
}
  • argc ("argument count", contagem de argumentos) é quantos argumentos existem, incluindo o nome do programa.
  • argv ("argument vector", vetor de argumentos) é um array de strings. char *argv[] significa "array de ponteiros para char", que é um array de strings C.

char **argv é uma grafia equivalente que você vai ver com a mesma frequência; parâmetros que são arrays decaem para ponteiros, então as duas declaram a mesma coisa.

Use o painel Args do editor para fornecer os argumentos (cada campo é um argumento), e então rode. Experimente três campos: hello, world, 42.

A anatomia

Rodar ./greet Ada Lovelace produz:

ÍndiceValor
argv[0]"./greet"o nome do programa como foi invocado
argv[1]"Ada"primeiro argumento de verdade
argv[2]"Lovelace"segundo argumento de verdade
argv[3]NULLo terminador
argc3contagem incluindo argv[0]

Quatro fatos que vale memorizar:

  • argc é pelo menos 1 na prática, porque argv[0] é o nome do programa. Os argumentos de verdade começam no índice 1, que é por que laços sobre eles começam em i = 1.
  • Tudo é string. ./prog 42 te dá "42", os dois caracteres, nunca o número 42. Converter é trabalho seu.
  • argv[argc] é NULL. Garantido pelo padrão, então você pode percorrer o array sem argc se preferir: for (char **p = argv + 1; *p != NULL; p++).
  • O shell separa as palavras, não o seu programa. ./prog "Ada Lovelace" é um argumento; as aspas são consumidas pelo shell e nunca chegam ao argv.

Verifique antes de ler

Um argumento que não foi passado não é uma string vazia - é memória que você não tem o direito de tocar. Sempre valide argc primeiro:

Duas convenções nesse programinha, ambas padrão nas ferramentas Unix:

  • A mensagem de uso vai para o stderr, não para o stdout, para não poluir uma saída que esteja sendo canalizada para outro lugar.
  • Um retorno diferente de zero da main sinaliza falha para quem executou o programa. 0 significa sucesso; qualquer outra coisa significa que algo deu errado. Scripts de shell verificam isso.

Imprimir argv[0] em vez de um nome fixo faz a mensagem combinar com o jeito como o usuário invocou o programa, mesmo que ele tenha sido renomeado ou alcançado por outro caminho.

Convertendo argumentos numéricos

argv[1] é texto. Para fazer aritmética você precisa convertê-lo, e a função a usar é a strtol de <stdlib.h>:

Adicione 10, 20 e 30 como três campos de Args, depois troque um por banana para ver o caminho de erro.

O terceiro parâmetro de strtol é a base: 10 para decimal, 16 para hexadecimal, ou 0 para detectar automaticamente a partir de um prefixo 0x ou de um zero à esquerda. O segundo é onde guardar um ponteiro para o primeiro caractere que ele não consumiu, e é isso que torna a verificação de erros possível:

  • end == text significa que nada foi lido - o argumento não começava com um número.
  • *end != '\0' significa que sobrou texto depois do número, então "12abc" é rejeitado em vez de virar silenciosamente 12.
  • errno == ERANGE significa que o valor estourou o long.

Compare com atoi, que é mais curto e não consegue reportar nada disso:

int n = atoi(argv[1]);   /* "banana" -> 0, "0" -> 0, overflow -> indefinido */

atoi retorna 0 para entrada inválida, o que é indistinguível de um zero legítimo. Use strtol (e strtod para ponto flutuante) sempre que a entrada vier de fora do seu programa. Mais em conversão de strings.

Uma pequena calculadora

Juntando tudo - um programa que recebe um número, um operador e um número:

Experimente 12 + 30, depois 7 x 6, depois 5 / 0.

Note strcmp(op, "+") == 0 em vez de op == "+". Comparar valores char * com == compara endereços, não conteúdos, e seria falso mesmo para textos idênticos. Veja funções de string.

O x em vez de * é um detalhe do mundo real: a maioria dos shells expande um * solto na lista de arquivos do diretório atual antes mesmo de o seu programa rodar. Colocá-lo entre aspas ('*') também funciona, mas escolher um caractere que o shell ignora é mais gentil.

Tratando flags

Opções convencionalmente começam com -. Um laço simples feito à mão dá conta dos casos comuns:

Experimente com quatro campos de Args: -v, -n, 3, hello.

A verificação i + 1 >= argc antes de argv[++i] é a linha importante: uma opção que espera um valor precisa confirmar que o valor está realmente lá, ou -n como último argumento lê além do fim do array. Em sistemas Unix de verdade, o getopt de <unistd.h> faz tudo isso por você, incluindo opções curtas agrupadas como -vn3; vale recorrer a ele assim que um programa tem mais de duas ou três flags.

Argumentos no editor do navegador

Os blocos de editor desta página são compilados e executados para você, e o painel Args é onde você digita o que viria depois do nome do programa em um terminal. Cada campo que você adiciona com Add arg vira exatamente uma entrada em argv - não há shell no meio, então nada é separado em espaços e nenhuma aspa é necessária: um campo contendo hello world chega como o único argumento hello world. Para passar -n 3 hello, adicione três campos. Deixar o painel vazio dá argc == 1 - que é por que a guarda argc < 2 dispara na primeira execução, e por que vale escrevê-la.

Erros comuns

  • Ler argv[1] sem verificar argc. Comportamento indefinido quando nenhum argumento foi passado - e o crash mais comum nesta área.
  • Começar o laço em i = 0. Isso processa o nome do programa como se fosse dado.
  • Tratar argv[1] como número. É texto até você converter.
  • Usar atoi em entrada do usuário. Sem jeito de distinguir um argumento ruim de um zero.
  • Comparar strings com ==. Use strcmp.
  • Escrever dentro das strings de argv. Modificá-las é permitido pelo padrão, mas o espaço é limitado e depende da plataforma; copie para o seu próprio buffer se precisar mudar alguma coisa.

Perguntas frequentes

O que são argc e argv em C?

São os dois parâmetros de int main(int argc, char *argv[]). argc é o número de argumentos de linha de comando, incluindo o nome do programa; argv é um array desses argumentos como strings. argv[0] é o nome do programa, argv[1] é o primeiro argumento de verdade, e argv[argc] é sempre NULL.

Como se passa argumentos para um programa em C?

Digite-os depois do nome do executável no terminal: ./program hello 42. Isso dá argc == 3, com argv[1] sendo a string "hello" e argv[2] a string "42". No editor desta página, os argumentos vão no painel Args em vez de um terminal.

Como converter um argumento de linha de comando em int em C?

Use strtol: char *end; long n = strtol(argv[1], &end, 10); e depois verifique que end não continua apontando para o início (nada foi lido) e que *end é '\0' (sem lixo sobrando). atoi é mais curto, mas retorna 0 tanto para "0" quanto para "banana", então não tem como reportar erro.

O que é argv[0] em C?

O nome com que o programa foi invocado - tipicamente ./program ou o caminho completo. É útil em mensagens de uso (fprintf(stderr, "uso: %s ARQUIVO\n", argv[0])) para que a mensagem combine com o jeito como o usuário realmente chamou o programa. Em casos incomuns pode ser uma string vazia, então não presuma que está presente.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR