Variables, punteros, objetos y direcciones de memoria: ¿Por qué obtengo este resultado extraño?

StackOverflow https://stackoverflow.com/questions/802717

  •  03-07-2019
  •  | 
  •  

Pregunta

Después de que pensé que había entendido cómo funcionan, intenté esto:

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

El valor de un puntero (como str1, str2) es una dirección de memoria. Cuando vaya a esa dirección, llegará al área " " " en la memoria donde se almacena el objeto.

Pero: cuando asigno str2 a str1, str1 debe tener como valor la dirección de memoria del mismo objeto al que hace referencia str2, ¿verdad? Lo extraño aquí es que el valor del puntero permanece igual (dirección de memoria bfffd3cc), donde cambia la cosa detrás de esa dirección. para mí eso es completamente nada lógico;) porque creo que la dirección de la memoria ES el objeto (o la casa del objeto en el ladrillo de la memoria, como sea). Así que esperaba esto:

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

De lo contrario, todavía no entendí el punto. La relación entre el valor de la " variable de puntero " y el " valor real " ;, digamos el objeto que se encuentra detrás de esa dirección de memoria.

¿Fue útil?

Solución

Recuerde que una variable de puntero es una variable en sí misma, por lo que tiene una dirección. Por lo tanto, & amp; str1 da como resultado la dirección de la variable del puntero, y str1 es una expresión que da como resultado la retención de la variable del puntero: la dirección del objeto al que apunta .

Supongamos que:

  • el objeto que contiene el NSString " uno " está en la dirección 0x00000100
  • el objeto que contiene la NSString " dos " está en la dirección 0x00000200

Entonces, tus punteros podrían verse algo como esto:

En la inicialización:

str1
0xbfffd3c8  +---------------+
            |               |
            |  0x00000100   |
            |    ("one")    |
            +---------------+

str2
0xbfffd3cc  +---------------+
            |               |
            |  0x00000200   |
            |    ("two")    |
            +---------------+

=======================================

Después de la asignación str1 = str2; :

str1
0xbfffd3c8  +---------------+
            |               |
            |  0x00000200   |
            |    ("two")    |
            +---------------+

str2
0xbfffd3cc  +---------------+
            |               |
            |  0x00000200   |
            |    ("two")    |
            +---------------+

Otros consejos

está imprimiendo la referencia de su puntero, que es la dirección del puntero, no el valor del puntero.

& amp; str1 toma la dirección del puntero.

Bien, recuerda cómo dijimos que todas las cosas " en vivo " en alguna direccion en la memoria? Y que un puntero es solo el número, un número que es la dirección?

Los punteros de los pozos también son cosas, y como tales ellos tienen direcciones.

Cuando imprime & amp; str1 , está imprimiendo la memoria ocupada por el puntero. Cuando imprime str1 , imprime el valor del puntero, que es la dirección de memoria que apunta a .

Cuando imprime * str1 , está eliminando la referencia del puntero, e imprimiendo que imprime el valor apuntado.


Por cierto, buen trabajo: he leído sus últimas dos preguntas y lo está recibiendo, y con su código de crédito para demostrar o refutar que su comprensión es correcta. Esto es exactamente lo que deberías estar haciendo, y estás en el camino correcto.

Parte del problema que tienes es que las cadenas son cosas graciosas, ya que una cadena realmente es una matriz de caracteres (const), y funciones como NSLog están escritas para hacer lo habitual con un puntero a char, que es para imprimir la cadena. Dado un puntero a la cadena, es realmente un bucle: desreferenciación del puntero, imprimiendo el carácter apuntado a, agregando uno al puntero, imprimiendo el siguiente carácter, hasta que el carácter apuntado es un carácter especial con el valor 0, en cuyo punto ha encontrado el final de la cadena y deja de imprimir caracteres.

Es posible que encuentre todo esto más fácil de entender si usa algo como ints y punteros a ints.

Los punteros son, de hecho, enteros con una aritmética dedicada (IIRC, se garantiza que sizeof (int) == sizeof (void *))

Si hace referencia a los punteros, obtendrá la dirección donde está almacenado; Si la variable es automática, obtendrás la dirección en la pila donde se almacena el puntero: por eso obtienes esos resultados.

La asignación se comporta como una asignación entre enteros; de hecho:

#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);
}

impresiones:

:~$ ./a.out
80484f8
80484fd
80484fd

str1 es un puntero a un valor de NSString .

& amp; str1 significa: la dirección de la variable str1 . Esto es un doble direccionamiento indirecto.

Supongo que quieres la dirección del valor, es decir, str1 , no & amp; str1 .

Supongamos que el valor del objeto NSString que contiene @ " one " se encuentra en la dirección 0x12345678 y @ " dos " ; está en 0x1234ABC0 .

Inicialmente, el valor de str1 es 0x12345678 y el valor de str2 es 0x1234ABC0 . Estos dos valores se almacenan en la memoria, respectivamente, en las direcciones 0xbfffd3cc y 0xbfffd3c8 . Estas son las direcciones de las variables str1 y str2 , es decir, los valores de & amp; str1 y & amp; str2 .

Cuando escribe str1 = str2 , la asignación cambia el valor de str1 para que sea igual al valor de str2 , es decir, el valor de str1 es entonces 0x1234ABC0 . Esta es la dirección del objeto @ " dos " . Pero la dirección de la variable str1 ( 0xbfffd3cc ) no se cambia.

Los objetos en Objective-C se trabajan utilizando punteros. Entonces, para manejar su objeto NSString, debe llevar un puntero hacia él. Que es lo que es str1, un puntero a un objeto NSString.

Si desea enviar un mensaje a su NSString, puede usar la sintaxis [str1 doSomething].

Si desea imprimir su cadena, debe pasar el puntero a NSLog AND indicar a NSLog que el puntero apunta a una NSString, que se realiza mediante la regla de formato "% @ " ;.

Ahora, si solo desea imprimir la dirección apuntada por str1, todavía tiene que pasar el puntero str1 PERO debe decirle a NSLog que lo está imprimiendo como un valor hexadecimal usando la regla de formato "% x " ;.

Algo así debería imprimir lo que quieres:

// First print str1 as an hexadecimal value
// Then print the content of the NSString object str1 points to
NSLog(@"str1: %x, %@", str1, str1);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top