malloc 看起来在我的程序中不起作用

malloc doesn't look to work in my program

我有一个打印文件全部内容的函数,该函数似乎工作正常,但 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 Exists\n", 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))。使用 calloc 告诉 valgrind 你更谨慎了...

通过malloc()获得的内存未初始化。那是故意的。解决方法是改用 calloc() 或在读取之前初始化通过 malloc() 获得的内存。在某些情况下,您只能初始化其中的一部分,而且通常您可以使用比全零更好的初始值。

但是,您的特定错误仅与此相关。您 do 通过 fread() 初始化大部分缓冲区,但是您分配的字节比文件长多了一个字节,并且 fread() 不会在最后一个字节中存储任何内容字节。看起来您可能打算添加一个 '[=15=]' 终止符,但忘记了。这是 valgrind 抱怨的最后一个字节。

在这种情况下,calloc() 执行的内存清除大部分没有用,因为您将覆盖缓冲区中的所有字节,只有一个字节除外。但它 确实 也初始化了最后一个字节,当您无法以任何其他方式初始化它时,它会为您省去多种麻烦。

您的字符串必须以 NUL 结尾。没有它,程序有未定义的行为,valgrind 正确地报告了这一点。

以 NUL 终止字符串的最简单方法是:

size = fread (buffer,1,length,file); /* no need to specify useless extra char */
                                     /* it will never be read */
...                                  /* check for errors here */
buffer[length] = '[=10=]';               /* <--- null termination */

calloc用NUL字符填充整个buffer,但是很浪费循环。你只需要一个。