Devo usar char ** argv ou char * argv em C?

Eu só estou aprendendo C e queria saber qual desses eu deveria usar no meu método principal. Existe alguma diferença?

Edit: Então, qual é o mais comum de usar?

Como você está apenas aprendendo C, eu recomendo que você realmente tente entender as diferenças entre arrays e pointers em vez das coisas comuns .

Na área de parâmetros e matrizes, existem algumas regras confusas que devem ficar claras antes de prosseguir. Primeiro, o que você declara em uma lista de parâmetros é tratado como especial. Existem situações em que as coisas não fazem sentido como um parâmetro de function em C. Estas são

  • Funciona como parâmetros
  • Matrizes como parâmetros

Matrizes como parâmetros

O segundo talvez não seja imediatamente claro. Mas fica claro quando você considera que o tamanho de uma dimensão de matriz é parte do tipo em C (e uma matriz cujo tamanho de dimensão não é dado tem um tipo incompleto). Então, se você cria uma function que recebe uma matriz por valor (recebe uma cópia), ela pode fazer isso apenas para um tamanho! Além disso, as matrizes podem se tornar grandes e C tenta ser o mais rápido possível.

Em C, por esses motivos, os valores de array não existem. Se você deseja obter o valor de uma matriz, o que você obtém é um ponteiro para o primeiro elemento dessa matriz. E aqui na verdade já está a solução. Em vez de desenhar um parâmetro array inválido antecipadamente, um compilador C transformará o tipo do respectivo parâmetro em um ponteiro. Lembre-se disso, é muito importante. O parâmetro não será uma matriz, mas será um ponteiro para o respectivo tipo de elemento.

Agora, se você tentar passar uma matriz, o que é passado em vez disso é um ponteiro para o primeiro elemento das matrizes.

Excursão: funciona como parâmetros

Para conclusão, e porque eu acho que isso vai ajudar você a entender melhor o assunto, vamos ver qual é o estado de coisas quando você tenta ter uma function como parâmetro. De fato, primeiro não faz sentido. Como um parâmetro pode ser uma function? Huh, queremos uma variável naquele lugar, claro! Então, o que o compilador faz quando isso acontece é, novamente, transformar a function em um ponteiro de function . Tentar passar uma function passará um ponteiro para essa function respectiva. Então, o seguinte é o mesmo (análogo ao exemplo da matriz):

 void f(void g(void)); void f(void (*g)(void)); 

Note que parênteses em torno de *g são necessários. Caso contrário, ele especificaria uma function retornando void* , em vez de um ponteiro para uma function retornando void .

Voltar para matrizes

Agora, eu disse no começo que os arrays podem ter um tipo incompleto – o que acontece se você não der um tamanho ainda. Como já imaginamos que um parâmetro de matriz não existe, mas em vez disso, qualquer parâmetro de matriz é um ponteiro, o tamanho da matriz não importa. Isso significa que o compilador traduzirá todos os itens a seguir e todos são a mesma coisa:

 int main(int c, char **argv); int main(int c, char *argv[]); int main(int c, char *argv[1]); int main(int c, char *argv[42]); 

Claro, não faz muito sentido ser capaz de colocar qualquer tamanho nele, e é simplesmente jogado fora. Por esse motivo, o C99 surgiu com um novo significado para esses números e permite que outras coisas apareçam entre os colchetes:

 // says: argv is a non-null pointer pointing to at least 5 char*'s // allows CPU to pre-load some memory. int main(int c, char *argv[static 5]); // says: argv is a constant pointer pointing to a char* int main(int c, char *argv[const]); // says the same as the previous one int main(int c, char ** const argv); 

As duas últimas linhas dizem que você não será capaz de alterar “argv” dentro da function – ela se tornou um ponteiro const. Apenas alguns compiladores C suportam esses resources C99. Mas esses resources deixam claro que o “array” não é realmente um. É um ponteiro.

Uma palavra de alerta

