当我创建指向某个struct的指针时,是否必须将其设置为NULL,然后分配它然后使用它?为什么?
答案 0 :(得分:10)
不,您不必将其设置为NULL
,但有些人认为这是一种很好的做法,因为它为新指针提供了一个值,使其显式它没有指向任何东西(尚)。
如果你正在创建一个指针,然后立即为它分配另一个值,那么将它设置为NULL
真的没什么价值。
最好在释放指向的内存后设置指向NULL
的指针。
答案 1 :(得分:7)
不,在声明它时,没有要求(就语言而言)将指针变量初始化为任何东西。因此
T* ptr;
是一个有效的声明,它引入了一个名为ptr
的变量,该变量具有不确定的值。您甚至可以以某种方式使用变量,而无需先分配任何内容或将其设置为任何特定值:
func(&ptr);
答案 2 :(得分:3)
根据C标准,未初始化自动存储变量将使其值不确定。
无论哪种情况,只要您的指针具有不确定的值,就绝对建议您将指针设置为NULL。具有不确定值的指针的使用是不确定的行为,如果您习惯于C编程并且来自高级语言,则可能无法正确理解该概念。
未定义的行为意味着任何事情都会发生,这是C标准的一部分,因为C的哲学是让程序员负担控制事情的重担,而不是保护他免受错误的侵害
您要避免代码中未定义的行为:任何行为都可能发生时,调试东西非常困难。它不会被编译器捕获,并且您的测试可能始终会通过,直到发现该错误的代价很高时,该错误才会被忽略。
如果您执行以下操作:
char *p;
if(!p) puts("Pointer is NULL");
您实际上并不知道if
控件是true还是false。这在大型程序中非常危险,在大型程序中,您可能会声明变量,然后在时空很远的地方使用它。
引用释放的内存时的概念相同。
free(p);
printf("%s\n", p);
p = q;
您实际上并不知道最后两个语句会得到什么。您无法正确测试它,无法确定结果。您的代码似乎可以正常工作,因为即使已更改释放的内存,回收的内存也可能被更改了……您甚至可以覆盖内存,或者破坏共享同一内存的其他变量。因此,您仍然有一个迟早会出现的错误,并且可能很难调试。
如果将指针设置为NULL,则可以保护自己免受以下危险情况的影响:在测试期间,您的程序将具有确定性,可预测的行为,该行为将快速且廉价地失败。您遇到了段错误,发现了错误,并修复了该错误。干净简单:
#include <stdio.h>
#include <stdlib.h>
int main(){
char* q;
if(!q) puts("This may or may not happen, who knows");
q = malloc(10);
free(q);
printf("%s\n", q); // this is probably don't going to crash, but you still have a bug
char* p = NULL;
if(!p) puts("This is always going to happen");
p = malloc(10);
free(p);
p = NULL;
printf("%s\n", p); // this is always going to crash
return 0;
}
因此,在初始化指针时(尤其是在大型程序中),您希望将其显式初始化或设置为NULL。您不希望他们获得不确定的价值,永远不要。我应该说,除非您知道自己在做什么,但我更喜欢从不。
答案 3 :(得分:2)
不,不要忘记初始化必须是空指针。现代C中一个非常方便的习惯是在第一次使用时声明变量
T * ptr = malloc(sizeof *ptr);
这可以避免您在记住类型以及变量是否已经初始化时遇到很多麻烦。只有当你不知道它在哪里(或者甚至是)稍后被初始化时,你最终应该将它初始化为空指针。
因此,根据经验,始终将变量初始化为适当的值。如果您手边没有更好的类型,那么“适合0
类型”总是一个不错的选择。对于所有类型,C都是这样制作的,这样就可以了。
在大多数情况下,不初始化变量是过早优化。当您发现存在真正的性能瓶颈时,只需查看变量。特别是如果在使用初始值之前在同一函数内存在赋值,并且现代编译器将优化初始化输出。首先考虑你的程序的正确性。
答案 4 :(得分:0)
除非你不想让它悬挂一段时间,否则你不必这样做。你知道你在解放后应该(防御风格)。
答案 5 :(得分:0)
您不必初始化为NULL。如果您打算立即分配,可以跳过它。
At可用于错误处理,如下例所示。在这种情况下,在p
分配后中断结束会使q
保持未初始化状态。
int func(void)
{
char *p;
char *q;
p = malloc(100);
if (!p)
goto end;
q = malloc(100);
if (!q)
goto end;
/* Do something */
end:
free(p);
free(q);
return 0;
}
此外,这是我的个人品味,总是使用calloc
分配结构。字符串可以使用malloc