Переменные, указатели, объекты и адреса памяти: почему я получаю этот странный результат? - PullRequest
3 голосов
/ 29 апреля 2009

После того, как я подумал, что понял, как они работают, я попробовал это:

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

Значение указателя (например, str1, str2) является адресом памяти. Когда вы переходите по этому адресу, вы попадаете в «область» памяти, где хранится объект.

Но: когда я назначаю str2 для str1, str1 должен иметь в качестве значения адрес памяти того же объекта, на который ссылается str2, верно? Странная вещь здесь в том, что значение указателя остается тем же (адрес памяти bfffd3cc), где вещь за этим адресом изменяется. это на самом деле совершенно нелогично для меня;) потому что я думаю, что адрес памяти - это объект (или дом объекта в блоке памяти, что угодно). Так что я ожидал этого:

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

В противном случае, я все еще не понял суть. Соотношение между значением «переменной-указателя» и «действительным значением», скажем, объекта, который находится за этим адресом памяти.

Ответы [ 6 ]

9 голосов
/ 29 апреля 2009

Помните, что указатель переменной является самой переменной, поэтому он имеет адрес. Таким образом, &str1 приводит к адресу переменной указателя, а str1 является выражением, которое приводит к тому, что содержит указатель переменной - адрес объекта, на который она указывает.

Предположим, что:

  • объект, содержащий строку NSString, находится по адресу 0x00000100
  • объект, содержащий строку NSString "два", находится по адресу 0x00000200

Тогда ваши указатели могут выглядеть примерно так:

При инициализации:

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

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

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

После назначения str1 = str2;:

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

str2
0xbfffd3cc  +---------------+
            |               |
            |  0x00000200   |
            |    ("two")    |
            +---------------+
2 голосов
/ 29 апреля 2009

&str1 принимает адрес указателя.

Хорошо, помните, как мы говорили, что все вещи «живут» по какому-то адресу в памяти? И что указатель - это просто число, число, которое является адресом?

Ну, указатели тоже вещи, и поэтому у них есть адреса.

Когда вы печатаете &str1, вы печатаете память, занятую указателем. Когда вы печатаете str1, вы печатаете значение указателя, то есть адрес памяти, на который он указывает .

Когда вы печатаете *str1, вы разыменовываете указатель, и печатаете , что печатает указанное значение.


Кстати, хорошая работа: я прочитал ваши последние два вопроса, и вы получили его, а также ваш кредитный код, чтобы доказать или опровергнуть правильность вашего понимания. Это именно то, что вы должны делать, и вы на правильном пути.

Отчасти проблема, с которой вы сталкиваетесь, заключается в том, что строки - это забавные вещи, поскольку строка действительно представляет собой массив (const) символов, а функции, такие как NSLog, написаны так, чтобы выполнять обычные действия с указателем на char, который распечатать строку. Имея указатель на строку, он действительно зацикливается: разыменовывает указатель, печатает указательный символ, добавляет его к указателю, печатает следующий символ, пока указанный символ не станет специальным символом со значением 0, и в этот момент он нашла конец строки и прервала печать символов.

Возможно, вам будет все легче понять, если вы используете что-то вроде int и указатели на int.

2 голосов
/ 29 апреля 2009

вы печатаете ссылку вашего указателя, которая является адресом указателя, а не значением указателя.

1 голос
/ 29 апреля 2009

Объекты в Objective-C обрабатываются с использованием указателей. Поэтому, чтобы обработать ваш объект NSString, вы должны взять указатель на него. Вот что такое str1, указатель на объект NSString.

Если вы хотите отправить сообщение на вашу NSString, вы можете использовать синтаксис [str1 doSomething].

Если вы хотите напечатать вашу строку, вы должны передать указатель на NSLog И сказать NSLog, что указатель указывает на строку NSString, что выполняется правилом форматирования "% @".

Теперь, если вы просто хотите напечатать адрес, на который указывает str1, вам все равно нужно передать указатель str1, НО вы должны сообщить NSLog, что вы печатаете его как шестнадцатеричное значение, используя правило форматирования "% x".

Что-то подобное должно напечатать то, что вы хотите:

// First print str1 as an hexadecimal value
// Then print the content of the NSString object str1 points to
NSLog(@"str1: %x, %@", str1, str1);
1 голос
/ 29 апреля 2009

Указатели на самом деле являются целыми числами со специальной арифметикой (IIRC, гарантируется, что sizeof (int) == sizeof (void *))

Если вы ссылаетесь на указатели, вы получите адрес, где он хранится; если переменная автоматическая, то вы получите адрес в стеке, где хранится указатель: именно поэтому вы получите эти результаты.

Назначение ведет себя как назначение между целыми числами; на самом деле:

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

печать:

:~$ ./a.out
80484f8
80484fd
80484fd
1 голос
/ 29 апреля 2009

str1 - указатель на значение NSString.

&str1 означает: адрес переменной str1. Это двойная косвенность.

Полагаю, вам нужен адрес значения, т. Е. str1, а не &str1.

Предположим, что значение объекта NSString, содержащее @"one", расположено по адресу 0x12345678, а @"two" в 0x1234ABC0.

Первоначально значение str1 равно 0x12345678, а значение str2 равно 0x1234ABC0. Эти два значения хранятся в памяти соответственно по адресам 0xbfffd3cc и 0xbfffd3c8. Это адреса переменных str1 и str2, то есть значения &str1 и &str2.

Когда вы пишете str1 = str2, назначение меняет значение str1 на то же, что и значение str2, то есть значение str1 равно 0x1234ABC0. Это адрес объекта @"two". Но адрес переменной str1 (0xbfffd3cc) не изменился.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...