所以我有这个密码
FILE* file = fopen("file.txt", "r");
if(file == NULL)
{
printf("Failed to open file.\n");
return NULL;
}
fseek(file, 0L, SEEK_END);
long bufferSize = ftell(file);
fseek(file, 0L, SEEK_SET);
char* buffer = (char*) malloc(bufferSize);
if(buffer == NULL)
{
printf("Failed to allocate memory for buffer.\n");
return NULL;
}
fread(buffer, sizeof(char), bufferSize, file);
fclose(file);
当使用printf("%s",缓冲区)打印控制台时,这似乎非常好,但我想知道这是否应该导致缓冲区溢出,或者它是否错误,因为在末尾似乎没有空终止符字符。让我们假设file.txt中正好有4个字符。当计算bufferSize时,它将是一个长的值为4。因此,当我调用malloc(bufferSize)时,我将创建一个大小为4字节的缓冲区,不代表为空终止符字符。在我见过的例子中,人们都使用这样的代码来读取整个文本文件,但这难道不应该用文件中的字符来创建char*而不使用终止符字符吗?我应该使用malloc(bufferSize + 1)分配这个缓冲区并添加一个空终止符吗?
发布于 2020-04-02 17:44:55
--当用printf("%s",缓冲区)打印到控制台时,这似乎非常好。
看起来工作得很好是undefined behavior的完美表现。
应该使用malloc(bufferSize + 1)并添加一个空终止符字符来分配这个缓冲区吗?
如果希望使用指向可打印字符的连续字节的指针的%s
printf
格式说明符,则需要以零字节结束这些字节。或者另一种方式,%s
printf
格式说明符需要一个以零结尾的字节序列。否则,就会发生未定义的行为。
所以:
您的输入文件包含一个零字节,以便printf("%.*s", (int)bufferSize, buffer);
停止输出。
%s
知道在哪里停止。
bufferSize
比INT_MAX
低,所以很可能是)只要告诉printf
何时停止指定格式说明符的精度,比如:否则就会发生不明确的行为。
发布于 2020-04-02 17:26:22
根据您分配的缓冲区的大小和您的操作系统提供的分配单元的大小,分配结束时通常会有额外的字节。这意味着,根据以后如何使用内存,精确的缓冲区分配可能会导致失败,或者在分配结束时可能会出现空闲字节,而fread()不会覆盖这些字节。结果是什么呢?您可以使用具有意外大小的文件来测试您的程序,但一旦发布,程序可能会间歇性地失败。
快速修复?始终在缓冲区的末尾分配更多的空间--取决于程序如何解释字节(char、short、int、long、long、struct)。
请注意,如果字符串嵌套在struct中,则分配单元的大小不太可能将您保存,其中struct元素紧贴在一起。但奇数大小的字符串仍有空闲空间,这取决于编译器标志。
请注意,您的特定用法是查找文件的结尾,并将整个文件读入内存。您的操作系统很可能以16、32或64字节块的形式提供内存。这意味着您有1/16、1/32或1/64的机会意外地从您分配的缓冲区的末尾走出来。
建议:(0)总是分配额外的垫子,以缓冲跑到墙上。(1)考虑使用fstat()而不是ftell()?(2)考虑内存映射文件,而不是使用malloc/free和fread。
https://stackoverflow.com/questions/61003564
复制相似问题