【问题标题】:Uninitialized variable or array in CC中未初始化的变量或数组
【发布时间】:2018-04-05 16:32:14
【问题描述】:

C 中未初始化数组的结果从何而来?它们是随机分配的值还是只是存储在内存中的先前值?

#include <stdio.h>

int main (void)
{
    int values[10];
    int index; 

    values[0] = 197;
    values[2] = -100;
    values[5] = 350;
    values[3] = values[0] + values[5];
    values[9] = values[5] / 10;
    --values[2];

    for ( index = 0; index < 10; index++ )
        printf ("values[%i] = %i\n", index, values[index]);

    return 0; 
}

和输出:

$ ./a.exe
values[0] = 197
values[1] = 0
values[2] = -101
values[3] = 547
values[4] = 8
values[5] = 350
values[6] = 51
values[7] = 0
values[8] = 44045216
values[9] = 35

【问题讨论】:

  • 是的,这是正常的未定义行为
  • 它们没有被初始化并且偶然有一些价值。有什么不清楚的地方?
  • int values[10]; 是一个自动变量,分配在栈上。默认情况下,自动变量不初始化为零;你必须自己做。
  • 很抱歉给您的印象是您的问题冒犯了我。只是似乎不清楚。顺便问一下,你知道stackoverflow.com/help/someone-answers 吗?但是,如果您发现最佳答案实际上是 Ian Abbott 的评论(我愿意;通过对“未定义行为”一词的一些支持性研究),您无需接受以下任何答案。
  • C 专为速度而设计。自动将变量初始化为零需要时间。如果你需要初始化一些,你可以。如果你不需要初始化它们,编译器不会浪费时间。

标签: c arrays variables uninitialized-constant


【解决方案1】:

Chapter and verse:

6.2.4 对象的存储时长
...
5 一个对象,其标识符被声明为没有链接且没有存储类 说明符 static 具有自动存储持续时间,一些复合文字也是如此。这 尝试间接访问具有自动存储持续时间的对象的结果 与对象关联的线程以外的线程是实现定义的。

6 对于这样一个没有变长数组类型的对象,它的生命周期会延长 从进入与其关联的块直到该块的执行结束 反正。 (进入封闭块或调用函数会暂停,但不会结束, 执行当前块。)如果块是递归进入的,则该块的新实例 每次都会创建对象。 对象的初始值是不确定的。如果 为对象指定初始化,每次声明或 在块的执行中达到复合文字;否则,值变为 每次达到声明时都不确定。

添加了重点。

基本上,具有auto 存储持续时间的对象不会隐式初始化为任何特定值 - 它们具有上次写入该特定内存位置的值1。您不能依赖该值为 0(或其他任何值)。

上面引用的最后一句话适用于这样的情况:

for (;;)
{
  int x;
  do_something_with( x );
}

循环的每次迭代都会有效地破坏和重新创建x,并且您不能依赖在循环的任何迭代中写入x 的值将被传递到下一次迭代。 在实践中在类似 x86 的系统上,它很可能会被继承,但不要假设到处都是这种情况。

请注意,当以调试模式或其他方式构建时,实现可能决定使用某个已知值初始化auto 变量。


  1. 其中的机制广泛而多样,不值得在这里介绍。

【讨论】:

  • 感谢回复,解释了很多,你引用的书是什么?
  • @el-aasi:​​Online C 2011 Standard(PDF 文件)。这不是官方标准(要花钱),但在大多数情况下已经足够了。
【解决方案2】:

你认为“未初始化”是什么意思?

表示该值尚未设置。 因为它没有被设置,所以它可以存储任何值。

也许是 0,也许是 547...
任何值都是有效的,并且无法保证您会找到什么。

【讨论】:

  • 谢谢,所以它基本上显示了存储在内存特定部分的最后一个值,还是只是随机的?
  • 这完全取决于机器。可能是最后存储的值,也可能是其他值。
  • 无法保证值是多少。
【解决方案3】:

未初始化的值只是您的应用程序尚未写入的内存地址。这就像拥有一个您周围的每个人都使用的记事本。当您的程序运行时,它会获得该记事本的一小部分,以前可能会或可能不会被其他人使用过。如果它是(很可能),那么它仍然会写一些东西,但可能对你没有任何意义。如果你想知道那里有什么,你必须写一些东西。一般情况下,我们会向它写入 0,这就像从空白纸开始擦除所有内容一样。

【讨论】:

    【解决方案4】:

    这是 C 编程 101。 C 是一种面向过程的语言,并没有实现面向对象语言(如 Java)中存在的某些功能,例如“自动”和保证变量的初始化。

    如果您在 C 中声明了一个自动变量(在堆栈上不是动态分配的)并且没有提供初始值,那么这个变量将具有我们所说的“垃圾值”。这是一般行为,但具体实现可能会有所不同。

    我举个例子:

    int a;  //a variable with no initial value
    printf("%d", a); 
    

    我们无法预测这会打印什么。可能是 0,也可能是其他任何值。该程序也可能崩溃。本质上,这是未定义的行为。

    如果在 Java 中也这样做,那么肯定会打印 0(因为 Java 默认将所有整数初始化为 0)。

    现在来回答您的数组问题:这是单个整数还是整数数组都没有关系。您未明确分配值的任何内存位置都将具有“垃圾值”。它可以是 0 或其他值。此行为完全依赖于机器且不可预测。

    底线是:确保变量在使用前已初始化。

    【讨论】:

    • 感谢您的回复,它清除了很多,不知道谁和为什么投-1....不幸的是我是StackOverflow的新手,我的评分没有显示)
    • 不要介意反对票。很高兴我能帮忙:)
    • 我不确定是不是我,事实上我是这里和计算机科学领域的新手,我问了很多很可能以前已经问过的愚蠢问题,但我只是找不到他们,但有时社区有点被动攻击性......当然不是全部,但是,有些......
    • printf("%d", a); 不是一个“我们无法预测这将打印什么”的问题——它更糟。试图读取未初始化的int未定义的行为。代码可能会在不打印任何内容、打印 0 或通常的“谁知道什么”行为的情况下崩溃。 “您没有明确分配值的任何内存位置都将具有“垃圾值”。它可以是 0 或其他值。”误导,因为它没有明确断言读取尝试本身是未定义的,而不仅仅是值。
    • 是否隐式初始化变量不是过程语言和面向对象语言之间的区别因素;在某些情况下,C 会保证未初始化对象的值。
    猜你喜欢
    • 2014-04-21
    • 2021-03-04
    • 2014-05-19
    • 2013-02-22
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    相关资源
    最近更新 更多