16

当我创建指向某个结构的指针时,是否必须将其设置为 NULL,然后分配它然后使用它?为什么?

4

6 回答 6

17

不,您不必将其设置为NULL,但有些人认为这是一种很好的做法,因为它为新指针提供了一个值,使其明确表示它没有指向任何东西(还)。

如果您正在创建一个指针,然后立即为其分配另一个值,那么将其设置为NULL.

NULL不过,在释放它指向的内存之后设置一个指针是个好主意。

于 2012-09-03T19:38:27.440 回答
10

不,没有要求(就语言而言)在声明指针变量时将其初始化为任何内容。因此

T* ptr;

是一个有效的声明,它引入了一个以ptr不确定值命名的变量。您甚至可以以某些方式使用该变量,而无需先分配任何内容或将其设置为任何特定值:

func(&ptr);
于 2012-09-03T19:47:03.563 回答
6

根据 C 标准,不初始化自动存储变量会导致其值不确定。

当您的指针具有不确定值时,绝对鼓励您将指针设置为 NULL。使用具有不确定值的指针是未定义的行为,如果您习惯于 C 编程并且来自更高级别的语言,您可能无法正确掌握这个概念。

未定义的行为意味着任何事情都可能发生,这是 C 标准的一部分,因为 C 的哲学是让程序员有责任控制事物,而不是保护他免受错误的影响。

你想避免代码中未定义的行为:当任何行为可能发生时,调试东西是非常困难的。它不会被编译器捕获,并且您的测试可能总是通过,而不会注意到错误,直到纠正它的成本非常高。

如果你做这样的事情:

char *p;
if(!p) puts("Pointer is NULL");

您实际上并不知道该if控制是对还是错。这在大型程序中是极其危险的,您可以在其中声明变量,然后在空间和时间很远的地方使用它。

引用释放的内存时的概念相同。

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。你不希望他们得到一个不确定的价值,永远不要。我应该说,除非你知道你在做什么,但我更喜欢从不

于 2018-07-17T10:41:43.080 回答
2

不,不要忘记初始化必须是空指针。现代 C 中一个非常方便的习惯用法是在第一次使用时声明变量

T * ptr = malloc(sizeof *ptr);

这避免了你记住类型以及变量是否已经初始化的麻烦。只有当你不知道它后来在哪里(或者即使)它被初始化时,你才应该明确地将它初始化为一个空指针。

因此,根据经验,始终将变量初始化为适当的值。0如果您手头没有更好的选择,“适合类型”总是一个不错的选择。对于所有类型,C 都是这样制作的,因此它可以工作。

在大多数情况下,不初始化变量是过早的优化。仅当您发现那里存在真正的性能瓶颈时,才检查您的变量。特别是如果在使用初始值之前在同一个函数内部进行了赋值,那么现代编译器会优化你的初始化。首先考虑程序的正确性。

于 2012-09-03T22:25:21.177 回答
0

除非您不希望它悬空一会儿,否则您不必这样做。你知道你应该在释放(防守风格)之后。

于 2012-09-03T19:39:33.073 回答
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

于 2012-09-03T19:44:34.403 回答