gets()如何超过malloc()分配的内存?

我对malloc和realloc函数有疑问,当我使用malloc函数为字符指针10字节分配内存时。 但是当我为该字符指针赋值时,如果我尝试分配则需要超过10个字节。 怎么可能。

例如:

main() { char *ptr; ptr=malloc(10*sizeof(char)); gets("%s",ptr); printf("The String is :%s",ptr); } 

样本输出:

 $./a.out hello world this is for testing 

字符串是:hello world这是用于测试

现在看输出字符数超过10个字节。 怎么可能,我需要明确的解释。 提前致谢。

malloc将保留10个字节(在您的情况下假设char有1个字节)并将返回保留区域的起始点。
你做了一个gets ,所以它得到你输入的文本并使用你的指针写。 Windows / Mac OS x / Unix(Advances OS’S)具有受保护的内存。 这意味着,当您执行malloc / new时,操作系统会为您的程序保留该内存区域。 如果另一个程序试图在该区域中写入,则会发生分段错误,因为您在不应该写入的区域上写入。

你保留了10个字节。 如果字节11,12,13,14尚未保留给另一个程序,它将不会崩溃,如果它是您的程序将访问受保护区域并崩溃。

这就是为什么使用gets是一件邪恶的事情 。 请改用fgets

malloc与它无关

不要使用gets() 。

不可否认,理由是有用的,是吗? 首先, gets()不允许您指定存储字符串的缓冲区的长度。这将允许人们在缓冲区末尾输入数据 ,并相信我,这将是坏消息。

详细说明 :

首先,让我们看一下这个函数的原型:

 #include  char *gets(char *s); 

您可以看到唯一参数是char指针。 那么,如果我们创建一个这样的数组:

 char buf[100]; 

我们可以将它传递给gets()如下所示:

 gets(buf) 

到现在为止还挺好。 或者似乎……但实际上我们的问题已经开始了。 gets()只接收了数组的名称(一个指针), 它不知道数组有多大 ,并且不可能仅从指针中确定这个数字。 当用户输入文本时, gets()会将所有可用数据读入数组,如果用户理智且输入少于99个字节,这将没有问题。 但是,如果它们输入的数量超过99,则gets() 不会在数组末尾停止写入 。 相反,它继续写到结束并进入它不拥有的内存。

  1. 此问题可能以多种方式表现出来:

  2. 没有可见的影响,所以永远

  3. 立即终止程序(崩溃)

  4. 终止程序生命周期的后期(可能是1秒后,也许是15天后)

  5. 终止另一个无关的计划

  6. 程序行为和/或计算不正确……列表继续。 这是“缓冲区溢出”错误的问题,你无法分辨它们何时以及如何咬你。

你刚才有一个未定义的行为。 ( 更多信息在这里 )

使用fgets而不是获取!

malloc保留内存供您使用。 规则是允许您使用以这种方式和其他方式分配的内存(如通过定义自动或静态对象),并且不允许使用未分配给您使用的内存。

但是, malloc和操作系统并不完全执行这些规则。 遵守它们的义务属于您,而不属于malloc或操作系统。

通用操作系统具有内存保护function,可防止一个进程在未经许可的情况下读取或更改另一个进程的内存。 它不会阻止一个进程以不正确的方式读取或更改自己的内存。 当您访问不应该使用的字节时,没有任何机制可以始终阻止这种情况。 内存在那里,您可以访问它,但您不应该访问它。

gets是一个设计糟糕的例程,因为如果输入行足够长,它将写入任何数量的内存。 这意味着您无法阻止它写入比分配的内存更多的内存。 你应该使用fgets代替。 它有一个参数,可以限制它可以写入的内存量。

通用操作系统以称为页面的块分配内存。 页面大小可能是4096字节。 当malloc为您分配内存时,它可以从操作系统获得的最小大小是一页。 当你要求十个字节时, malloc将获得一个页面,如果需要,在其中选择十个字节,记录已经分配了一小部分页面,但其余部分可用于其他用途,并返回指向十个字节的指针字节给你。 当您进行进一步分配时, malloc可能会从同一页面分配额外的字节。

当您超出已分配给您的字节时,您违反了规则。 如果您的进程的其他任何部分没有使用这些字节,您可能会逃避此违规行为。 但是您可能会更改malloc用于跟踪分配的数据,您可能会更改作为单独内存分配的一部分的数据,或者如果您走得足够远,可能会完全更改单独页面中的数据,并且由程序的完全不同部分使用。

通用操作系统确实提供了一些保护,防止在您的进程中不正确地使用内存。 如果您尝试访问未在虚拟地址空间中映射的页面,或者您尝试修改标记为只读的页面,则会触发故障,并且您的进程将被中断。 但是,此保护仅适用于页面级别,并且不能防止您错误地使用分配给您的进程的内存。

OP:…字符数超过10个字节。 这怎么可能?
答:写入外部分配的内存由gets()是未定义的行为 – UB。 UB的范围从您想要的崩溃和燃烧开始。

真正的问题不是令人遗憾的使用gets() ,而是C语言应该防止内存访问误用想法 。 C不会阻止它。 代码应该阻止它。 C不是一种具有大量幕后保护的语言。 如果写入ptr[10]是坏的,不要这样做。 不要调用可能会执行此操作的函数,例如gets() 。 像生活的许多方面 – 练习安全计算。

C为你提供了很多绳索来做各种各样的事情,包括足够的绳索来吊自己。