Você está recebendo os avisos porque está usando o especificador de formato incorreto em printf()
. p
é um ponteiro inteiro. &p
é o endereço de um ponteiro. &x
e &y
são endereços de inteiros. Estes são todos os endereços na memória, não valores de uma variável. O especificador %u
é para valores de inteiros sem sinal. Então você está imprimindo maçãs onde o compilador espera laranjas. Os endereços são mais curtos do que alguns valores armazenados em variáveis. Ao usar %u
, na verdade, será impresso um valor de endereço como decimal (muito incomum) e mais alguns dados localizados atrás da memória. O compilador está reclamando, porque provavelmente não é isso que você quer fazer. Para imprimir os endereços, use o especificador %p
, como em:
printf("\n&x = %p\n",&x);
Além disso, suas variáveis são números inteiros assinados e, como tal, devem usar %i
em vez de %u
. O especificador de formato %u
de printf()
é apenas para inteiros positivos. Para valores positivos pequenos, %i
e %u
são intercambiáveis. O aviso é exibido porque o tipo de variável não corresponde ao seu especificador e isso causa problemas em alguns casos.
Isso seria mais sensato com seus tipos de variáveis:
printf("\n\np = %p\n", p); // p is a pointer so %p would print the address
printf("\n*p = %i\n", *p); // the data saved at that address is an integer
// so %i is appropriate if you dereference the
// pointer with the star "*p"
printf("\n&x = %p\n", &x); // &x gives the address of the integer variable x
// so %p is the specifier for that address
printf("\n&y = %p\n", &y);
printf("\n&z = %p\n", &z);
printf("\n&p = %p\n\n", &p); // &p gives the address, where the pointer p is
// stored -> still an address -> %p is the right
// specifier
Um fundo de bits em inteiros e ponteiros assinados e não assinados:
C usa o mesmo bit 32 (ou outro poder de dois, dependendo da arquitetura do sistema) para armazenar inteiros não assinados e assinados. Assim, a mais alta unsigned int
é 2 32 -1 ou na notação binária :
2 32 -1 = (11111111111111111111111111111111) 2 & lt; - (sem assinatura)
E o número um ficaria assim em binário:
1 = (00000000000000000000000000000001) 2 & lt; - (sem assinatura)
Agora os números inteiros com sinal regulares também precisam armazenar os números negativos, mas ainda no mesmo espaço de 32 bits. Se você armazenou o sinal, do número em, e. o primeiro bit, você perderia um pouco. Isso seria um desperdício, por exemplo o zero teria duas representações como + e - zero. Para contornar este problema, números negativos em números inteiros são armazenados de forma um pouco diferente : Para codificar um número em um número inteiro com sinal, adicione metade do intervalo possível para o seu número de 32 bits. Isso é 2 (32-1) e, em seguida, use a representação binária regular desse novo número. Então, um é codificado como 2 (32-1) + 1 seria para um inteiro sem sinal. Nós temos:
2 (32-1) = (11111111111111111111111111111111) 2 & lt; -sign
...
1 = (10000000000000000000000000000001) 2 & lt; - assinado
0 = (10000000000000000000000000000000) 2 & lt; - assinado
-1 = (01111111111111111111111111111111) 2 & lt; - assinado
...
-2 (32-1) = (00000000000000000000000000000000) 2 & lt; -sign
Agora você codificou o mesmo número de inteiros, mas o máximo para números inteiros assinados é conseqüentemente apenas 2 (32-1) ao invés de dobrar isso, 2 32 -1, para inteiros sem sinal. Isso é chamado de representação excesso-K ou offset-binary para números negativos. A maioria dos sistemas usa o Complemento de dois , onde o primeiro bit mais significativo é invertido.
Para ver isso, defina x=-1;
e, em seguida, printf("%u",x)
. Você receberá a seguinte saída:
2147483648
Qual é 2 32-1 ou (01111111111111111111111111111111) 2 em notação binária. Para o complemento dos dois, esse número seria:
4294967295
Ou 2 32 -1. Isso é igual a (11111111111111111111111111111111) 2 em binário, então ele tem o primeiro bit invertido comparado ao valor de K-excesso acima de 2147483648.
Portanto, é como os dados são armazenados. Os ponteiros entram em cena quando você pensa no onde . Os bits físicos na memória devem ter endereços. Como há muitos deles, você os aborda em partes de mais de um bit. Se você criar um ponteiro, a memória física no endereço do ponteiro contém outro endereço na memória. Então, uma casa é um objeto físico, muito parecido com um pouco na memória do seu PC. Um pedaço de papel seria um ponteiro. É menor que a casa, mas pode conter o endereço de uma casa ou de outras casas. Nessa analogia, acima você teria tentado demolir o pedaço de papel em vez da casa real e era na verdade uma montanha ...