C 指针与数组的混淆
我们有 我想知道下面两段代码是怎么做的C 指针与数组的混淆,c,C,我们有 我想知道下面两段代码是怎么做的 int a[5]={10, 20, 30, 40, 50}; 如果我们有 int *ptr = (int *)(&a+1); int *t = (int *)(&a -1); 结果应该是什么?让我们一件一件地看一看 &a表示a的地址。因此,它得到整数10的地址。 &a+1是从该点开始的下一个指针。所以它是存储在内存中变量a之后的东西。坏主意。 &a-1是在a之前存储在内存中的东西。又是一个坏主意 *(a+1)是由a加上一个整数指向
int a[5]={10, 20, 30, 40, 50};
如果我们有
int *ptr = (int *)(&a+1);
int *t = (int *)(&a -1);
结果应该是什么?让我们一件一件地看一看
&a
表示a的地址。因此,它得到整数10的地址。&a+1
是从该点开始的下一个指针。所以它是存储在内存中变量a
之后的东西。坏主意。&a-1
是在a
之前存储在内存中的东西。又是一个坏主意
*(a+1)
是由a加上一个整数指向的位置处的东西。那将是a[1]
或20。*(ptr-1)
是a
,因为ptr
是&a+1
,所以ptr-1
是&a
。它是a
的指针值。将其打印为%d
是一个错误。如果你说**(ptr-1)
,你会从printf
中得到一个更有意义的10
*(t+1)
也是a
,如上所述,但加号和减号是切换的。所有问题都来自&a
的使用,它是指向“五个整数的数组”的指针,因此指针算法(当您考虑地址时)会按大小(a)
(例如,如果int
是4个字节,并且编译器不需要为对齐目的而进行填充,则可能是20个字节——这是合理的假设,当然远不能确定
那么,在
printf("%d %d %d \n", *(a+1), *(ptr-1), *(t+1));
ptr
是指向内存地址“sizeof(a)大于地址a”处int的指针,t
类似地指向“sizeof(a)小于地址a”处int的指针。因此…:
int *ptr = (int *)(&a+1);
int *t = (int *)(&a -1);
结果应该是什么 很可能是分段冲突,否则
20
后跟两个完全任意的整数值。由于ptr
和t
是指向int
的指针,因此它们的-1
和+1
的地址算术缩放不会对&a
进行补偿(内存地址的缩放是通过sizeof(int)
,而不是sizeof(a)
!),因此ptr-1
和t+1
指向(所谓的;-)int
分别是a
结束后的一些int
和a
开始前的一些int
)
无法知道在这些任意地址上是否存在允许进程寻址的内存(因此可能存在分段冲突),如果存在任何可访问内存,则其“视为int
”的内容可能是什么
Edit:@caf指出,ptr-1
不是无效的——它正确地指向a
的最后一个元素;因此输出(除非存在分段错误,@NullUserException认为不太可能,但在这一点上我们不同意;-)将以第三个“任意”之前的2050
开始垃圾。点是,根据C标准,可以有效地计算(尽管不使用)数组的指针“仅过一个端点,并且数组的大小必须正好是该数组的长度乘以其元素的大小(如果需要,可以对元素的类型进行填充,如果需要,可以在元素自身的大小中显示,但不能对整个数组进行填充)。微妙但重要;-)。“结果应该是什么?”
下次您想知道像这样的小代码段应该做什么时,请查看以下内容:
我得到的结果是:
2050134520820
编辑:
当您运行一个程序时,看到这样的输出,您会发现自己在问:“那个值是从哪里来的?”您可能遇到了未定义的行为
在这种情况下,第三个值并不指向您可能认为它会指向的位置。它读取未初始化的内存(很可能)、进程空间中的代码所拥有的内存,但在您的程序(加载的库或C运行时)之外的内存,或者与此程序无关的内存(不太可能,因为内存受保护)。因为
a
的类型是array-of-5-int
s,这意味着&a
的类型是指向-array-of-5-int
s的指针
当你从一个指针上加上或减去1时,你要求它指向内存中该类型的下一个或上一个对象。因此&a+1
正在创建一个指向内存中a
之后的数组-5-int
的指针(该数组不存在),并且&a-1
正在创建一个指针,指向内存中a
之前的数组-5-int
(该数组也不存在)。在内存中,它看起来是这样的(其中每个单元格代表一个int
):
当在表达式*(a+1)
中使用a
时,它被转换为指向其第一个元素的指针,因此指向int
的指针指向10
值。向其中添加一个,然后使指向下一个int
-a+1
的指针指向20
值。*(a+1)
然后获取该值,因此打印的第一个数字是20
由于ptr
也是指向-int
的指针,这意味着ptr-1
在ptr
之前创建一个指向int的指针,在这种情况下,它将指向50。因此打印的第二个数字是50
类似地,t+1
在t
之后立即创建一个指向int
的指针-在这种情况下,它是上图中的第二个?
。这是一个未初始化的值-它可能打印任何内容,甚至导致程序崩溃
Address: &a-1 &a &a+1
Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? |
当您尝试时,您的程序说了什么?这是一个测试问题,并不是假设在计算机上运行就能回答的
Address: &a-1 &a &a+1
Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? |
Address: &a-1 &a &a+1
t t+1 a a+1 ptr-1 ptr
Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? |