变量,指针,对象和内存地址:为什么我会得到这个奇怪的结果?

时间:2009-04-29 14:51:20

标签: c++ c objective-c pointers

在我认为我已经理解它们是如何工作之后,我尝试了这个:

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 个答案:

答案 0 :(得分:9)

请记住,指针变量本身就是一个变量,所以它有一个地址。因此&str1会产生指针变量的地址,而str1是一个表达式,它会导致指针变量所持有的内容 - 它所指向的对象的地址。

假设:

  • 持有NSString“one”的对象位于地址0x00000100
  • 持有NSString“two”的对象位于地址0x00000200

然后你的指针看起来像这样:

初始化时:

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

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

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

str1 = str2;分配后:

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

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

答案 1 :(得分:2)

您正在打印指针的引用,这是指针的地址,而不是指针的值。

答案 2 :(得分:2)

&str1获取指针的地址。

好的,还记得我们怎么说所有的东西都“活着”在记忆中的某个地址?并且指针只是数字,一个数字是地址?

好的指针也是如此,因此他们有地址。

打印出&str1时,打印出指针占用的内存。当你打印str1时,你打印出指针的值,它是指向的内存地址。

当您打印*str1时,您将取消引用指针,并打印 打印指向的值。


顺便说一句,好的工作:我已经阅读了你的最后两个问题,而且你已经阅读了这些问题,还有你的信用编写代码来证明或反驳你的理解是正确的。这正是你应该做的,而你正走在正确的轨道上。

你遇到的部分问题是字符串是有趣的东西,因为字符串实际上是一个(const)字符数组,而像NSLog这样的函数被编写为通常使用指向char的指针,这是打印字符串。给定一个指向字符串的指针,它实际上是循环的:取消引用指针,打印指向的字符,向指针添加一个,打印下一个字符,直到指向的字符是值为0的特殊字符,此时它找到了字符串的结尾并停止打印字符。

如果使用int和指向int的内容,您可能会发现所有这些都更容易理解。

答案 3 :(得分:1)

str1是指向NSString值的指针。

&str1表示:str1变量的地址。这是双重间接。

我想你想要值的地址,即str1本身,而不是&str1

我们假设包含NSString的{​​{1}}对象值位于地址@"one",而0x12345678位于@"two"

最初0x1234ABC0的值为str10x12345678的值为str2。 这两个值分别存储在地址0x1234ABC00xbfffd3cc的内存中。这些是0xbfffd3c8str1变量的地址,即str2&str1的值。

当您撰写&str2时,分配会将str1 = str2的值更改为str1的值,即str2的值为str1 }。这是0x1234ABC0对象的地址。但@"two"变量(str1)的地址不会更改。

答案 4 :(得分:1)

事实上,指针是一个带有专用算术的整数(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

答案 5 :(得分:1)

Objective-C中的对象使用指针。因此,为了处理您的NSString对象,您必须使用指向它的指针。这就是str1是指向NSString对象的指针。

如果要向NSString发送消息,可以使用语法[str1 doSomething]。

如果要打印字符串,则必须将指针传递给NSLog并告诉NSLog指针指向NSString,这由格式化规则“%@”完成。

现在,如果你只想打印str1指向的地址,你仍然必须传递指针str1但是你必须告诉NSLog你使用格式化规则“%x”将它打印为十六进制值。 / p>

这样的东西应该打印出你想要的东西:

// First print str1 as an hexadecimal value
// Then print the content of the NSString object str1 points to
NSLog(@"str1: %x, %@", str1, str1);