我知道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/