我有一个函数打印文件的整个内容,该函数似乎工作得很好,但valgring抱怨条件跳转或移动取决于未初始化的值和未初始化的值是由堆分配:
==7876== Memcheck, a memory error detector ==7876== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==7876== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==7876== Command: ./program ==7876== ==7876== Conditional jump or move depends on uninitialised value(s) ==7876== at 0x4E864B2: vfprintf (vfprintf.c:1642) ==7876== by 0x4E8CC38: printf (printf.c:33) ==7876== by 0x40074C: main (program.c:45) ==7876== Uninitialised value was created by a heap allocation ==7876== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==7876== by 0x4008A7: printFile (program.c:23) ==7876== by 0x40073A: main (program.c:43) ==7876== The world is not enought and michi is the only one who's not agree. ==7876== ==7876== HEAP SUMMARY: ==7876== in use at exit: 0 bytes in 0 blocks ==7876== total heap usage: 2 allocs, 2 frees, 621 bytes allocated ==7876== ==7876== All heap blocks were freed -- no leaks are possible ==7876== ==7876== For counts of detected and suppressed errors, rerun with: -v ==7876== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
程序如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *printFile(char *fileName){
size_t length=0,size=0;
char *buffer;
FILE *file;
file = fopen (fileName , "r" );
if (file==NULL){
printf("n");
printf("tThe file %s does not Existsn", fileName);
exit(1);
}
fseek (file , 0 , SEEK_END);
length = (size_t)ftell (file);
fseek (file , 0 , SEEK_SET);
buffer = malloc(length+1);
if (!buffer){
fputs ("Memory error",stderr);
exit (2);
}
size = fread (buffer,1,length+1,file);
if (size != length){
fputs ("Reading error",stderr);
exit(3);
}
fclose (file);
return buffer;
}
int main (void) {
char *fileName = "test.txt";
char *fileContent = printFile(fileName);
printf("%s",fileContent);
free(fileContent);
return 0;
}
一个快速的修复方法是使用calloc而不是malloc,因为它将返回的字节归零所以我替换了:
buffer = malloc(length+1);
:
buffer = calloc(length,sizeof(char*));
和valgrind不抱怨:
==7897== Memcheck, a memory error detector ==7897== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==7897== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==7897== Command: ./program ==7897== The world is not enought and michi is the only one who's not agree. ==7897== ==7897== HEAP SUMMARY: ==7897== in use at exit: 0 bytes in 0 blocks ==7897== total heap usage: 2 allocs, 2 frees, 1,096 bytes allocated ==7897== ==7897== All heap blocks were freed -- no leaks are possible ==7897== ==7897== For counts of detected and suppressed errors, rerun with: -v ==7897== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
我的问题是,为什么malloc产生这个错误,以及如何避免calloc。我这里有一些编码问题,还是只是malloc?..编辑:如果我改变:
size = fread (buffer,1,length+1,file);
:
size = fread (buffer,1,length,file);
我:
==7985== Memcheck, a memory error detector ==7985== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==7985== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==7985== Command: ./program ==7985== ==7985== Invalid read of size 1 ==7985== at 0x4E864B2: vfprintf (vfprintf.c:1642) ==7985== by 0x4E8CC38: printf (printf.c:33) ==7985== by 0x40074C: main (program.c:44) ==7985== Address 0x52022f4 is 0 bytes after a block of size 68 alloc'd ==7985== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==7985== by 0x4008A6: printFile (program.c:22) ==7985== by 0x40073A: main (program.c:42) ==7985== The world is not enought and michi is the only one who's not agree. ==7985== ==7985== HEAP SUMMARY: ==7985== in use at exit: 0 bytes in 0 blocks ==7985== total heap usage: 2 allocs, 2 frees, 620 bytes allocated ==7985== ==7985== All heap blocks were freed -- no leaks are possible ==7985== ==7985== For counts of detected and suppressed errors, rerun with: -v ==7985== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
您打印读取到缓冲区的文件内容,但没有什么可以确保缓冲区包含NUL字符,因此valgrind抱怨,因为printf解析您的数据直到NUL (jump or move depends on uninitialised value(s)
)。
字符串必须以空结束。如果没有它,程序会有未定义的行为,valgrind会正确地报告。
以空结束字符串的最简单方法是:
size = fread (buffer,1,length,file); /* no need to specify useless extra char */
/* it will never be read */
... /* check for errors here */
buffer[length] = ' '; /* <--- null termination */
calloc
用NUL字符填充整个缓冲区,但这是浪费循环。你只需要一个。
通过malloc()
获得的内存未初始化。这是故意的。解决方法是使用calloc()
,或者在读取之前初始化通过malloc()
获得的内存。在某些情况下,你只能初始化它的一部分,通常你有更好的初始值比所有的零可用。
fread()
初始化了大部分缓冲区,但是你分配了比文件长度多一个字节,并且fread()
在最后一个字节中不存储任何东西。看起来也许你打算添加一个' '
终止符,但忘记了。这是valgrind抱怨的最后一个字节。
在这种情况下,calloc()
执行的内存清除基本上没有任何作用,因为您将覆盖缓冲区中的所有字节,只保留一个字节。但是它也对最后一个字节进行了初始化,当您无法以其他方式初始化它时,这将为您省去许多麻烦。