c - 我真的需要malloc吗?

标签 c malloc mingw

我知道malloc用于动态分配内存。在我的代码中,我有时调用以下函数:

int memory_get_log(unsigned char day, unsigned char date, unsigned char month){

    char fileName[11];
    unsigned long readItems, itemsToRead;
    F_FILE *file;

    sprintf(fileName, "%s_%u%u%u%s", "LOG", day, date, month, ".bin");

    file = f_open(fileName , "r");

    itemsToRead = f_filelength( fileName );

    //unsigned char *fileData = (unsigned char *) malloc(itemsToRead);
    unsigned char fileData[itemsToRead]; //here I am not using malloc

    readItems = f_read(fileData, 1, itemsToRead, file);

    transmit_data(fileData, itemsToRead);

    f_close(file);

    return 0;
}

如您所见,每次从文件中读取的项目数可能不同。线路
unsigned char fileData[itemsToRead];用于读取这些可变大小的文件。我可以看到我正在以某种方式动态分配内存。这个功能工作正常。我真的需要在这里使用malloc吗?
我声明这个数组的方式有什么问题吗?

最佳答案

我真的需要在这里使用malloc吗?我声明这个数组的方式有什么问题吗?
这要看情况。vla:s作为必需组件从c11中删除,所以严格地说,您使用的是编译器扩展,因此降低了可移植性。在将来,vla:s可能(几率可能非常低)从编译器中删除。也许您还想在不支持vla:s的情况下在编译器上重新编译代码。这方面的风险分析取决于您。
另一个问题是如果分配失败。如果你使用malloc,你有机会从中恢复过来,但是如果你只想做这样的事情:

unsigned char *fileData = malloc(itemsToRead);
if(!fileData)
    exit(EXIT_FAILURE);

也就是说,在失败时退出,而不是试图恢复,那并不重要。至少从纯恢复的角度来看不是这样。
但是,尽管c标准没有强制要求vla:s最终出现在堆栈或堆上,但据我所知,将它们放在堆栈上是很常见的。这意味着,由于可用内存不足而导致分配失败的风险要高得多。在Linux上,堆栈通常为8MB,在Windows上为1MB。在几乎所有情况下,可用堆都要高得多。声明char arr[n]char *arr = alloca(n)基本相同,只是sizeof运算符的工作方式不同。
vla:s不能替代malloc。它们是alloca的替代品。如果不想将amalloc更改为aalloca,则也不应更改为vla。
有很多事情要考虑,但我会避免使用vla:s。如果你问我,使用它们最大的风险是,因为它们很容易使用,人们对它们变得粗心大意。对于那些我认为合适的情况,我会使用alloca来代替,因为这样我就不会隐藏危险。
小结
vla:s不是c11和更高版本所必需的,所以严格地说,您依赖于编译器扩展。
vla:s是alloca的语法糖,而不是malloc。所以不要用它们代替malloc。除了sizeof如何在vla上工作之外,它们完全没有任何好处,除了一个稍微简单的声明。
vla:s(通常)存储在堆栈上,而分配完成后,malloc(通常)存储在堆上,因此大的分配失败的风险要高得多。
这个功能工作正常。
不,没有。它有未定义的行为。正如jonathan leffler在评论中指出的,数组fileName太短。它至少需要12个字节才能包含\0-终止符。您可以通过更改为:
snprintf(fileName, 
         sizeof(fileName), 
         "%s_%u%u%u%s", 
         "LOG", day, date, month, ".bin");

在这种情况下,过小数组的问题将通过创建扩展名为.bi的文件而不是.bin来显现,这比当前的未定义行为更好。
您的代码中也没有错误检查。我会这样重写。对于那些认为goto不好的人来说,它通常是坏的,但是错误处理在有经验的c程序员中既实用又被普遍接受。另一个常见的用法是中断嵌套循环,但这在这里不适用。
int memory_get_log(unsigned char day, unsigned char date, unsigned char month){

    char fileName[12];
    unsigned long readItems, itemsToRead;
    int ret = 0;

    F_FILE *file;

    snprintf(fileName, 
             sizeof(fileName), 
             "%s_%u%u%u%s", "LOG", 
             day, date, month, ".bin");

    file = f_open(fileName , "r");
    if(!file) { 
        ret = 1; 
        goto END;
    }

    itemsToRead = f_filelength( fileName );

    unsigned char *fileData = malloc(itemsToRead);
    if(!fileData) { 
        ret=2;
        goto CLOSE_FILE;
    }

    readItems = f_read(fileData, 1, itemsToRead, file);
    // Maybe not necessary. I don't know. It's up to you.
    if(readItems != itemsToRead) {  
        ret=3;
        goto FREE;
    }

    // Assuming transmit_data have some kind of error check
    if(!transmit_data(fileData, itemsToRead)) {  
        ret=4;
    }

FREE:
    free(fileData);
CLOSE_FILE:
    f_close(file);
END:
    return ret;
}

如果一个函数只返回0,那么返回任何内容都是没有意义的。声明为无效。现在我使用返回值使调用方能够检测错误和错误类型。

关于c - 我真的需要malloc吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58163105/

相关文章:

c - C中动态分配的字符串数组

c++ - Code::Blocks 中的 OpenCV:应用程序无法正确启动 (0xc00000be)

c - C89 中可移植的用户定义的字符类通过查找表划分,你会这样做吗?

c - 将多维数组传递给 C 中的函数

c - 系统小程序 : Assertion failed - How can I solve?

c++ - 堆腐败问题

c - 将数据存储在数组中

c - 从 NetBeans 启动 C 应用程序时重定向标准输入

c++ - Mingw 和 C++ vector

python-2.7 - SIP Makefile 失败(gnuwin 和 mingw)