【问题标题】:Why we must initialize a variable before using it? [duplicate]为什么我们必须在使用变量之前对其进行初始化? [复制]
【发布时间】:2011-12-08 20:55:05
【问题描述】:

可能重复:
What happens to a declared, uninitialized variable in C? Does it have a value?

现在我正在阅读Teach Yourself C in 21 Days。在第 3 章中,有这样的注释:

不要使用尚未初始化的变量。结果可以 不可预测。

请向我解释为什么会这样。这本书没有提供进一步的说明。

【问题讨论】:

  • 把书扔掉。从这里获取一个stackoverflow.com/questions/562303/…
  • 当你在 C 中声明一个变量时,它会给你一些内存供你使用,但它不会打扰将内存设置为零或其他什么,所以你最终可能会在那里得到任何旧的垃圾值.我在 C 程序中遇到的很多错误都被证明是由未初始化的变量引起的。
  • @pmr:善待新手。收回-1
  • 对我来说,这似乎是一个合理的问题。
  • 这不是一个坏问题;这是一本糟糕的书。

标签: c


【解决方案1】:

因为,除非变量有静态存储空间,否则它的初始值是不确定的。你不能依赖它是任何东西,因为标准没有定义它。即使是静态分配的变量也应该被初始化。只需初始化您的变量并避免将来出现潜在的麻烦。没有充分的理由不初始化变量,相反的做法有很多充分的理由。

附带说明,不要相信任何声称可以在 21 天内教你 X 编程语言的书。他们在撒谎,给自己买一本像样的书。

【讨论】:

  • 我可以在这里迂腐地说它是 indeterminate 而不是 undefined 吗?
  • @Brian:我想你可以,虽然我看不出有什么区别:)。标准未定义没有静态存储空间的未初始化变量的值。我想这会是一种更好的表达方式。
  • @EdS Undefined 通常被解释为undefined behaviour,这意味着您的整个编程不再是真实的C,而indeterminate 意味着可以这样做,但是您的结果将是不可预测的。
  • @pmr:同意,不确定是准确的。我重读了我写的内容,我的意思是说标准没有定义行为。稍微改了一下。
  • “Indeterminate”是标准使用的语言。 “未定义”通常保留用于谈论未定义的行为。读取具有 indeterminate 值的变量会导致 undefined behavior,但变量可能包含不确定值这一事实本身并不会导致 undefined behavior 所以保持这些概念清晰和独立是一件好事,恕我直言。
【解决方案2】:

在 C 中,未初始化变量的值是不确定的。这意味着您不知道它的价值,并且它可能因平台和编译器而异。对于诸如structunion 类型的化合物也是如此。

为什么? 有时您不需要初始化变量,因为您将把它传递给填充它的函数,而该函数并不关心变量中的内容。您不希望将初始化开销强加给您。

如何?可以从文字或函数返回值初始化原始类型。

int i = 0;
int j = foo();

可以使用聚合初始化器语法对结构进行零初始化:

struct Foo { int i; int j; }

struct Foo f = {0};

