当我将指针初始化为NULL时,运行结果很奇怪

时间:2018-03-03 12:48:42

标签: c pointers null

据说我们最好用NULL初始化一个新指针,否则会发生意外结果。但事实是,当我按如下方式添加NULL时:

#include <stdio.h>
int main(){
    char *str = NULL;
    gets(str);
    printf("%s\n", str);
    return 0;
}

结果是:

Segmentation fault: 11

我只是保留新指针,如下所示:

#include <stdio.h>
int main(){
    char *str;
    gets(str);
    printf("%s\n", str);
    return 0;
}

没关系!我可以得到我写的东西。 我想知道背后的原因。

2 个答案:

答案 0 :(得分:3)

正如所有评论所示:

C不为您处理内存

你必须自己做。

由于您将指针声明为字符串,因此您必须确保指针指向您的内存。

  • 当您为指针指定NULL时,它指向“禁止”内存地址为零并尝试在那里放置某些内容(使用gets)导致内存管理拦截您不允许的尝试并中止您的程序;

  • 当你没有为它指定任何内容时,它是一个未初始化的本地变量,它有一个垃圾值(指向一个随机地址),你可以在其中存储读取的字符串gets但是在程序的任何后续点都会导致任何随机行为,称为未定义的行为。你写的内存可能是你的,但没有管理(其他东西存放在那里)。

有两种方法可以解决这个问题:

  • 向堆请求内存(使用malloc),例如char *str= malloc(1024);

  • 声明一个足够大的缓冲区,例如char str[1024];

不要使用gets。这是不安全的。使用fgets

答案 1 :(得分:3)

您的两个版本都是错误的并且具有未定义的行为。未定义 行为意味着结果未定义,任何事情都可能发生:段错误 例如,程序运行的外观没有问题。

首先,再也不要使用gets,这是一个没有危险的功能 考虑缓冲区的大小,可能会导致缓冲区溢出。这个 函数也已在C99中弃用,因此没有真正的理由使用它,使用 而是fgets

gets需要一个指向char数组的指针,它存储字符串。如果你 传递NULL指针,gets不检查并通过NULL进行写入 指针,这是未定义的行为。

如果你这样做

char *str;
gets(str);

这里你只是声明一个新的指针,但它是未初始化的,这意味着 它指向内存中的随机位置。在你的情况下似乎这样 随机位置是有效的,因此该程序具有外观 一切正常。你必须初始化你的指针并制作它 指向有效的地方

char buffer[1024];
char *str = buffer;
fgets(str, 1024, stdin);

或者您必须使用malloc&amp;分配内存。朋友

char *str = calloc(1024, 1);
if(str == NULL)
{
    fprintf(stderr, "not enough memory\n");
    return;
}
fgets(str, 1024, stdin);

许多人说你应该使用NULL初始化指针的原因 是因为它允许稍后检查指针是否指向某个有效位置 在记忆中。例如,算法可以检查指针是否指向有效 位置,然后它继续,否则它先分配内存然后 继续。它也是一个很好的策略,必须释放记忆:

char *ptr = NULL;

if(something_is_true())
{
    // do stuff
    ptr = malloc(...);

    // more stuff
}

free(ptr);

如果something_is_true()返回false,则free(ptr)赢了 错误,因为free(NULL)有效。