Note que tudo o que eu disse acima é verdade apenas quando você tem um array como parâmetro de uma function. Se você trabalha com matrizes locais, uma matriz não será um ponteiro. Ele se comportará como um ponteiro, porque, como explicado anteriormente, uma matriz será convertida em um ponteiro quando seu valor for lido. Mas não deve ser confundido com pointers.

Um exemplo clássico é o seguinte:

 char c[10]; char **c = &c; // does not work. typedef char array[10]; array *pc = &c; // *does* work. // same without typedef. Parens needed, because [...] has // higher precedence than '*'. Analogous to the function example above. char (*array)[10] = &c; 

Você pode usar qualquer um, isso depende de como você deseja usá-lo. char* argv[] é (principalmente) equivalente a char ** argv . Ambos os formulários são ponteiro para pointers para char, a única diferença é que com char *argv[] você está informando ao compilador que o valor de argv não irá mudar (embora os valores para os quais ele aponta ainda possam). Na verdade, estou errado, eles são completamente equivalentes. Veja os comentários de litb e sua resposta .

Isso realmente depende de como você deseja usá-lo (e você pode usá-lo em qualquer caso):

 // echo-with-pointer-arithmetic.c #include  int main(int argc, char **argv) { while (--argc > 0) { printf("%s ", *++argv); } printf("\n"); return 0; } // echo-without-pointer-arithmetic.c #include  int main(int argc, char *argv[]) { int i; for (i=1; i 

Quanto ao que é mais comum - não importa. Qualquer programador C experiente lendo seu código verá ambos como intercambiáveis ​​(sob as condições corretas). Assim como um palestrante experiente diz "eles são" e "eles são" igualmente facilmente.

Mais importante é que você aprenda a lê-los e reconheça como eles são semelhantes. Você estará lendo mais código do que você escreve, e você precisará estar igualmente confortável com ambos.

Você pode usar qualquer um dos dois formulários, como em arrays C e os pointers são intercambiáveis ​​nas listas de parâmetros de function. Veja http://en.wikipedia.org/wiki/C_(programming_language) # Array- pointer_interchangeability .

Não faz diferença, mas eu uso o char *argv[] porque ele mostra que é uma matriz de tamanho fixo de strings de comprimento variável (que geralmente são char * ).

Não faz diferença, mas o último é mais legível. O que você é dado é uma matriz de pointers de caracteres, como a segunda versão diz. Ele pode ser implicitamente convertido em um ponteiro de caractere duplo, como na primeira versão, no entanto.

char ** → ponteiro para ponteiro de caractere e char * argv [] significa array de pointers de caractere. Como podemos usar o ponteiro em vez de um array, ambos podem ser usados.

você deve declará-lo como char *argv[] , por causa de todas as muitas formas equivalentes de declará-lo, que mais se aproxima de seu significado intuitivo: um array de strings.

Não vejo nenhum mérito especial de usar uma das abordagens em vez da outra – use a convenção que esteja mais alinhada com o resto do seu código.

Se você precisar de um número variável ou dynamic de strings, o char ** pode ser mais fácil de se trabalhar. Se você tiver um número de string fixo, char * var [] seria o preferido.

Eu sei que isso está desatualizado, mas se você está apenas aprendendo a linguagem de programação C e não está fazendo nada de importante com isso, não use opções de linha de comando.

Se você não estiver usando argumentos de linha de comando, não use nenhum deles. Apenas declare a function principal como int main() Se você

  • Deseja que o usuário do seu programa possa arrastar um arquivo para o seu programa para que você possa alterar o resultado do seu programa com ele ou
  • Deseja manipular as opções de linha de comando ( -help , /? Ou qualquer outra coisa que vá após o program name no terminal ou no prompt de comando)

use o que fizer mais sentido para você. Caso contrário, use apenas int main() Afinal, se você quiser adicionar opções de linha de comando, poderá editá-las facilmente mais tarde.