1

在没有初始化变量的情况下是否可以使用变量,或者它总是被认为是垃圾?例如,一种情况是:

// global example?
// static example?
// extern example?
// etc.
{
    int n=1, max_n;
    printf("%d %d\n", n, max_n);
}

在这种情况下max_n,有一个垃圾/未定义的值。但是是否存在值已知并且可以使用的情况,例如执行诸如bool item自动初始化为0/之类的事情false,或者在 C 语言中永远不会出现这种情况?

4

6 回答 6

3

根据定义,如果某些东西没有被初始化,它就没有定义的值。如果它确实具有定义的值,则将其初始化。

cppreference

未初始化变量中的值可以是任何值——它是不可预测的,并且每次运行程序时都可能不同。读取未初始化变量的值是未定义的行为——这总是一个坏主意。它必须先用一个值初始化,然后才能使用它。

同样来自cppreference关于隐式初始化:

如果未提供初始化程序:

  • 具有自动存储持续时间的对象被初始化为不确定的值(可能是陷阱表示)
  • 具有静态和线程本地存储持续时间的对象是零初始化的

因此,例如,int a;如果在全局范围内声明为静态类变量、thread_local变量等,则将被零初始化。在其他情况下,它将未初始化。

于 2021-01-23T21:41:27.037 回答
2

在 C 中,读取未初始化的变量会导致未定义的行为。它可能0,但也可能是恰好在该内存地址中的任何随机值。长话短说 - 不要依赖未初始化变量的值。

于 2021-01-23T21:39:54.107 回答
2

不确定您是否会认为这是一个“案例”,但在 C 中,局部变量是在堆栈上分配的,并且未初始化。

但是,全局变量和静态变量分配在其中一个程序数据部分中,因此它们在加载时由操作系统归零。

有关包括标准参考在内的更多信息,请参阅此问题: 为什么将全局变量和静态变量初始化为其默认值?

于 2021-01-23T21:47:00.237 回答
2

全局和静态对象使用其类型的默认值进行初始化(整数为 0,浮点数为 0.0,指针为 NULL 等)

不能依赖其他未初始化的值。

下面是一个简单的解释:大多数实现都将所有局部变量放在一个堆栈上。当您声明局部变量或调用函数时,此堆栈会增长,而当您执行相反的操作时会缩小 - 退出变量的范围或从函数返回。

现在让我们看一个程序:

void good()
{
    int p = 2;
    printf("%d", p);
}

void notgood()
{
    int p;
    printf("%d", p);
}

int main()
{
    good();
    notgood();
    notgood();
}

这是程序开始时的堆栈(堆栈向下增长)。堆栈指针始终指向顶部元素(由箭头表示):

|---------------------|
|main's return address| <-- stack pointer

接下来是在good()被调用后立即:

|---------------------|
|main's return address|
|good's return address| <-- stack pointer

接下来我们声明 p 并用 2 初始化它:

|---------------------|
|main's return address|
|good's return address|
|value 2 (variable p) | <-- stack pointer

之后,我们调用 printf:

|---------------------|
|main's return address|
|good's return address|
|value 2 (variable p) |
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     | <-- stack pointer

返回时printf,返回地址和参数从堆栈中弹出,但不会从内存中删除。那将是低效的。我们只是减少堆栈指针。

|---------------------|
|main's return address|
|good's return address|
|value 2 (variable p) | <-- stack pointer
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     |

接下来,我们的good()函数返回到 main:

|---------------------|
|main's return address| <-- stack pointer
|good's return address|
|value 2 (variable p) |
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     |

打电话notgood。堆栈上的任何垃圾都会被覆盖:

|---------------------|
|main's return address|
|notgood's return addr| <-- stack pointer
|value 2 (variable p) |
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     |

声明变量(分配空间),但我们不初始化。因此,旧的垃圾值仍然存在:

|---------------------|
|main's return address|
|notgood's return addr|
|value 2 (variable p) | <-- stack pointer
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     |

接下来,我们再次调用 printf。请注意,它的返回地址实际上发生了变化,因此旧垃圾在堆栈上被覆盖:

|---------------------|
|main's return address|
|notgood's return addr|
|value 2 (variable p) |
|value 2 (parameter)  |
|format string address|
|printf's return addr |
|#printf's frame#     | <-- stack pointer

因此,如您所见,如果您不初始化变量,它们将采用堆栈上的任何值。

请注意,该程序可能无法运行,因为编译器可能会优化某些函数调用。

于 2021-01-23T21:48:18.420 回答
1

您的问题的答案是否定的。这将取决于声明该变量的范围。如果它是全局或静态变量,它将被初始化为 0。在其他情况下,您无法确定。

于 2021-01-23T21:45:52.430 回答
0

使用未初始化的自动存储变量的任何操作的结果都是未定义的。他们最初持有的东西尚未确定。

C(2007 草案)标准(6.7.8 p10):

如果具有自动存储持续时间的对象未显式初始化,则其值是不确定的。

于 2021-01-23T21:51:30.227 回答