【问题标题】:malloc() in C not working as expectedC 中的 malloc() 未按预期工作
【发布时间】:2013-11-12 04:48:24
【问题描述】:

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

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

谢谢, 西蒙

【问题讨论】:

  • 因为你到达了“未定义的行为”领域。任何事情都可能发生......
  • 另外,不要强制返回malloc:stackoverflow.com/questions/605845/…,而sizeof(char)是多余的,mallocchar来计算分配数组的大小,所以根据定义sizeof(char) 是一个。
  • 感谢 Jens Gustedt!我也想知道类型转换。

标签: c malloc


【解决方案1】:

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

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

操作系统并不关心您在自己的程序中乱搞。只有当你在操作系统给你的范围之外编写代码时,你的程序才会崩溃。

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

编辑:

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

【讨论】:

  • 对...我想这回答了我的问题,谢谢!那么*s = (char *)malloc((strlen(temp)+1)*sizeof(char)); 行是否为数据分配了正确的空间量? (每次程序运行时,即使它不应该运行,也有一个隐藏在内心深处的错误=))
  • 是的,之后您可以安全地将内容 temp 复制到 s。但是,您不检查用户输入的长度,因此如果给出的字符数超过 MAXLEN 个,则 temp 将溢出。
  • 酷,谢谢! C 确实是一门...有趣的语言 =)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

          一般来说,缓冲区溢出导致的崩溃只发生在...

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

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

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

          【讨论】:

            【解决方案7】:

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

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

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

            问题是如何工作的......

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

            当您调用 'free' 时,您的区块会返回到空闲链列表。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-08-20
              • 1970-01-01
              • 1970-01-01
              • 2011-04-25
              • 1970-01-01
              相关资源
              最近更新 更多