Variabili, puntatori, oggetti e indirizzi di memoria: perché ottengo questo strano risultato?

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

  •  03-07-2019
  •  | 
  •  

Domanda

Dopo aver pensato di aver capito come funzionano, ho provato questo:

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

Il valore di un puntatore (come str1, str2) è un indirizzo di memoria. Quando vai a quell'indirizzo, raggiungi l'area " " nella memoria in cui è archiviato l'oggetto.

Ma: quando assegno str2 a str1, str1 dovrebbe avere come valore l'indirizzo di memoria dello stesso oggetto a cui fa riferimento str2, giusto? La cosa strana qui è che il valore del puntatore rimane lo stesso (indirizzo di memoria bfffd3cc), dove cambia la cosa dietro quell'indirizzo. questo è in realtà completamente logico per me;) perché penso che l'indirizzo di memoria sia l'oggetto (o la casa dell'oggetto nel mattone della memoria, qualunque cosa). Quindi mi aspettavo questo:

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

Altrimenti, non ho ancora capito il punto. La relazione tra il valore della variabile "pointer pointer" e il "valore reale", diciamo l'oggetto che si trova dietro quell'indirizzo di memoria.

È stato utile?

Soluzione

Ricorda che una variabile puntatore è una variabile stessa, quindi ha un indirizzo. Quindi & amp; str1 risulta nell'indirizzo della variabile puntatore, e str1 è un'espressione che si traduce in qualunque cosa la variabile puntatore trattiene - l'indirizzo dell'oggetto a cui punta .

Supponi che:

  • l'oggetto che contiene l'NSString "uno" è all'indirizzo 0x00000100
  • l'oggetto che contiene l'NSString "due" è all'indirizzo 0x00000200

Quindi i tuoi puntatori potrebbero assomigliare a questo:

All'inizializzazione:

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

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

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

Dopo l'assegnazione str1 = str2; :

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

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

Altri suggerimenti

stai stampando il riferimento del tuo puntatore, che è l'indirizzo del puntatore, non il valore del puntatore.

& amp; str1 prende l'indirizzo del puntatore.

Ok, ricorda come abbiamo detto che tutte le cose "vivono" a qualche indirizzo in memoria? E che un puntatore è solo il numero, un numero che è l'indirizzo?

Anche i puntatori sono cose, e come tali hanno hanno indirizzi.

Quando stampi & amp; str1 , stai stampando la memoria occupata dal puntatore. Quando stampi str1 , stai stampando il valore del puntatore, che è l'indirizzo di memoria a cui punta .

Quando stampi * str1 stai dereferenziando il puntatore e stampando che viene stampato il valore indicato.


Per inciso, buon lavoro: ho letto le tue ultime due domande, e tu le stai ricevendo, e al tuo codice di scrittura del credito per dimostrare o confutare che la tua comprensione è corretta. Questo è esattamente ciò che dovresti fare e sei sulla strada giusta.

Parte del problema che stai riscontrando è che le stringhe sono cose divertenti, in quanto una stringa è in realtà un array di caratteri (const) e funzioni come NSLog sono scritte per fare la solita cosa con un puntatore a char, che è per stampare la stringa. Dato un puntatore alla stringa, è davvero un ciclo: dereferenziare il puntatore, stampare il carattere puntato, aggiungerne uno al puntatore, stampare il carattere successivo, fino a quando il carattere indicato è un carattere speciale con il valore 0, a quel punto esso ha trovato la fine della stringa e smette di stampare caratteri.

Potresti trovare tutto questo più facile da capire se usi qualcosa come ints e puntatori a ints.

I puntatori sono, infatti, numeri interi con un'aritmetica dedicata (IIRC, è garantito che sizeof (int) == sizeof (void *))

Se fai riferimento a puntatori, otterrai l'indirizzo in cui è memorizzato; se la variabile è automatica, allora otterrai l'indirizzo nello stack in cui è memorizzato il puntatore: ecco perché ottieni quei risultati.

L'assegnazione si comporta come un'assegnazione tra numeri interi; in effetti:

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

stampe:

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

str1 è un puntatore a un valore NSString .

& amp; str1 significa: l'indirizzo della variabile str1 . Questa è una doppia indiretta.

Suppongo che tu voglia l'indirizzo del valore, cioè str1 stesso, non & amp; str1 .

Supponiamo che il valore dell'oggetto NSString contenente @ " one " si trovi all'indirizzo 0x12345678 e @ " due " ; è in 0x1234ABC0 .

Inizialmente il valore di str1 è 0x12345678 e il valore di str2 è 0x1234ABC0 . Questi due valori sono memorizzati rispettivamente negli indirizzi 0xbfffd3cc e 0xbfffd3c8 . Questi sono gli indirizzi delle variabili str1 e str2 , ovvero i valori di & amp; str1 e & amp; str2 .

Quando scrivi str1 = str2 , l'assegnazione cambia il valore di str1 in modo che corrisponda al valore di str2 , ovvero il valore di str1 è quindi 0x1234ABC0 . Questo è l'indirizzo dell'oggetto @ " two " . Ma l'indirizzo della variabile str1 ( 0xbfffd3cc ) non è cambiato.

Gli oggetti in Objective-C vengono elaborati usando i puntatori. Quindi, per gestire il tuo oggetto NSString, devi prendere un puntatore ad esso. Che cos'è str1, un puntatore a un oggetto NSString.

Se vuoi inviare un messaggio al tuo NSString, puoi usare la sintassi [str1 doSomething].

Se vuoi stampare la tua stringa, devi passare il puntatore a NSLog E dire a NSLog che il puntatore punta a una NSString, che è fatta dalla regola di formattazione "% @ " ;.

Ora, se vuoi solo stampare l'indirizzo indicato da str1, devi comunque passare il puntatore str1 MA devi dire a NSLog che lo stai stampando come valore esadecimale usando la regola di formattazione "% x " ;.

Qualcosa del genere dovrebbe stampare quello che vuoi:

// First print str1 as an hexadecimal value
// Then print the content of the NSString object str1 points to
NSLog(@"str1: %x, %@", str1, str1);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top