为什么指针 +1 包含的内存地址与指向的值的地址 +1 不同
Why memory address contained by pointer +1 is different from address of value being pointed + 1
指针存储的是所指向的值的内存地址,因此指针包含的内存地址与值的内存地址相同。因此,向这两个内存地址加 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。为什么?
这里发生了几件事。
&cur_ages
是指向一个值的指针的地址,而不是一个值的地址。因为C中的(arguably odd) semantics of array names,&ages
是一个值的地址。
- 指针运算 (
&<anything>+1
) 按整个项目而不是按字节计算。因此,将 1 添加到 int *
将添加 sizeof(int)
个字节,而不是一个字节。
指针算法将指针的值增加给定值乘以它指向的类型的大小。
所以当你这样做时:
&ages+1
您获取 ages
的地址(类型为 int [5]
)并将 sizeof(ages)
添加到指针值。假设 sizeof(int)
是 4,这会将指针值加 20。
同样,当您这样做时:
cur_ages+1
这里,cur_ages
指向一个int
,所以指针值加1就是sizeof(int)
。
&cur_ages是cur_ages入栈的地址。由于 &cur_ages+1 大于 8,我假设这是在指针大小为 8 字节的 64 位模式下完成的。
&ages 类似于声明 int (*ptr_to_ages)[5],其中 ptr_to_ages 是指向 5 个整数的数组的指针,它可以是指向数组第一行的指针矩阵,其中每行是 5 个整数的数组。 &ages = 存储数组第一个成员的地址。正如 dbush 的回答中提到的,由于 ages 是 5 个整数的数组,那么 &ages+1 指向 ages 中 5 个整数之后的 5 个整数的数组,所以 + 5 * 4,其中 4 是整数的大小,实际上与指向矩阵第二行的指针相同,其中每一行都是 5 个整数的数组。
示例代码不会打印出 ages 和 ages+1,它们的区别在于 sizeof(int) 而不是 5 * sizeof(int)。如果年龄上没有 & 前缀,数组的大小将无关紧要。
cur_ages 和 cur_ages+1 指向年龄中的第一个和第二个整数,正如预期的那样。
*cur_ages 和 *(cur_ages+1) 是 ages 中的第一个和第二个整数值。
指针存储的是所指向的值的内存地址,因此指针包含的内存地址与值的内存地址相同。因此,向这两个内存地址加 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。为什么?
这里发生了几件事。
&cur_ages
是指向一个值的指针的地址,而不是一个值的地址。因为C中的(arguably odd) semantics of array names,&ages
是一个值的地址。- 指针运算 (
&<anything>+1
) 按整个项目而不是按字节计算。因此,将 1 添加到int *
将添加sizeof(int)
个字节,而不是一个字节。
指针算法将指针的值增加给定值乘以它指向的类型的大小。
所以当你这样做时:
&ages+1
您获取 ages
的地址(类型为 int [5]
)并将 sizeof(ages)
添加到指针值。假设 sizeof(int)
是 4,这会将指针值加 20。
同样,当您这样做时:
cur_ages+1
这里,cur_ages
指向一个int
,所以指针值加1就是sizeof(int)
。
&cur_ages是cur_ages入栈的地址。由于 &cur_ages+1 大于 8,我假设这是在指针大小为 8 字节的 64 位模式下完成的。
&ages 类似于声明 int (*ptr_to_ages)[5],其中 ptr_to_ages 是指向 5 个整数的数组的指针,它可以是指向数组第一行的指针矩阵,其中每行是 5 个整数的数组。 &ages = 存储数组第一个成员的地址。正如 dbush 的回答中提到的,由于 ages 是 5 个整数的数组,那么 &ages+1 指向 ages 中 5 个整数之后的 5 个整数的数组,所以 + 5 * 4,其中 4 是整数的大小,实际上与指向矩阵第二行的指针相同,其中每一行都是 5 个整数的数组。
示例代码不会打印出 ages 和 ages+1,它们的区别在于 sizeof(int) 而不是 5 * sizeof(int)。如果年龄上没有 & 前缀,数组的大小将无关紧要。
cur_ages 和 cur_ages+1 指向年龄中的第一个和第二个整数,正如预期的那样。
*cur_ages 和 *(cur_ages+1) 是 ages 中的第一个和第二个整数值。