1

我是 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 个字符。

PS如果这有什么不同,我正在使用Xcode。

谢谢,西蒙

4

7 回答 7

2

效果很好,因为你很幸运!通常,操作系统会为您的程序提供一个比 2 字节大一点的块。

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

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

尝试写入 200 字节,看看它是否崩溃。

编辑:

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

于 2013-11-11T20:21:30.480 回答
2

是的,将更多数据写入分配的缓冲区是缓冲区溢出。但是,在 C 中没有缓冲区溢出检查,如果缓冲区之后恰好有有效内存,那么您的代码将看起来正常工作。

但是,您所做的是写入您不拥有并且可能已损坏堆的内存。您的下一次调用freemalloc可能会崩溃,或者如果不是下一次调用,稍后的调用可能会崩溃,或者您可能会很幸运并malloc给您一个比您请求的缓冲区更大的缓冲区,在这种情况下您将永远不会看到问题。

于 2013-11-11T20:23:22.593 回答
2

如果我输入的字符串超过两个字符,这不会导致缓冲区溢出吗?

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

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

于 2013-11-11T20:30:46.947 回答
1

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

此外,如果您有一个变量就在您分配的块后面,它可能会被您输入的内容覆盖。

于 2013-11-11T20:23:23.430 回答
1

简单地说,这是未定义行为的一种情况。你很不幸,你得到了预期的结果。

于 2013-11-11T20:27:10.233 回答
1

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

通常,缓冲区溢出导致的崩溃仅发生在...

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

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

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

于 2013-11-11T20:27:52.077 回答
1

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

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

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

它是如何工作的,这是个问题……

所以你的系统有空闲链表,列出了所有可用的内存空间,malloc 搜索这个列表,直到找到足够大的空间。然后它将这个空间分成 2 个,向您发送所需的空间并将另一个空间放回列表中。它分解成 2^n 大小的块,这样你的列表中就不会出现奇怪的空间大小,就像乐高一样容易。

当您调用“免费”时,您的块将返回到免费链列表。

于 2013-11-11T20:35:07.767 回答