C 内存中的变量
如果我有两个变量aib都是int,还有一个指针ptr指向&b。如果我们像那样增加ptr++的话,它应该指向a,如果我没有错的话。我认为这是可能的,因为编译a时,b在堆栈中,b比a少4个字节。但当我在下一行打印指针时,我只得到地址。 代码:C 内存中的变量,c,variables,C,Variables,如果我有两个变量aib都是int,还有一个指针ptr指向&b。如果我们像那样增加ptr++的话,它应该指向a,如果我没有错的话。我认为这是可能的,因为编译a时,b在堆栈中,b比a少4个字节。但当我在下一行打印指针时,我只得到地址。 代码: #包括 #包括 内部主(空) { INTA=52; int b=12; int*ptr; ptr=&b; printf(“%d\n”,*ptr); ptr++; printf(“\n%d”,*ptr); 返回0; } 但是如果我把printf(“%d,&a”
#包括
#包括
内部主(空)
{
INTA=52;
int b=12;
int*ptr;
ptr=&b;
printf(“%d\n”,*ptr);
ptr++;
printf(“\n%d”,*ptr);
返回0;
}
但是如果我把printf(“%d,&a”);然后最后一个printf被打印好,它打印a的值
代码:
#包括
#包括
内部主(空)
{
INTA=52;
int b=12;
printf(“%d\n”、&a);
int*ptr;
ptr=&b;
printf(“%d\n”,*ptr);
ptr++;
printf(“\n%d”,*ptr);
返回0;
}
有人能解释一下为什么会这样吗?
图片:
您不能保证
a
和b
变量存储在内存附近的任何位置,并且尝试以指针增量从一个变量“移动”到另一个变量,并依赖结果,显然是不安全的。你所做的是停留在未定义行为的领域,你不应该这样做。C11标准草案n1570:
6.5.2.4后缀递增和递减运算符
二,
[…]有关详细信息,请参见加法运算符和复合赋值的讨论
有关约束、类型和转换以及操作对
指针。[…]
6.5.6加法运算符
七,
在这些运算符中,指向不是对象元素的对象的指针
数组的行为与指向长度为1的数组的第一个元素的指针相同
对象的类型作为其元素类型
八,
[…]如果指针和
操作数和结果指向同一数组对象的元素,或超过最后一个的元素
数组对象的元素,求值时不应产生溢出;否则
行为是未定义的。如果结果指向数组对象的最后一个元素后一个元素,则
不得用作计算的一元*运算符的操作数
在
ptr=&b代码>和ptr++代码>,在printf中取消引用ptr
(\n%d“,*ptr)代码>是未定义的行为。编译器可以自由地在堆栈上选择任何顺序排列局部变量。事实上,C标准甚至没有提到堆栈。这是留给编译器的实现细节
添加一行看似不相关的代码可能会导致编译器决定在堆栈上以不同的顺序放置变量,而不是不添加额外代码。因此,在编写代码时不能依赖这种行为。这样做是你经历过的
此外,对不属于同一数组的变量执行指针算术也是未定义的行为。不能将指向一个对象的指针递增为指向另一个对象的指针,除非这两个对象是同一数组的一部分。你的程序表现出未定义的行为。我知道关于数组,实际上它们正好相隔4个字节,并且只有当我使用更多不同类型的变量时,它们才会始终保持一致,因此,你的第一个程序从不使用a
,因此编译器正在优化内存分配和/或赋值。第二个程序使用它,所以它会分配内存。你不了解“未定义行为”的哪一部分?@honeyPot:看看C标准,你就会发现你的问题。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a = 52;
int b = 12;
int *ptr;
ptr = &b;
printf("%d\n",*ptr);
ptr++;
printf("\n%d",*ptr);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a = 52;
int b = 12;
printf("%d\n",&a);
int *ptr;
ptr = &b;
printf("%d\n",*ptr);
ptr++;
printf("\n%d",*ptr);
return 0;
}