【问题标题】:Why is my code working when I haven't allocated enough memory using malloc()?当我没有使用 malloc() 分配足够的内存时,为什么我的代码可以工作?
【发布时间】:2015-02-08 04:14:51
【问题描述】:

我在 SPOJ 上做这个问题。 http://www.spoj.com/problems/NHAY/。它需要动态输入。在下面的代码中,即使我没有使用malloc()char *needle 分配内存——我正在使用l = 1——但我能够接受任何长度的输入,并且它正在打印出整个字符串。有时它会给出运行时错误。当我没有为字符串分配足够的内存时,为什么会这样?

#include<stdio.h>
#include<malloc.h>
#include<ctype.h>
#include<stdlib.h>

int main()
{
    long long l;
    int i;
    char *needle;
    while(1){
        scanf("%lld",&l);
        needle =(char *)malloc(sizeof(char)*l);
        scanf("%s",needle);
        i=0;
        while(needle[i]!='\0'){
            printf("%c",needle[i]);
            i++;
        }
        free(needle);
    }
}

我还在stackoverflow上读到一个字符串是char *,所以我应该声明char *needle。我如何在代码中使用这个事实?如果我采用l = 1,那么无论输入字符串的长度是多少,它应该包含的字符最多只能到为char * 指针分配的内存,即1 个字节。我该怎么做?

【问题讨论】:

  • 未定义的行为是未定义的。有时它会崩溃,有时它似乎可以工作,但两次都不正确。
  • 您分配了一些内存,但由于没有边界检查,它给您一种错觉,即您可以使用比您指定的更多的内存。如果在您分配的块之后有空闲内存,它不会崩溃,否则它将崩溃或覆盖那里的内存。

标签: c pointers memory memory-management dynamic-memory-allocation


【解决方案1】:

C 语言没有默认的绑定检查。充其量它会在调试时崩溃,有时它会按预期工作。否则,您最终将覆盖其他内存块。

它并不总是有效。它是未定义的行为

【讨论】:

    【解决方案2】:

    您的代码通过让sscanf 将大于分配空间的字符串复制到malloc 分配的内存中来产生故意的缓冲区溢出。这“有效”是因为在大多数情况下,分配的缓冲区位于页面中间的某个位置,因此将更多数据“仅”复制到缓冲区中会覆盖相邻的数据。 C(和 C++)不对普通 C 数组进行任何数组边界检查,因此错误未被捕获。

    在您最终遇到运行时错误的情况下,您很可能将字符串的一部分复制到未映射和未分配的内存中,这会触发访问冲突。

    内存通常是从底层操作系统以固定大小的页面分配的。例如,在 x86 系统上,页面大小通常为 4k。如果您正在写入的映射地址距离页面的开头和结尾足够远,则整个字符串将适合页面的边界。如果您足够接近上限,代码可能会尝试越过边界写入,从而触发访问冲突。

    【讨论】:

    • 你能解释一下什么是“页面中间”吗?
    • 感谢您的努力和解释!
    【解决方案3】:

    [对底层系统有一些假设]

    它现在工作的原因是 C 库管理从操作系统的页面中分配的内存池。操作系统只返回页面。 C 库返回任意数量的数据。

    对于您的第一次分配,您将获得由操作系统分配并由池管理的读/写页面。您正在超出库分配的数据的边缘,但位于操作系统返回的页面内。

    做你正在做的事情会破坏池的结构,使用动态内存的更广泛的程序最终会崩溃。

    【讨论】:

      猜你喜欢
      • 2019-11-18
      • 2014-04-24
      • 1970-01-01
      • 2017-05-26
      • 2011-03-31
      • 2023-03-19
      • 2014-03-15
      • 2015-09-29
      相关资源
      最近更新 更多