2011-11-19 528 views
1

我在接受采访时被问到了这个问题。什么是未初始化的指针变量?

如果有声明,但没有初始化像这样的指针: int *ptr;

是它分配一个默认值?或者它会是一个空指针?

if(ptr) { //block of code }

请问如果条件通过:另外,如果我们试图用这个指针一样会发生什么?此外,这将工作在调试/发布构建?

我试着在家里运行这个程序,发现if条件的推移,如果我尝试打印的PTR这样的值:

printf("%x %d", ptr, *ptr);

它打印一些随机值,但它不会使程序崩溃。这背后的解释是什么?

回答

4

未初始化的指针适用于安全漏洞,并可能有助于播种随机数生成器。

如果指针已初始化为NULL(0),则您的if条件将仅跳过该代码块。

因为初始化值默认是未定义的,所以初始化为NULL总是被认为是很好的做法。

您的printf语句只是说明了它默认为NULL以外的值的事实,在这种情况下,它是一个可以取消引用的有效内存区域。

+1

“可能有助于播种随机数发生器” - 提供的熵估计值与0一致。 –

+0

并提供了一条评论,指出这是未初始化的原因,因此有人不运行valgrind,初始化为null并打开一个新的安全漏洞(http://digitaloffense.net/tools/debian-openssl/) –

+2

虽然这很复杂。 Debian的bug涉及一个删除*两个操作来添加种子数据的检查。其中一个贡献的数据始终未初始化,并导致valgrind/purify错误。删除这是安全的,因为它不是播种过程的重要组成部分。其他操作贡献的数据通常不是未初始化的,在初始化的情况下,它对安全性至关重要。但是这条线看起来很像另一条线,所以当另一条线(可能是正确的)被删除时,它(绝对不正确)也被删除了。 –

9

如果它是一个全局变量(或static),它将被隐式初始化为NULL。否则,它的值是未定义的。因此,该if语句的行为是未定义的(即,您不能假定它可能做什么)。您的第二个示例的行为也未定义(并且可能导致分段错误)。

未初始化的指针被认为是危险的;想象一下这段代码的后果:

int *ptr; 

... 

*ptr = 42; // Dereference pointer and trash somewhere random in memory 

但是请注意,这可能不会崩溃;它可能会悄悄地破坏东西。

所以约定总是明确地初始化它指向一些有用的东西。如果这是不可能的(例如,你还没有指向的东西),你可以做的下一个最好的事情是将其初始化为NULL。取消引用NULL指针会在大多数平台上引发分段错误,这至少可以帮助您追踪错误。

+0

谢谢你的回答。我认为这是有道理的。 – rain

2

什么是非初始化指针变量的好处?

效率。如果C自动初始化指向NULL的指针,它将浪费整个CPU指令(或者如果变量必须存储在主存储器而不是寄存器中,则可能更多),这对于C的设计者是不可接受的。你会相信程序员现在想牺牲宝贵的纳秒运行时间来节省几个小时的调试吗?

+3

没有帮助的事实是,在C89中你必须在块的顶部定义所有的变量,并且(错误地是IMO)一种常见的风格是将它们全部定义在函数的顶部。所以人们在变量被初始化之前很久就定义了变量,包括有条件地未使用的变量。出于你说的原因,并且因为伪初始化可以抑制关于真正未使用的变量的编译器警告,所以通常很容易定义它们而没有初始化器。现在你可以在你喜欢的地方定义变量,定义一个有条件的未使用的变量的理由很少。 –

+0

“抑制编译器警告” - 示例'int * s = 0,* a = 0; if(condition1){a = value1; } else if(condition2){a = value2; } else if(condition3} {s = value3;/* typo,应该是 - 如果我没有初始化为0,我可能会得到关于此分支的编译器警告* /} printf(“%d \ n” ,* a);''我的意思是真正未初始化的,没有真正没有被使用的...... –

+1

我认为正交性不仅仅是效率,一般来说局部变量不是为了效率原因而初始化的(想想大数组),特别是局部指针变量为正交原因初始化。 – ninjalj