Somente o *, []e ()os operadores têm qualquer significado em declarações (C ++ acrescenta &, mas não vamos entrar em detalhes aqui).
Na declaração
int *p;
o int-ness de pé especificado pelo especificador de tipo int, enquanto o ponteiro de pé especificado pelo declarador *p .
O tipo de pé "ponteiro para int"; esse tipo é totalmente especificado pela combinação do especificador de tipo intmais o declarador *p.
Em uma declaração, o declarador introduz o nome da coisa que está sendo declarada ( p) junto com informações adicionais sobre o tipo não fornecidas pelo especificador de tipo ("ponteiro para"):
T v; // v is a single object of type T, for any type T
T *p; // p is a pointer to T, for any type T
T a[N]; // a is an N-element array of T, for any type T
T f(); // f is a function returning T, for any type T
Isso é importante - ponteiro, matriz e função são especificados como parte do declarador, não como o especificador de tipo 1 . Se você escrever
int* a, b, c;
será analisado como
int (*a), b, c;
portanto, somente aserá declarado como um ponteiro para int; be csão declarados como ints regulares .
A *, []e ()os operadores podem ser combinados para criar tipos arbitrariamente complexas:
T *a[N]; // a is an N-element array of pointers to T
T (*a)[N]; // a is a pointer to an N-element array of T
T *(*f[N])(); // f is an N-element array of pointers to functions
// returning pointer to T
T *(*(*(*f)[N])())[M] // f is a pointer to an N-element array of pointers
// to functions returning pointers to M-element
// arrays of pointers to T
Observe que *, []e ()obedecem às mesmas regras de precedência em declarações que fazer em expressões. *a[N]é analisado como *(a[N])nas declarações e expressões.
O que é realmente importante perceber é que a forma de uma declaração corresponde à forma da expressão no código. Voltando ao nosso exemplo original, temos um ponteiro para um número inteiro chamado p. Se queremos recuperar esse valor inteiro, usamos o *operador para desreferenciar p, da seguinte forma:
x = *p;
O tipo da expressão *p é intque segue da declaração
int *p;
Da mesma forma, se tivermos uma matriz de ponteiros para doublee desejamos recuperar um valor específico, indexamos na matriz e desreferimos o resultado:
y = *ap[i];
Novamente, o tipo da expressão *ap[i] é double, que segue a declaração
double *ap[N];
Então, por que não ++jogar um papel em uma declaração como *, []ou ()? Ou qualquer outro operador como +ou ->ou &&?
Bem, basicamente, porque a definição da linguagem diz isso. Ele só deixa de lado *, []e ()de desempenhar qualquer papel em uma declaração, uma vez que você tem que ser capaz de especificar ponteiro, matriz e tipos de função. Não há um tipo "increment-this" separado, portanto não há necessidade de ++fazer parte de uma declaração. Não há nenhuma "-este bit a bit" tipo, por isso não há necessidade de unário &, |, ^, ou ~para ser parte de uma declaração de qualquer um. Para tipos que usam o .operador de seleção de membro, usamos as tags structe unionna declaração. Para tipos que usam o ->operador, usamos as tags structe unionem conjunto com o *operador no declarador.
- Obviamente, você pode criar nomes de typedef para tipos de ponteiro, matriz e função, como
typedef int *iptr;
iptr a,b,c; // all three of a, b, and c are pointers to int
mas, novamente, é o declarador *iptr que especifica o ponteiro do nome do typedef.
void move(int *units) { ... }, é um operador indireto. Considerado parte do tipo, também pode ser escritovoid move(int* units) { ... }, embora eu prefira o estilo anterior. Você lê os dois como "int ponteiro". Veja também stackoverflow.com/a/8911253