C中的malloc()没有按预期工作

时间:2013-11-11 20:16:56

标签: c malloc

我是C的新手。对不起,如果已经回答了这个问题,我找不到答案,所以我们走了......

我正在尝试理解malloc()在C中是如何工作的。我有这段代码:

#define MAXLINE 100

void readInput(char **s)
{
    char temp[MAXLINE];

    printf("Please enter a string: ");
    scanf("%s", temp);

    *s = (char *)malloc((strlen(temp)+1)*sizeof(char)); // works as expected
    //*s = (char *)malloc(2*sizeof(char)); // also works even when entering 10 chars, why?

    strcpy ((char *)*s, temp);
}

int main()
{
    char *str;

    readInput(&str);
    printf("Your string is %s\n", str);
    free(str);

    return 0;
}

问题是为什么当我像这样调用malloc()时,程序不会崩溃(或者至少剥离剩余的字符):

*s = (char *)malloc(2*sizeof(char)); // also works even when entering 10 chars, why?

如果我输入一个超过两个字符的字符串,这不会导致缓冲区溢出吗?我理解malloc(),它为数据分配一个固定的空间,所以肯定只为两个字符分配空间将允许字符串最多一个可用字符('0'是第二个),但它仍然是打印输入所有10个字符。

P.S。如果有任何不同,我正在使用Xcode。

谢谢, 西蒙

7 个答案:

答案 0 :(得分:2)

这很好,因为你很幸运!通常,操作系统会为程序提供略大于2个字节的块。

如果操作系统在您要求2个字节时实际给出了16个字节,则可以写入16个字节,而操作系统不会注意到它。但是,如果您的程序中有另一个malloc()使用了其他14个字节,那么您可以将这些变量内容写下来。

操作系统并不关心你在自己的程序中乱搞。如果您在操作系统提供的内容外写作,您的程序将只会崩溃。

尝试写入200个字节并查看它是否崩溃。

编辑:

malloc()free()使用一些堆空间来维护有关已分配内存的信息。该信息通常存储在存储块之间。如果溢出缓冲区,则可能会覆盖此信息。

答案 1 :(得分:2)

是将更多数据写入分配的缓冲区是缓冲区溢出。但是,在C中没有缓冲区溢出检查,并且在缓冲区之后是否存在有效内存,而不是代码看起来可以正常工作。

但是你所做的就是写入你不拥有的内存并且可能已经破坏了堆。您对freemalloc的下一次通话可能会崩溃,或者如果没有下一次通话,以后的某个通话可能会崩溃,或者您可能会很幸运,malloc向您提供的缓冲区比您大请求,在这种情况下,你永远不会看到问题。

答案 2 :(得分:2)

  

如果我输入一个包含两个以上字符的字符串,这不会导致缓冲区溢出吗?

绝对。但是,C在运行时没有检查边界;它假设您在分配内存时知道自己在做什么,并且知道可用的内容。如果你超过缓冲区的末尾,你将破坏之前的任何东西。

是否导致代码崩溃取决于之前的内容以及您使用的内容。并非所有溢出都会导致程序崩溃,并且堆中的溢出可能不会导致任何(明显的)问题。

答案 3 :(得分:1)

这是因为即使你没有分配内存,内存也存在。 您正在访问不属于您的数据,可能使用良好的调试器或静态分析器,您会看到错误。

此外,如果您的变量位于您分配的块后面,则可能会被您输入的内容覆盖。

答案 4 :(得分:1)

这只是未定义行为的案例之一。你不幸的是你得到了预期的结果。

答案 5 :(得分:1)

确实会导致缓冲区溢出。但是C没有做任何事情来防止缓冲区溢出。大多数malloc的实现都没有。

通常,缓冲区溢出崩溃只发生在......

  • 它溢出了一个页面 - malloc实际从操作系统获取的内存单元。 Malloc将从同一页内存中完成许多单独的分配请求。
  • 溢出会破坏缓冲区后面的内存。这不会导致立即崩溃。当其他代码运行时,它会导致崩溃,这取决于该内存的内容。

(......但这些事情取决于所涉系统的具体情况。)

如果幸运的话,完全有可能缓冲区溢出永远不会导致崩溃。虽然它可能会产生其他不太明显的问题。

答案 6 :(得分:1)

malloc()是在Stdlib.h头文件中指定的函数调用。如果您使用数组,则必须在使用数据之前修复内存长度。但是在malloc()函数中,您可以在需要时以所需大小分配内存。当您通过malloc()分配内存时,它将搜索内存模块并找到空闲块。即使内存块位于不同的位置,它也会分配一个地址并连接所有块。 当你的过程完成后,你可以释放它。自由意味着,分配内存仅在RAM中。处理完该函数并生成一些数据后,您将把数据转移到硬盘或任何其他永久存储器。之后,您可以释放该块,以便您可以使用其他数据。 如果你要通过指针函数,使用malloc()就不能生成数据块。 New()是c ++的关键字。

当你不知道编程时你需要多大的内存空间时,你可以使用函数malloc

void * malloc(size_t size); malloc()函数应为一个对象分配未使用的空间,该对象的大小以字节为单位由size指定,其值未指定。

它的工作原理是什么......

所以 你的系统有自由链列表,它列出了所有可用的内存空间,malloc搜索这个列表,直到找到一个足够大的空间,你需要它。然后它在2中打破这个空间,向你发送你需要的空间并将另一个放回到列表中。它打破了2 ^ n的大小,你的列表中没有奇怪的空间大小,这就像Lego一样简单。

当你打电话'免费'时你的区块会回到免费链列表。