No bit a seguir, os valores e os endereços dos ponteiros diferem conforme o esperado.
Mas valores e endereços de matriz não!
Como isso pode ser?
Resultado
my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>
int main()
{
char my_array[100] = "some cool string";
printf("my_array = %p\n", my_array);
printf("&my_array = %p\n", &my_array);
char *pointer_to_array = my_array;
printf("pointer_to_array = %p\n", pointer_to_array);
printf("&pointer_to_array = %p\n", &pointer_to_array);
printf("Press ENTER to continue...\n");
getchar();
return 0;
}
sizeof(&array)
retorna?Respostas:
O nome de uma matriz geralmente avaliada como o endereço do primeiro elemento da matriz, de modo que
array
e&array
tem o mesmo valor (mas tipos diferentes, de modo quearray+1
e&array+1
vai não ser igual, se a matriz é mais do que um elemento de comprimento).Existem duas exceções: quando o nome da matriz é um operando
sizeof
ou unário&
(endereço de), o nome se refere ao próprio objeto da matriz. Assim,sizeof array
fornece o tamanho em bytes de toda a matriz, não o tamanho de um ponteiro.Para uma disposição como definida
T array[size]
, que terá tipoT *
. Quando / se você incrementa, você chega ao próximo elemento na matriz.&array
avalia para o mesmo endereço, mas, dada a mesma definição, cria um ponteiro do tipoT(*)[size]
- ou seja, é um ponteiro para uma matriz, não para um único elemento. Se você incrementar esse ponteiro, ele adicionará o tamanho de toda a matriz, não o tamanho de um único elemento. Por exemplo, com código como este:Podemos esperar que o segundo ponteiro seja 16 maior que o primeiro (porque é uma matriz de 16 caracteres). Como% p normalmente converte ponteiros em hexadecimal, pode parecer algo como:
fonte
&array
é um ponteiro para o primeiro elemento da matriz, onde, comoarray
se refere a toda a matriz. A diferença fundamental também pode ser observada comparando-sesizeof(array)
comsizeof(&array)
. Observe, no entanto, que se você passaarray
como argumento para uma função, apenas&array
é de fato passado. Você não pode passar uma matriz por valor, a menos que seja encapsulada dentro de astruct
.&array[0]
passado, não o&array
que seria um ponteiro para o array. Pode ser uma escolha difícil, mas acho importante deixar claro; compiladores irá avisar se a função tem um protótipo que corresponde ao tipo do ponteiro passado.int *p = array; int **pp = &p;
.Isso ocorre porque o nome da matriz (
my_array
) é diferente de um ponteiro para a matriz. É um alias para o endereço de uma matriz e seu endereço é definido como o endereço da própria matriz.O ponteiro é uma variável C normal na pilha, no entanto. Assim, você pode pegar o endereço e obter um valor diferente do endereço que ele contém.
Eu escrevi sobre este tópico aqui - por favor, dê uma olhada.
fonte
register
), independentemente da duração do armazenamento: estática, dinâmica ou automática.my_array
em si está na pilha, porquemy_array
é toda a matriz.my_array
, quando não é o assunto dos operadores&
ousizeof
, é avaliado como um ponteiro para seu primeiro elemento (ou seja.&my_array[0]
) - masmy_array
ele próprio não é esse ponteiro (my_array
ainda é o array). Esse ponteiro é apenas um valor efêmero (por exemploint a;
, dado , é exatamente comoa + 1
) - conceitualmente, pelo menos, é "calculado conforme necessário". O verdadeiro "valor" demy_array
é o conteúdo de toda a matriz - é apenas que fixar esse valor em C é como tentar captar neblina em uma jarra.Em C, quando você usa o nome de uma matriz em uma expressão (incluindo a passagem para uma função), a menos que seja o operando do operador address-of (
&
) ou dosizeof
operador, ele decai para um ponteiro para o primeiro elemento.Ou seja, na maioria dos contextos
array
é equivalente&array[0]
em tipo e valor.No seu exemplo,
my_array
tem um tipochar[100]
que decai para achar*
quando você o passa para printf.&my_array
tem tipochar (*)[100]
(ponteiro para uma matriz de 100char
). Como é o operando&
, esse é um dos casos quemy_array
não decai imediatamente para um ponteiro para seu primeiro elemento.O ponteiro para a matriz tem o mesmo valor de endereço que um ponteiro para o primeiro elemento da matriz como um objeto de matriz é apenas uma sequência contígua de seus elementos, mas um ponteiro para uma matriz tem um tipo diferente de ponteiro para um elemento de essa matriz. Isso é importante quando você faz aritmética de ponteiro nos dois tipos de ponteiro.
pointer_to_array
tem typechar *
- inicializado para apontar para o primeiro elemento da matriz, como é o quemy_array
decai na expressão do inicializador - e&pointer_to_array
possui typechar **
(ponteiro para um ponteiro para achar
).Destes:
my_array
(após decaimento parachar*
),&my_array
epointer_to_array
todos apontam diretamente para a matriz ou o primeiro elemento da matriz e, portanto, têm o mesmo valor de endereço.fonte
A razão pela qual
my_array
e o&my_array
resultado no mesmo endereço pode ser facilmente entendida quando você olha para o layout de memória de uma matriz.Digamos que você tenha uma matriz de 10 caracteres (em vez dos 100 no seu código).
Memória para se
my_array
parece com:Em C / C ++, uma matriz decai para o ponteiro para o primeiro elemento em uma expressão como
Se você examinar onde está o primeiro elemento da matriz, verá que seu endereço é o mesmo que o endereço da matriz:
fonte
Na linguagem de programação B, que foi a predecessora imediata de C, ponteiros e números inteiros eram livremente intercambiáveis. O sistema se comportaria como se toda a memória fosse uma matriz gigante. Cada nome de variável tinha um endereço global ou relativo à pilha associado a ele, para cada nome de variável as únicas coisas que o compilador tinha que acompanhar era se era uma variável global ou local e seu endereço relativo ao primeiro local ou global. variável.
Dada uma declaração global como
i;
[não havia necessidade de especificar um tipo, uma vez que tudo foi um inteiro / ponteiro] seria processado pelo compilador como:address_of_i = next_global++; memory[address_of_i] = 0;
e uma declaração comoi++
seria processado como:memory[address_of_i] = memory[address_of_i]+1;
.Uma declaração como
arr[10];
seria processada comoaddress_of_arr = next_global; memory[next_global] = next_global; next_global += 10;
. Observe que, assim que a declaração foi processada, o compilador pode esquecer imediatamente dearr
ser uma matriz . Uma declaração comoarr[i]=6;
seria processada comomemory[memory[address_of_a] + memory[address_of_i]] = 6;
. O compilador não se importaria searr
representasse uma matriz ei
um número inteiro ou vice-versa. Na verdade, não se importaria se eles fossem matrizes ou dois números inteiros; seria perfeitamente feliz em gerar o código conforme descrito, sem considerar se o comportamento resultante provavelmente seria útil.Um dos objetivos da linguagem de programação C era ser amplamente compatível com B. Em B, o nome de uma matriz [chamada de "vetor" na terminologia de B] identificava uma variável segurando um ponteiro que foi inicialmente designado para apontar para para o primeiro elemento de uma alocação do tamanho especificado, portanto, se esse nome aparecesse na lista de argumentos de uma função, a função receberia um ponteiro para o vetor. Embora C tenha adicionado tipos de matrizes "reais", cujo nome estava rigidamente associado ao endereço da alocação, em vez de uma variável de ponteiro que apontaria inicialmente para a alocação, tendo as matrizes decompostas em códigos feitos por ponteiros que declararam que uma matriz do tipo C se comporta de maneira idêntica para o código B que declarou um vetor e nunca modificou a variável que contém seu endereço.
fonte
Na verdade,
&myarray
emyarray
ambos são o endereço base.Se você quiser ver a diferença em vez de usar
usar
fonte