C ++中未初始化的变量行为

时间:2015-05-11 16:03:09

标签: c++ initialization undefined-behavior

我已经检查了自己,我写了一个这样的程序

String sql =
    "SELECT route FROM arrivaltimes INNER JOIN stops"
    + " ON arrivaltimes.stop_id = stops.stop_id"
    + " WHERE weekday = ?"
    + " and arrivaltime = ?"
    + " and name LIKE ?";
PreparedStatement preparedTime = con
    .prepareStatement(sql);
preparedTime.setString(1, day);
//preparing the proper time using java.util.Calendar
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 12);
cal.set(Calendar.MINUTE, 56);
cal.set(Calendar.SECOND, 0);
//create an instance of java.sql.Time
//Calendar#getTime returns an instance of java.util.Date
//Date#getTime returns the time in millis (long)
Time time = new Time(cal.getTime().getTime());
//setting the time
preparedTime.setTime(2, time);
preparedTime.setString(3, stopname);
ResultSet rs = preparedTime.executeQuery();

我跑了几次程序,结果一直都是一样的,零。 我在C中尝试了它,结果是一样的。

但是我的教科书说

  

如果未初始化已定义的变量   在函数内部,变量值保持未定义。这意味着元素继承   以前住在记忆中该位置的任何值。

当程序总是为变量分配空闲内存位置时,这怎么可能?怎么可能是零以外的东西(我假设默认的空闲内存值为零)?

4 个答案:

答案 0 :(得分:12)

  

当程序总是分配空闲内存时,这怎么可能   位置变量?怎么可能是零而不是零?

让我们来看一个示例实际实现。

让我们说它利用堆栈来保存局部变量。

void
foo(void)
{
        int foo_var = 42;
}

void
bar(void)
{
        int bar_var;
        printf("%d\n", bar_var);
}

int
main(void)
{
        bar();
        foo();
        bar();
}

上面完全破解的代码说明了这一点。在我们调用foo之后,堆栈中放置foo_var的某个位置设置为42.当我们调用bar时,bar_var占据该确切位置。实际上,执行代码会导致打印0和42,表明除非已初始化,否则无法依赖bar_var值。

现在应该清楚,需要进行局部变量初始化。但主要可能是个例外吗?有没有什么可以与堆栈一起玩,结果给我们一个非零值?

是。 main不是您程序中执行的第一个函数。事实上,设置所有东西需要的工作。任何这项工作都可以使用堆栈并在其上留下一些非零。您不仅可以在不同的操作系统上获得相同的价值,而且您现在正在使用的系统上可能会突然发生变化。有兴趣的人可以google for"动态链接器"。

最后,C语言标准甚至没有术语堆栈。有一个"地方"对于局部变量,留给编译器。它甚至可以从给定寄存器中发生的任何事情中得到随机废话。它真的可以完全任何东西。事实上,如果触发了未定义的行为,编译器可以自由地做任何感觉。

答案 1 :(得分:9)

  

如果未初始化在函数内定义的变量,则变量值保持未定义。

这一点是真的。

  

这意味着元素会占用以前驻留在内存中该位置的任何值。

这个位不是。

有时在实践中会发生这种情况,并且您应该意识到没有为零完全符合这个理论,对于任何给定的程序运行。

理论上,如果需要,您的编译器实际上可以为该整数分配一个随机的初始值,因此尝试合理化这一点完全没有意义。但让我们继续,好像我们假设“元素具有以前驻留在记忆中该位置的任何值”......

  

怎么可能是零而不是零(我假设默认的空闲内存值为零)?

嗯,这就是你假设的情况。 :)

答案 2 :(得分:3)

由于指针未初始化使用,因此此代码调用未定义行为(UB)。

使用警告标志时,编译器应发出警告,例如-Wall

warning: 'i' is used uninitialized in this function [-Wuninitialized]
  cout << i;
          ^

碰巧的是,在您的系统上,此运行时它的值为0。这意味着该变量被分配给的垃圾值恰好为0,因为那里的内存剩余建议这样做。

但是请注意,kernel zeroes appear relatively often。这意味着我可以将零作为系统的输出,这是很常见的事,但这并不能保证,也不应被视为承诺。

答案 3 :(得分:1)

静态变量和全局变量初始化为零:

Global:
int a;  //a is initialized as 0

void myfunc(){
   static int x;     // x is also initialized as 0
   printf("%d", x);}

作为非静态变量或 auto 变量,即局部变量不确定(不确定通常意味着它可以做任何事情。它可以是零,它可以是在那里的价值,它可以使程序崩溃)。在分配值之前读取它们会导致未定义的行为。

void myfunc2(){
   int x;        // value of x is assigned by compiler it can even be 0
   printf("%d", x);}

它主要取决于编译器,但一般情况下,大多数情况下,编译器将值假定为0