Variáveis, ponteiros, objetos e endereços de memória: Por que recebo este resultado estranho?
-
03-07-2019 - |
Pergunta
Depois eu pensei que eu entendi como eles funcionam, eu tentei isso:
NSString *str1 = [NSString stringWithCString:"one"];
NSString *str2 = [NSString stringWithCString:"two"];
NSLog(@"str1: %x, %@", &str1, str1); //bfffd3cc, one
NSLog(@"str2: %x, %@", &str2, str2); //bfffd3c8, two
str1 = str2;
NSLog(@"str1: %x, %@", &str1, str1); //bfffd3cc, two
O valor de um ponteiro (como str1, str2) é um endereço de memória. Quando você vai para esse endereço, você chegar a "área" em memória onde o objeto está armazenado.
Mas: Quando eu str2 atribuir a str1, str1 deve ter como valor o endereço de memória do mesmo objeto que é referenciado por str2, certo? O estranho aqui é que o valor do ponteiro permanece a mesma (endereço de memória bfffd3cc), onde a coisa por trás dessa mudança de endereço. isso é realmente completamente unlogical para mim;) porque eu acho que o endereço de memória é o objeto (ou a casa do objeto no tijolo de memória, o que nunca). Então, eu esperava isso:
NSString *str1 = [NSString stringWithCString:"one"];
NSString *str2 = [NSString stringWithCString:"two"];
NSLog(@"str1: %x, %@", &str1, str1); //bfffd3cc, one
NSLog(@"str2: %x, %@", &str2, str2); //bfffd3c8, two
str1 = str2;
NSLog(@"str1: %x, %@", &str1, str1); //bfffd3c8, two
Caso contrário, eu ainda não chegar ao ponto. A relação entre o valor da "variável de ponteiro" e o "valor real", vamos dizer que o objeto que está sentado atrás de que o endereço de memória.
Solução
Lembre-se que uma variável ponteiro é uma variável em si, por isso tem um endereço. Assim resultados &str1
no endereço da variável ponteiro, e str1
é uma expressão que resulta em qualquer que seja a variável ponteiro está segurando -. O endereço do objeto que ele está apontando para
Suponha que:
- o objeto segurando o NSString "um" é no endereço 0x00000100
- o objeto segurando o NSString "dois" é no endereço 0x00000200
Em seguida, seus ponteiros poderia ser algo como isto:
Na inicialização:
str1
0xbfffd3c8 +---------------+
| |
| 0x00000100 |
| ("one") |
+---------------+
str2
0xbfffd3cc +---------------+
| |
| 0x00000200 |
| ("two") |
+---------------+
=======================================
Após a atribuição str1 = str2;
:
str1
0xbfffd3c8 +---------------+
| |
| 0x00000200 |
| ("two") |
+---------------+
str2
0xbfffd3cc +---------------+
| |
| 0x00000200 |
| ("two") |
+---------------+
Outras dicas
estiver imprimindo a referência do ponteiro, que é o endereço do ponteiro, e não o valor do ponteiro.
&str1
leva o endereço do ponteiro.
Ok, me lembro como nós dissemos que todas as coisas "ao vivo" em algum endereço na memória? E que um ponteiro é apenas o número, um número que é o endereço?
ponteiros Bem são coisas também, e, como tal, que ter endereços.
Quando você imprimir &str1
, você está imprimindo a memória ocupada pelo ponteiro. Quando você imprimir str1
, você está imprimindo o valor do ponteiro, que é o endereço de memória que pontos para .
Quando você imprimir *str1
você está dereferencing o ponteiro, e imprimir que imprime o valor apontado.
Aliás, bom trabalho: Eu li suas duas últimas perguntas, e você está recebendo-o e ao seu código escrito de crédito para provar ou refutar que o seu entendimento está correto. Este é exatamente o que você deve fazer, e você está no caminho certo.
Parte do problema que você está tendo é que as cordas são coisas engraçadas, em que uma seqüência realmente um array de caracteres (const), e funções como NSLog são escritos para fazer a coisa habitual com um ponteiro para char, que é para imprimir a string. Dado um ponteiro para seqüência, é realmente looping: dereferencing o ponteiro, imprimir o caráter apontou-a, adicionando um ao ponteiro, imprimir o carácter seguinte, até que o caractere apontado é um caractere especial com o valor 0, altura em que encontrou o fim da cadeia e pára de imprimir caracteres.
Você pode encontrar tudo isso mais fácil de entender se você usar algo como ints e ponteiros para ints.
Os ponteiros são, na verdade, inteiros com uma aritmética dedicado (IIRC, é garantido que sizeof (int) == sizeof (void *))
Se você faz referência ponteiros, você poderá obter o endereço onde ele é armazenado; se a variável é automático, então você vai obter o endereço na pilha onde o ponteiro é armazenado:. é por isso que você obter esses resultados
comportam Assignment como atribuição entre números inteiros; de fato:
#include <stdio.h>
int main() {
char *str1 = "Ciao";
char *str2 = "Mondo";
printf("%x\n", str1);
printf("%x\n", str2);
str1 = str2;
printf("%x\n", str1);
}
impressões:
:~$ ./a.out
80484f8
80484fd
80484fd
str1
é um ponteiro para um valor NSString
.
meios &str1
: o endereço da variável str1
. Este é um engano duplo.
Eu acho que você quer o endereço do valor, ou seja, str1
si só, não &str1
.
Vamos supor que o valor NSString
objeto contendo @"one"
está localizado na 0x12345678
endereço e @"two"
está em 0x1234ABC0
.
Inicialmente o valor de str1
é 0x12345678
eo valor da str2
é 0x1234ABC0
.
Estes dois valores são armazenados na memória, respectivamente, nos endereços 0xbfffd3cc
e 0xbfffd3c8
. Estes são os endereços dos str1
e str2
variáveis, ou seja, valores de &str1
e &str2
.
Quando você escreve str1 = str2
, a atribuição altera o valor de str1
ser o mesmo que o valor de str2
, ou seja, o valor de str1
é então 0x1234ABC0
. Este é o endereço do objeto @"two"
. Mas endereço da variável str1
(0xbfffd3cc
) não é alterado.
Objetos em Objective-C são trabalhadas usando ponteiros. Assim, a fim de lidar com o seu objeto NSString, você tem que tomar um ponteiro para ele. Que é o que str1 é, um ponteiro para um objeto NSString.
Se você quiser enviar uma mensagem para o NSString, você pode usar a sintaxe [str1 doSomething].
Se você deseja imprimir sua seqüência, você tem que passar o ponteiro para NSLog e dizer NSLog que o ponteiro aponta para um NSString, que é feito pela regra formatação "% @".
Agora, se você só quer imprimir o endereço apontado por str1, você ainda tem que passar o str1 ponteiro, mas você deve dizer NSLog que você está imprimindo-o como um valor hexadecimal usando a regra de formatação "% x".
Algo assim deve imprimir o que você quer:
// First print str1 as an hexadecimal value
// Then print the content of the NSString object str1 points to
NSLog(@"str1: %x, %@", str1, str1);