当我将指针初始化为NULL时,运行结果很奇怪
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当我将指针初始化为NULL时,运行结果很奇怪相关的知识,希望对你有一定的参考价值。
据说我们最好用NULL初始化一个新指针,否则会发生意外结果。但事实是,当我按如下方式添加NULL
时:
#include <stdio.h>
int main(){
char *str = NULL;
gets(str);
printf("%s
", str);
return 0;
}
结果是:
Segmentation fault: 11
虽然我只是保留新指针,如下所示:
#include <stdio.h>
int main(){
char *str;
gets(str);
printf("%s
", str);
return 0;
}
没关系!我可以得到我写的东西。我想知道背后的原因。
正如所有评论所示:
C不为您处理内存
你必须自己做。
既然你声明了一个指向字符串的指针,你必须确保指针指向你的内存。
- 当你为指针指定NULL时,它指向“禁止”的内存地址为零,并尝试在那里放置一些东西(使用
gets
)导致内存管理拦截你不允许的尝试并中止你的程序; - 当你没有为它分配任何内容时,它是一个未初始化的局部变量,它有一个垃圾值(指向一个随机地址),你可以用
gets
存储读取的字符串,但这可能导致任何随机行为,称为未定义行为,在你的程序的任何后期。你写的内存可能是你的,但没有管理(其他东西存储在那里)。
有两种方法可以解决这个问题:
- 请求堆内存(使用
malloc
),例如char *str= malloc(1024);
- 声明一个足够大的缓冲区,例如
char str[1024];
。
并且不要使用gets
。这是不安全的。使用fgets
。
您的两个版本都是错误的,并且具有未定义的行为。未定义的行为意味着结果未定义,任何事情都可能发生:例如段错误或程序运行没有问题的外观。
首先,永远不要再使用gets
,它是一个危险的函数,不考虑缓冲区的大小可能导致缓冲区溢出。此功能在C99中也已弃用,因此没有真正的理由使用它,请改用fgets
。
gets
期望一个指向char
数组的指针,它存储字符串。如果你传递一个NULL
指针,gets
不检查并通过NULL
指针写入,这是未定义的行为。
如果你这样做
char *str;
gets(str);
在这里你只是声明一个新的指针,但它是未初始化的,这意味着它指向内存中的随机位置。在你的情况下,这个随机位置似乎是一个有效的位置,因此该程序的外观表明一切正常。您必须初始化指针并使其指向某个有效的位置
char buffer[1024];
char *str = buffer;
fgets(str, 1024, stdin);
或者你必须用malloc
和朋友分配记忆
char *str = calloc(1024, 1);
if(str == NULL)
{
fprintf(stderr, "not enough memory
");
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)
有效。
当您将str
初始化为NULL时,它指向内存地址为零。在典型的系统中,正常进程的虚拟地址空间中的地址为零的页面未被映射 - 操作系统将其标记为不可读和不可写。然后,当您的程序使用gets
尝试读取str
指向的数据时,硬件报告访问内存时出错,操作系统和shell报告给您作为分段错误。
当你没有初始化str
时,它恰好承担了编译器碰巧用于它的内存中的任何值。此值恰好是您地址空间中的某个地址。 (这可能是一些已经在程序堆栈中的指针,因为在调用main
之前帮助启动进程的代码是出于各种目的使用地址。)然后,当你调用gets
时,它会在这个内存中写入数据。显然,这很危险,因为它会将数据写入您的程序可能需要用于其他目的的某个地方。但是,在这种情况下,你逃脱了它,数据被写入内存,然后打印出来。
以上是关于当我将指针初始化为NULL时,运行结果很奇怪的主要内容,如果未能解决你的问题,请参考以下文章
定义指针变量时,必须将指针变量初始化为NULL(为空),否则,指针变量会由于初始化位置的不确定