为啥指针+1包含的内存地址与被指向的值的地址+1不同

Posted

技术标签:

【中文标题】为啥指针+1包含的内存地址与被指向的值的地址+1不同【英文标题】:Why memory address contained by pointer +1 is different from address of value being pointed + 1为什么指针+1包含的内存地址与被指向的值的地址+1不同 【发布时间】:2016-07-21 20:19:23 【问题描述】:

指针存储指向的值的内存地址,因此指针包含的内存地址与值的内存地址相同。因此,将 1 加到这两个内存地址应该会产生相同的结果,但这是不会发生的。为什么? 这是代码

 int main()
 
     int ages[] = 23, 43, 12, 89, 2;
     int *cur_ages = ages;

     printf("\n&cur_ages=%p, &cur_ages+1=%p", &cur_ages, &cur_ages+1);
     printf("\n&ages=%p, &ages+1=%p", &ages, &ages+1);
     printf("\ncur_ages=%p, cur_ages+1=%p", cur_ages, cur_ages+1);
     printf("\n*cur_ages=%d, *cur_ages+1=%d", *cur_ages, *(cur_ages+1));

     return 0;
 

输出是

&cur_ages=0x1ffff85f3d0, &cur_ages+1=0x1ffff85f3d8
&ages=0x1ffff85f3dc, &ages+1=0x1ffff85f3f0
cur_ages=0x1ffff85f3dc, cur_ages+1=0x1ffff85f3e0
*cur_ages=23, *cur_ages+1=43

&ages+1 不等于 cur_ages+1。为什么?

【问题讨论】:

将非void* 参数传递给printf("%p") 的未定义行为。您可能认为这是迂腐的,但各种对象的类型确实是问题的核心。 指针不是地址,指针加1不等于地址加1。 @user2357112:在 C 语言中,指针值一个“地址”。这就是 C 标准中使用“地址”一词的方式。 C“地址”与机器级“地址”不同。 谨慎措辞,@user2357112,指针是具有类型的地址。给指针加 1 会增加其类型的大小。 【参考方案1】:

指针算法通过给定值乘以它指向的类型的大小来增加指针的值。

所以当你这样做时:

&ages+1

您获取ages(类型为int [5])的地址并将sizeof(ages) 添加到指针值。假设 sizeof(int) 为 4,这会将 20 添加到指针值。

同样,当你这样做时:

cur_ages+1

这里,cur_ages 指向一个 int,所以加 1 会将 sizeof(int) 添加到指针值。

【讨论】:

这是一个很好的例子,说明为什么数组和指针是一回事。【参考方案2】:

&cur_ages 是 cur_ages 在堆栈中存储的地址。由于 &cur_ages+1 比 8 大,我假设这是在 64 位模式下完成的,其中指针的大小为 8 个字节。

&ages 类似于声明 int (*ptr_to_ages)[5],其中 ptr_to_ages 是指向 5 个整数数组的指针,它可以是指向矩阵第一行的指针,其中每行是 5 个整数的数组. &ages = 存储数组第一个成员的地址。正如 dbush 的回答中提到的,由于年龄是 5 个整数的数组,所以 &ages+1 指向在年龄的 5 个整数之后的 5 个整数数组,所以 + 5 * 4,其中 4 是整数的大小,实际上与指向矩阵第二行的指针相同,其中每一行都是 5 个整数的数组。

示例代码不会打印出年龄和年龄+1,它们的区别是 sizeof(int) 而不是 5 * sizeof(int)。如果没有年龄的 & 前缀,则数组的大小无关紧要。

cur_ages 和 cur_ages+1 指向年龄的第一个和第二个整数,正如预期的那样。

*cur_ages 和 *(cur_ages+1) 是年龄的第一个和第二个整数值。

【讨论】:

【参考方案3】:

这里发生了几件事。

    &cur_ages 是指向值的指针的地址,而不是值的地址。由于 C 中的(arguably odd) semantics of array names,&ages 是一个值的地址。 指针算法 (&<anything>+1) 适用于整个项目,而不是字节。因此,将 1 添加到 int * 将添加 sizeof(int) 字节,而不是一个字节。

【讨论】:

抱歉,从初学者的角度来看,这是一个糟糕的答案 :) 这部分的特别之处&cur_ages is the address of a pointer to a value, not the address of a value.

以上是关于为啥指针+1包含的内存地址与被指向的值的地址+1不同的主要内容,如果未能解决你的问题,请参考以下文章

“指针”就是___存放地址值的变量或常量,或者答地址。 对吗?我实在不理解,请老师指教,学生有礼了。

Go笔记-指针

go的指针学习

如何从该指针获取指针指向的值的地址

空指针——野指针——内存泄漏

指针为啥是不安全的呢?