指针初始化不会产生稳定的结果

时间:2015-03-04 03:51:57

标签: c pointers

我写了一个小程序来更好地理解指针。

#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)

以下是我的问题:

  1. 在第一次循环迭代中。我做完之后

    ptr1 = (char **)&buf[i];
    

    然后ptr1获得了buf。由于我没有完全初始化**ptr1,因此我获得了*ptr1

    的随机地址
    printf("*ptr1 = %p\n", *ptr1);
    

    然而,我然后用ptr1的地址初始化* ptr1。

    *ptr1 = (char *)ptr1;
    

    所以我期待**ptr1 = 0。但是每次运行程序时我都会得到一些随机值。为什么呢?

  2. 为什么在此程序结束时始终存在seg错误?

1 个答案:

答案 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;检测,取决于检测的准确程度。

恕我直言,尝试分析在写完数组结束后发生的事情并没有多大意义。