【问题标题】:Default values for Array of Pointers in CC 中指针数组的默认值
【发布时间】:2015-05-04 14:36:02
【问题描述】:

我真的对这段代码感到困惑。我有的是

int main(){
 int *array[6];
 for (int i = 0; i < 6; i++){
  if (array[i]==NULL){
   printf("NULL\n");
  }
 }
}

谁能解释为什么我的代码只打印一次 NULL ?我以为这会打印 NULL 6 次。

【问题讨论】:

标签: c


【解决方案1】:

因为您没有初始化 array 元素。如果未初始化,它们的值是未指定的。

用途:

int *array[6] = {0};

将所有数组元素初始化为空指针常量。

【讨论】:

  • 我知道如果没有初始化,它们的值是未指定的,这意味着数组实际上只保存了很多垃圾。我想知道为什么第 0 个元素总是 NULL,即使它没有指定
  • @ShameelAbdullah unspecified 意味着它可能是42314159 甚至是0。如果您稍后运行程序,您可能会有完全不同的行为。
  • 是的,这就是我的意思,我已经运行了很多次,它总是打印出一个 NULL
  • @ShameelAbdullah 在另一个系统上,或者在您的系统上,但在另一天,或者在您的系统上运行不同数量的进程时,您可能会得到不同的行为。这就是未指明的原则。
【解决方案2】:

根据 C 标准(6.7.9 初始化)

10 如果具有自动存储时长的对象未初始化 明确地说,它的值是不确定的。如果一个物体有静电 或线程存储持续时间未显式初始化,则: — 如果 有指针类型,初始化为空指针;

因此在你的程序中

int main(){
 int *array[6];
 for (int i = 0; i < 6; i++){
  if (array[i]==NULL){
   printf("NULL\n");
  }
 }
}

数组array 可以包含任何值。但是,如果您将按照以下方式重写您的程序

int main(){
 static int *array[6];
 for (int i = 0; i < 6; i++){
  if (array[i]==NULL){
   printf("NULL\n");
  }
 }
}

int *array[6];

int main(){
 for (int i = 0; i < 6; i++){
  if (array[i]==NULL){
   printf("NULL\n");
  }
 }
}

那么数组的所有元素都会被初始化为NULL。

【讨论】:

    【解决方案3】:

    C(与其他一些语言相比)不会为数组成员分配默认值,因此您的程序输出NULL 的次数是未定义的。

    【讨论】:

    • 每次运行程序时始终为 1 是否只是巧合?
    • @ShameelAbdullah:是的。访问处于不确定状态的对象的值是未定义的行为(C99§Annex J.2),因此您的编译器可能执行了优化,导致程序行为一致但不正确。您的操作系统也有可能重用资源,导致每次运行程序时产生相同的垃圾值(但我认为这种可能性较小)。
    • @Axel “所以你的程序输出 NULL 的次数是未定义的。”从技术上讲,整个程序的行为是不确定的。
    【解决方案4】:


    您得到一个并且总是一个 NULL 值的事实是由于堆栈的内容,这取决于调用 main 之前执行的代码,而这又取决于您正在使用的编译器/libc,以及编译选项。 但是一旦编译,运行程序任意次数总是会得到相同的值。 正如其他答案中所述,这是因为您没有明确初始化数组,并且它的范围(函数本地)允许编译器将它放在堆栈上,在那里它获取调用 main 之前的内容。

    要获得 6 个 NULL 指针,您应该明确地初始化数组 (int *array[6] = {0};) 或者使其成为静态或全局的。

    在后面的情况下,编译器会将数组放在 bss 部分(二进制文件中不存在的数据部分,但在调用 main() 函数之前由 libc 分配并初始化为零)。

    在第一种情况下(本地数组初始化为 0),编译器现在可以进行优化,因为该值是已知的并且永远不会被修改,并且肯定会删除数组和测试并简单地调用 printf 6 次。

    使用另一个编译器编译,或者使用不同的优化级别(-O2、-O3)会给你一个不同的结果,但在每次调用之间仍然是一致的(如果不相同的话)。

    无论如何,无论初始化您的数组,您都应该根据 C 标准来修正您的代码: 你的 main 必须返回一个值,并且“for”循环初始声明只允许在 C99 模式下,所以你应该得到这个:

    #include <stdio.h>
    int main(){
        int* array[6];
        int i = 0;
        for (i = 0; i < 6; i++) {
            if (array[i] == NULL) {
                printf("%d NULL\n", i);
            }
        }
        return 0;
    }
    

    我添加了显示NULL值的位置编号,以表明它始终是同一个。 您甚至可以添加 else 语句,并在不为 NULL 时打印值:

            } else {
                printf("%d %p\n", i, array[i]);
    

    你会得到这样的东西:

    $ ./test
    0 NULL
    1 0x4011cd
    2 0x7f8d2fdf64c0
    3 NULL
    4 0x4011a0
    5 0x401050
    
    $ ./test
    0 NULL
    1 0x4011cd
    2 0x7fa96155e4c0
    3 NULL
    4 0x4011a0
    5 0x401050
    

    我可以运行它 1000 次,0、1、3、4 和 5 的值总是相同的。只有数字2的值发生了变化,我认为这意味着它是用来存储地址的。

    通过读取 objdump -D 的输出并分析 GCC 生成的代码,可以得到准确的信息。

    【讨论】:

      猜你喜欢
      • 2013-01-27
      • 1970-01-01
      • 2015-04-06
      • 2012-07-17
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      • 1970-01-01
      • 2011-05-09
      相关资源
      最近更新 更多