【讨论】:

    【解决方案3】:

    您最终可能会使用在当前方法范围之外声明的变量。

    考虑以下

    int count = 0;
    
    while(count < 500) 
    {
       doFunction();
       count ++;
    }
    
    ...
    
    
    void doFunction() {
    
       count = sizeof(someString);
       print(count);
    
    }
    

    【讨论】:

      【解决方案4】:

      在 C 中,使用满足成为 register 变量要求的未初始化自动变量(非静态局部变量和参数变量)的值是未定义行为,因为这些变量值可能是从寄存器中获取的,并且某些如果您读取此类未初始化的值,平台可能会中止您的程序。这包括 unsigned char 类型的变量(这被添加到后来的 C 规范中,以适应这些平台)。

      使用不满足作为register 变量要求的未初始化自动变量的值,例如已获取地址的变量,只要您使用的 C 实现没有变量的陷阱表示,就可以了您使用的类型。例如,如果变量类型是unsigned char,则标准要求所有平台不要将陷阱表示存储在此类变量中,并且从中读取不确定值将始终成功并且不是未定义的行为。 intshort 之类的类型没有这样的保证,因此您的程序可能会崩溃,具体取决于您使用的 C 实现。

      如果您不明确执行此操作,则始终会初始化静态存储持续时间的变量,因此您不必担心。

      对于分配存储持续时间的变量 (malloc ...),同样适用于不满足成为 register 变量要求的自动变量,因为在这些情况下,受影响的 C 实现需要使您的程序从内存中读取,并且不会遇到寄存器读取可能引发异常的问题。

      【讨论】:

      • 我认为在不确定的情况下使用具有自动存储持续时间的对象的值读取始终是未定义的行为。满足register要求的区别从何而来?
      • @CharlesBailey 在 C90 中它是未定义的,在 C99 中它变得很好定义(即使对于 do 满足 register 要求的变量),但是 DR 添加了限制(见DR338)C1x。所以在 C99 中,它完全取决于实现。 如果它具有陷阱表示,则从未初始化的变量读取是未定义的行为,因为此类变量具有不确定的“值”,并且此类值可能是陷阱表示。 C++11 没有及时修复,但也许 TC 可以。
      【解决方案5】:

      当一个变量被声明时,它会指向一块内存。

      访问变量的值将为您提供那块内存的内容。

      然而,在变量被初始化之前,那块内存可以包含任何东西。这就是为什么使用它是不可预测的。

      其他语言可能会在您分配变量时自动初始化变量,从而在这方面为您提供帮助,但作为 C 程序员,您使用的是一种相当低级的语言,它不假设您想对您的程序做什么。作为程序员,你必须明确告诉程序做所有事情。

      这意味着初始化变量,但它还意味着更多。例如,在 C 语言中,您需要非常小心地取消分配您分配的任何资源,一旦您完成了它们。其他语言会在你程序结束后自动清理;但是在 C 语言中,如果你忘记了,你最终会导致内存泄漏。

      C 可以让你做很多在其他语言中很难或不可能的事情。但这种权力也意味着你必须对那些你认为在其他语言中理所当然的家务工作负责。

      【讨论】:

        【解决方案6】:

        冒着迂腐的风险,声明

        不要使用尚未初始化的变量。

        不正确。如果可以更好地表达:

        不要使用未初始化变量的值。

        语言区分 initialisationassignment,所以第一个警告是,在这个意义上,过于谨慎 - 你不需要为每个变量提供一个初始化器,但你应该在您执行任何随后使用其值的操作之前,已分配使用有用且有意义的值初始化变量。

        所以以下是可以的:

        int i ;  // uninitialised variable
        
        i = some_function() ;  // variable is "used" in left of assignment expression.
        some_other_function( i ) ; // value of variable is used
        

        即使调用 some_function() 时 i 未初始化。如果您正在分配一个变量,那么您肯定是在“使用”它(在这种情况下存储返回值);它未初始化的事实无关紧要,因为您没有使用它的值。

        现在如果你坚持

        不要使用未初始化变量的值。

        正如我所建议的,这个要求的原因很明显 - 为什么你会在不知道它包含有意义的东西的情况下获取变量的值?一个有效的问题可能是“为什么 C 不使用已知值初始化 auto 变量。可能的答案是:

        • 任何编译器提供的任意值在应用程序的上下文中都不需要有意义 - 或者更糟糕的是,它的含义可能与应用程序的实际状态相反。 p>

        • C 被刻意设计为没有隐藏开销,因为它根植于系统编程语言 - 初始化仅在显式编码时执行,因为它需要额外的机器指令和 CPU 周期才能执行。

          李>

        请注意,static 变量始终初始化为零。 .NET 语言(例如 C#)具有空值或包含 nothing 的变量的概念,并且可以显式测试甚至分配。 C 中的变量不能包含 nothing,但它包含的内容可能是不确定的,因此使用其值的代码的行为是不确定的。

        【讨论】:

          猜你喜欢
          • 2020-05-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-25
          • 2012-01-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多