【问题标题】:What are the contents of the memory just allocated by `malloc()`?`malloc()` 刚刚分配的内存的内容是什么?
【发布时间】:2018-10-02 11:04:33
【问题描述】:

在使用malloc() 分配内存空间之后,我很好奇指针到底是什么?手册页告诉我calloc() 将分配的内存空间初始化为零。

malloc() 函数分配 size 字节并返回一个指向已分配内存的指针。 内存未初始化。如果 size 为 0,则 malloc() 返回 NULL,或稍后可以成功传递给 free() 的唯一指针值。

calloc() 函数为每个大小字节的 nmemb 元素数组分配内存 并返回一个指向分配内存的指针。 内存设置为零。如果 nmemb 或 size 为 0,然后 calloc() 返回 NULL 或稍后可以返回的唯一指针值 成功传递给free()。

我为自己创建了一个非常简短的 C 示例程序,用于 C(哈哈):

int main() {
    char *dynamic_chars;
    unsigned amount;
    printf("how much bytes you want to allocate?\n");
    scanf("%d", &amount);

    dynamic_chars = (char*)malloc(amount*sizeof(char));
    printf("allocated:\n%s\n", dynamic_chars);

    free(dynamic_chars);
    return 0;

}

但是,当执行此代码时,它什么也不输出。如果我初始化我自己的内存,例如使用循环使用0xFFFF 初始化每个字节,那么程序会向我显示我所期望的。内存空间实际上是存在的,因为我不会收到声称我正在尝试访问未初始化的变量的错误消息。

由于内存空间通常不会被删除但被标记为可重写我想知道通过执行我的程序是否应该能够看到以前随机使用的内存字节?但是我什么都看不到,所以我真的很困惑malloc() 究竟是如何工作的。

编辑1

关于malloc() 或者一般的内存使用情况的另一件事是,我的程序很有趣: 如果我使用calloc() 分配内存,我可以跟踪程序的实际内存使用情况,例如监控它。例如,如果我告诉我的程序,为每个 calloc() 分配 1.000.000.000 字节的内存,我将在我的系统监视器中看到以下内容:

正如您可能想象的那样,当使用malloc() 时,我什么也看不到。我理解,仅仅通过分配内存,我当时并没有真正使用它,但我仍然对为什么我的操作系统(unix 衍生版)无法识别它被使用感到困惑。由于malloc() 就像calloc() 一样将物理地址返回到我没有得到的内存位置,所以这个内存区域似乎实际上并没有被操作系统保留。否则我可以在系统监视器中看到它,对吗? 如果我宁愿将此作为新问题发布,请告诉我。但我认为,由于问题仍然是关于 malloc() 的工作原理,它适合这里。

【问题讨论】:

  • 当你像这样测试它时,往往会意外地为 0。当您在实际程序中执行此操作时,这不会很好地重复,并且先前释放的堆块正在被回收。您不得做出任何假设。
  • 如果内存以零开头,printf 将其视为""(零是终止符)如果要查看实际值,则应使用另一种方法。
  • scanf("%d", &amount);scanf("%u", &amount);
  • 我认为您问题的“编辑 1”部分的答案可能是特定于实现/操作系统的,但是由于 calloc 需要连续内存并且 malloc 可以使用片段,因此 malloc 可能可以使用已分配的内存对于您的程序,而 calloc 需要保留“新”内存。或者 malloc 可以将实际预留推迟到内存实际使用的时候。
  • 注意:为什么使用类型unsigned amount;?查看malloc()接受的参数类型。

标签: c initialization malloc dynamic-memory-allocation


【解决方案1】:

不,malloc() 返回未初始化的内存,其内容是不确定的。因此,尝试使用该值调用undefined behavior

引用 C11,附件 §J.2,未定义的行为

使用malloc函数分配的对象的值

在这种情况下,%s 需要一个以 null 结尾的 char 数组。但是dynamic_chars的内容是不确定的,所以很可能根本没有空终止符,这会导致内存越界访问,进而调用UB。

引用C11,第 7.22.3.5 章,malloc 函数(强调我的):

malloc 函数为大小由size 指定的对象分配空间,并且 其值不确定。

也就是说,please see this discussion on why not to cast the return value of malloc() and family in C.

【讨论】:

  • 不要与初始化分配内存的realloc混淆!
  • @gsamaras 我认为这个问题是关于malloc() 的,不是吗? :)
  • Sourav 当然,但在此之前只是有人说一个新人会与这两个混淆。也许我应该删除我的 cmets?
  • @RadLexus 将不确定的值读取为char 可能会产生陷阱表示。但即使在没有陷阱表示的系统上,也没有定义将不确定的值传递给库函数,例如 printfSee here 进一步讨论
  • @RadLexus 只是为了添加更多上下文,C11 特别提到这种情况为 UB。请注意我的答案中的编辑。
【解决方案2】:

malloc 为您分配内存并设置指向它的指针。它不会以任何方式初始化内存,因此分配的内存区域可以包含任何内容。由于它不包含字符串,因此您无法通过打印字符串来读取它的内容。相反,您可以逐字节打印它,如下所示:

for(int i=0;i<amount*sizeof(char);i++)
{
    printf("%02x", (unsigned)dynamic_chars[i]);
}

【讨论】:

  • 这会将不确定的值传递给库函数。 C 标准对此并不清楚,但 DR451 Proposed Committee Resolution 建议这是未定义的行为
  • @M.M 我不明白为什么这段代码会有问题。 dynamic_chars 中的值肯定是欠终止的,但它们仍然只是值,我不明白为什么打印这些值的十六进制表示会是个问题。
  • @M.M 关于 %x 的好点,我做了一些小的改进来修复它。但是我很难理解为什么 printf 的行为是不确定的,内容肯定是(正如迈克尔沃尔兹所说),但我不明白为什么不能打印出内存的内容。
  • 未初始化的内存在标准 C 中没有任何内容。听起来您在想象它包含一些值
  • @M.M 好的,从规范的角度来看,我同意你的看法。然而,在实践中,未初始化的内存不包含任何值,它需要在初始化之前是不存在的内存。你见过这样的实现吗?我没有,我什至无法想象。
【解决方案3】:

当你得到它时,C 语言没有定义内存块包含的内容。在实践中,它很可能只包含之前物理内存中的内容。

如果内存之前被您的程序使用并被释放,那么您很可能会得到之前的内容。如果它是操作系统新请求的内存,您将获得操作系统放入其中的内容。大多数操作系统会返回专门设置为“零”字节的内存,因为如果内存中仍然包含以前来自其他程序的内容,这将是一个安全问题。

任何标准都不能保证这些,这正是大多数系统在实践中所做的。

【讨论】:

    猜你喜欢
    • 2017-03-10
    • 2012-05-30
    • 1970-01-01
    • 2017-10-30
    • 2015-06-05
    相关资源
    最近更新 更多