我写了一个小程序来更好地理解指针。
#include<stdio.h>
int main(){
char buf[4] = {0, 1, 2, 3};
int i;
char ** ptr1;
for (i = 0; i < 4; i++) {
printf("------------------\n");
printf("i = %i\n", i);
printf("buf = %p\n", buf+i);
ptr1 = (char **)&buf[i];
printf("ptr1 = %p\n", ptr1);
printf("*ptr1 = %p\n", *ptr1);
*ptr1 = (char *)ptr1;
printf("B ptr1 = %p\n", ptr1);
printf("B *ptr1 = %p\n", *ptr1);
printf("B **ptr1 = %i\n", **ptr1);
}
return 0;
}
程序输出:
------------------
i = 0
buf = 0x7fff3d6898f0
ptr1 = 0x7fff3d6898f0
*ptr1 = 0x7fff03020100
B ptr1 = 0x7fff3d6898f0
B *ptr1 = 0x7fff3d6898f0
B **ptr1 = -16
------------------
i = 1
buf = 0x7fff3d6898f1
ptr1 = 0x7fff3d6898f1
*ptr1 = 0x7fff3d6898
B ptr1 = 0x7fff3d6898f1
B *ptr1 = 0x7fff3d6898f1
B **ptr1 = -15
------------------
i = 2
buf = 0x7fff3d6898f2
ptr1 = 0x7fff3d6898f2
*ptr1 = 0x9f00007fff3d6898
B ptr1 = 0x7fff3d6898f2
B *ptr1 = 0x7fff3d6898f2
B **ptr1 = -14
------------------
i = 3
buf = 0x7fff3d6898f3
ptr1 = 0x7fff3d6898f3
*ptr1 = 0x9b00007fff3d6898
B ptr1 = 0x7fff3d6898f3
B *ptr1 = 0x7fff3d6898f3
B **ptr1 = -13
*** stack smashing detected ***: ./test terminated
Aborted (core dumped)
以下是我的问题:
在第一次循环迭代中。我做完之后
ptr1 = (char **)&buf[i];
然后ptr1
获得了buf。由于我没有完全初始化**ptr1
,因此我获得了*ptr1
printf("*ptr1 = %p\n", *ptr1);
然而,我然后用ptr1的地址初始化* ptr1。
*ptr1 = (char *)ptr1;
所以我期待**ptr1 = 0
。但是每次运行程序时我都会得到一些随机值。为什么呢?
为什么在此程序结束时始终存在seg错误?
答案 0 :(得分:4)
问题从这里开始:
ptr1 = (char **)&buf[i];
char **
表示&#34;指向包含char *
的内存区域。但是,然后将其指向不包含char *
变量的内存区域。实际上该区域包含char
s。
如果&buf[i]
未正确对齐char *
,则可能已导致未定义的行为。但是,您通过尝试读取指针肯定会得到未定义的行为:
printf("*ptr1 = %p\n", *ptr1);
此行违反了严格别名规则; char
数组的一部分不能被视为包含指针。
所以从现在开始你的程序行为是不确定的。
让我们暂时想象一下严格的别名规则是否存在(例如gcc有一个模式,-fno-strict-aliasing
)。该行的效果是从sizeof(char *)
指向的位置读取ptr1
个字节,并将它们视为指针的表示。
您的输出表明系统上此大小为8
个字节。但是,您的数组大小只有4
个字节。所以你已经阅读了超出数组末尾的内容(导致未定义的行为)。
以下行*ptr1 = (char *)ptr1;
写入数组末尾,再次导致未定义的行为。这可能已经触发了#34;堆栈粉碎&#34;检测,取决于检测的准确程度。
恕我直言,尝试分析在写完数组结束后发生的事情并没有多大意义。