在c中获取和malloc

在c中获取和malloc,c,malloc,gets,C,Malloc,Gets,在github的某个地方,我看到了下面的代码 char *p=malloc(1); gets(p); printf(p); 我也试过同样的方法,结果发现效果不错。 无论我输入的字符串有多长,它都会被存储,并且不会给出分段错误。它是如何工作的?我只给了它1个字节 加上当我输入freep时;它给出了奇怪的输出。这段代码是一个教科书上的例子,说明了为什么GET从2011年的标准库中被删除。这是一种恶意软件攻击 获取从标准输入读取字符序列,直到它看到换行符,并将该序列存储到从地址p开始的缓冲区。get

在github的某个地方,我看到了下面的代码

char *p=malloc(1);
gets(p);
printf(p);
我也试过同样的方法,结果发现效果不错。 无论我输入的字符串有多长,它都会被存储,并且不会给出分段错误。它是如何工作的?我只给了它1个字节


加上当我输入freep时;它给出了奇怪的输出。

这段代码是一个教科书上的例子,说明了为什么GET从2011年的标准库中被删除。这是一种恶意软件攻击

获取从标准输入读取字符序列,直到它看到换行符,并将该序列存储到从地址p开始的缓冲区。gets不知道目标缓冲区有多大,如果输入序列比缓冲区的大小要长,则gets会很高兴地将这些多余的字符立即存储到缓冲区后面的内存中,这可能会造成各种混乱

分配一个1字节宽的缓冲区。当调用gets时,它会将输入的第一个字符写入该缓冲区,然后将任何额外的输入加上一个零值终止符写入紧跟在缓冲区之后的未分配堆内存

在这个特定的情况下,没有什么重要的内容被覆盖,因此您的代码似乎运行正常。但是,在另一个上下文中,此代码可能会导致其他数据损坏或导致运行时错误

写入超过缓冲区结尾的行为未定义;编译器不必发出任何警告,编译后的代码可以执行任何操作,从彻底崩溃到执行病毒,都可以按预期工作

所以

永远不要用得到。曾经在任何情况下。甚至连玩具代码都没有。正如我所说,它不再是标准库的一部分

C将所有资源管理的负担都放在您身上,程序员缓冲区不会自动增长以容纳额外的输入,也不会有任何自动垃圾收集来清理不再被引用的动态内存

C语言不会保护你不做愚蠢的事情——这种语言假设你知道你在做什么


正如其他人所指出的,这是未定义的行为

未定义的行为可能很难思考。这里有一个类似于你的问题,这可能会让你更容易思考

我在某个地方听到这样一条规则,“红灯亮时,你不能通过检票口”。 我也试过同样的方法,结果发现效果不错。 不管我开多少次车闯红灯,都没有什么不好的事情发生。 它是如何工作的?
我住在一个小镇上,不久前由于预算削减,我们不得不解雇我们的警察。

假设你有一个朋友是一个心不在焉的房地产经纪人。有一天你对他说,我想建一座房子。他问:“你想要多大的房子?”?你说,哦,1000平方英尺就可以了。他说,事实上,我的房子旁边有一块1000平方英尺的空地。你可以拥有它。然后他去度假

假设你还有一个朋友是个粗心的建筑工人。你说,我刚买了很多。你能在上面给我盖栋房子吗?“没问题,”他说,然后就出发,开始挖掘和建造。事实上,既然你没有告诉他要建多大的房子,他就给你建了一栋10000平方英尺的豪宅。在这个过程中,他无意中拆除了隔壁房地产经纪人的房子,同时挖掘了新大厦的西翼

后来你意识到你根本不想要这座豪宅,所以你决定把这块地卖给房地产经纪人。当他度假回来时,你给他打手机告诉他这件事。你希望他说,好吧,太好了,现在我可以把这批货卖给别人了。相反,他喊道:“你这个混蛋,我要起诉你!”!你认为这是一个奇怪的说法。 如果不明显的话,这个小故事中的房地产经纪人扮演了malloc和free的角色,而建筑商扮演了gets的角色

你的代码还有一个问题。这个类比更不现实,但让我们试试看。假设,在建筑商建造完你的豪宅后,但在你试图拆除它之前,你决定想要一张它的照片。所以你请你的朋友,一个非常注重文字的摄影师,为你拍一张照片。你知道我的规矩,他说。请把你们想让我拍照的物品列一个清单,然后放在我的邮箱里。你找不到一张纸,而且你认为写一个只有一个项目的清单是愚蠢的,所以你没有把一张写着“我的房子”的清单放在他的邮箱里,而是把你的整个房子捡起来放在他的邮箱里。当然,它不合适,所以你把它放在他的前廊上。当他到家时,他看到了你的房子,一时感到困惑,但你的房子上有你的邮箱,所以现在他回到了坚实的基础上,他知道该做什么,他打开邮箱寻找他的下一个任务。在你的m里面 ailbox是你的新版本《国家地理》,封面故事是世界上十个最美丽但致命的地方。所以他去给你拍照,你再也没有他的消息了


所以,当你听到printf的第一个参数需要一个列表,列出你希望它打印的东西时,请总是给它这个列表,即使你只想让它打印一件东西。也就是说,请改用printf%s,p。要了解原因,假设您在gets调用中键入的字符串不是A,不是Hello,而是%s。。然后仔细考虑printf将要做什么,记住printf和你的摄影师朋友一样是字面意思。

不应该使用Undefined behavior.get。在本例中,对于长度大于1的任何字符串,您都有一个越界内存访问权限。如果GET在p中写入的字符超过“\0”以外的零个字符,则会导致缓冲区溢出说明,GET无法检查要写入的字符数。在那之后,任何事情都可能发生。它可能会像您预期的那样工作,可能会在周三使您的程序崩溃,…注意,GET已从最新的C标准中删除。尽量避免使用它,首选fgets,并可能手动删除尾部换行符。scanf格式字符串中的s按字面解释:它不构成转换说明符的一部分。对于包含11个或更多字节的空间,正确的说明符是%10[^\n]。使用scanf进行缓冲区管理通常比使用fgets进行错误恢复要麻烦得多。