Como você está aprendendo C, eu recomendo que você tente realmente entender as diferenças entre matrizes e ponteiros primeiro, em vez das coisas comuns .
Na área de parâmetros e matrizes, existem algumas regras confusas que devem ser 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 parâmetro de função em C. Essas são
- Funções como parâmetros
- Matrizes como parâmetros
Matrizes como parâmetros
O segundo talvez não esteja imediatamente claro. Mas fica claro quando você considera que o tamanho de uma dimensão de matriz faz parte do tipo em C (e uma matriz cujo tamanho de dimensão não é fornecido possui um tipo incompleto). Portanto, se você criar uma função que assume um valor por matriz (recebe uma cópia), poderá fazê-lo 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 matriz não existem. Se você deseja obter o valor de uma matriz, o que 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 de matriz 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 é um ponteiro para o primeiro elemento das matrizes.
Excursão: Funções como parâmetros
Para conclusão, e porque acho que isso ajudará você a entender melhor o assunto, vamos ver qual é o estado das coisas quando você tenta ter uma função como parâmetro. De fato, primeiro não fará sentido. Como um parâmetro pode ser uma função? Ah, queremos uma variável nesse local, é claro! Então, o que o compilador faz quando isso acontece é, novamente, transformar a função em um ponteiro de função . Tentar passar uma função passará um ponteiro para a respectiva função. Portanto, o seguinte é o mesmo (análogo ao exemplo da matriz):
void f(void g(void));
void f(void (*g)(void));
Observe que parênteses *g
são necessários. Caso contrário, especificaria uma função retornando void*
, em vez de um ponteiro para uma função retornando void
.
Voltar para matrizes
Agora, eu disse no começo que matrizes podem ter um tipo incompleto - o que acontece se você ainda não fornecer um tamanho. Como já descobrimos que um parâmetro de matriz não existe, mas 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]);
Obviamente, não faz muito sentido ser capaz de colocar qualquer tamanho nele, e é apenas jogado fora. Por esse motivo, o C99 criou 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 poderá alterar "argv" dentro da função - ela se tornou um ponteiro const. Apenas alguns compiladores C suportam esses recursos do C99. Mas esses recursos deixam claro que a "matriz" não é realmente uma. É um ponteiro.
Uma palavra de alerta
Observe que tudo o que eu disse acima é verdadeiro somente quando você tem uma matriz como parâmetro de uma função. 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 ponteiros.
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;