据说我们最好用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;
}
没关系!我可以得到我写的东西。 我想知道背后的原因。
答案 0 :(得分:3)
正如所有评论所示:
你必须自己做。
由于您将指针声明为字符串,因此您必须确保指针指向您的内存。
当您为指针指定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)
有效。