了解何时需要 malloc():我在编译时知道 char * n 的长度,但似乎仍然需要 malloc()

Posted

技术标签:

【中文标题】了解何时需要 malloc():我在编译时知道 char * n 的长度,但似乎仍然需要 malloc()【英文标题】:Understanding when malloc() is necessary: I know the length of char * n at compile time yet still seem to need malloc() 【发布时间】:2019-11-23 12:23:33 【问题描述】:

我是学习 C 的初学者。例如,根据我所学和阅读的 here,当您不知道编译时所需的内存量时,您可以使用 malloc()。我正在编写代码,其中我知道我要声明的字符串的长度,但是如果我不使用 malloc() 分配内存并且我不明白为什么会出现错误。

我正在编写的代码是针对哈佛 CS50 问题集,其中目标是恢复已删除的 jpg,但我已将其剥离以仅显示此问题。我的代码显示了两行声明 char* 文件名的行,其中导致错误的行被注释掉了。两个选项都会编译,没有 malloc() 的选项会在运行时导致 UndefinedBehaviorSanitizer:DEADLYSIGNAL 错误。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

typedef uint8_t  BYTE;


int main(int argc, char *argv[])


    // remember filenames
    char *infile = argv[1];

    //open input file
    FILE *inptr = fopen(infile, "r");


    //buffer
    BYTE buffer[512];


    //read first 512 byte block in to buffer
    size_t r = fread(&buffer, 1, 512, inptr);

    int n = 0;
    //get name for new jpg file
    //char *filename[8]; //<<<<<<<<<<<<<<<<<<<<<this causes error
    char *filename = malloc(8);
    sprintf(filename, "%03i.jpg", n);


这是错误:

UndefinedBehaviorSanitizer:DEADLYSIGNAL
==5563==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7fb433fba0ac bp 0x000000000030 sp 0x7ffd5af8a290 T5563)
==5563==The signal is caused by a WRITE memory access.
==5563==Hint: address points to the zero page.
    #0 0x7fb433fba0ab  (/lib/x86_64-linux-gnu/libc.so.6+0x900ab)
    #1 0x7fb433fb8493  (/lib/x86_64-linux-gnu/libc.so.6+0x8e493)
    #2 0x7fb433faa37d  (/lib/x86_64-linux-gnu/libc.so.6+0x8037d)
    #3 0x7fb433f86f1f  (/lib/x86_64-linux-gnu/libc.so.6+0x5cf1f)
    #4 0x7fb433fab6d0  (/lib/x86_64-linux-gnu/libc.so.6+0x816d0)
    #5 0x7fb433f8f093  (/lib/x86_64-linux-gnu/libc.so.6+0x65093)
    #6 0x428049  (/home/ubuntu/pset3/recover/malloc+0x428049)
    #7 0x7fb433f4bb96  (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #8 0x402ad9  (/home/ubuntu/pset3/recover/malloc+0x402ad9)

UndefinedBehaviorSanitizer can not provide additional info.
==5563==ABORTING

【问题讨论】:

char *filename[8]; 创建一个包含 8 个(未初始化)指针的数组。你可能想要char filename[8]; char filename[8] 将为您创建一个长度为 8 的字符数组。 请注意,当n &gt;= 1000 时,sprintf(filename, "%03i.jpg", n); 会导致缓冲区溢出,因为'\0' 终止符需要空间 谢谢pmg 和Taegyung。 char filename[8] 运行时没有错误。该问题仅限于 50 jpg,因此 n 不会超过 50。 无论如何,请使用 sprintf,因此最糟糕的情况是文件名被截断(找不到)而不是堆栈损坏。 【参考方案1】:
char *filename[8];

好的,所以我们声明一个包含 8 个字符指针的数组,不初始化任何指针,并将一个传递给 sprintf 目标。

你的工作代码是

char *filename = malloc(8);

它清楚地声明了一个指针,并用指向堆外 8 个字节的指针对其进行初始化。因此,你想要

char filename[8];

声明一个 8 个字符的数组。

【讨论】:

以上是关于了解何时需要 malloc():我在编译时知道 char * n 的长度,但似乎仍然需要 malloc()的主要内容,如果未能解决你的问题,请参考以下文章

malloc 和 free 在 C 中是如何实现的? [复制]

C# 编译器如何知道何时切断异步方法?

何时使用或何时不使用malloc函数?学数据结构有感

何时将 malloc 用于 char 指针

malloc 何时处理从虚拟地址到物理地址的映射?

动态内存分配(c语言)