malloc看起来不适用于我的程序

时间:2015-10-15 18:31:44

标签: c malloc calloc

我有一个打印文件整个内容的函数,函数似乎工作正常,但是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)

3 个答案:

答案 0 :(得分:2)

您将读取的文件内容打印到缓冲区中,但没有任何东西可以确保缓冲区包含NUL字符,因此valgrind会抱怨因为printf会将您的数据解析为NUL(jump or move depends on uninitialised value(s))。使用calloc告诉valgrind你更谨慎......

答案 1 :(得分:1)

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

然而,您的特定错误仅与外围相关。您执行通过fread()初始化大部分缓冲区,但是您分配的文件比文件长一个多,而fread()不会在最后一个字节中存储任何内容。看起来你可能想要添加一个'\0'终结符,但是忘了。它是valgrind抱怨的最后一个字节。

在这种情况下,由calloc()执行的内存清除通常没有任何意义,因为您将覆盖缓冲区中的所有字节而不是一个。但 也会初始化最后一个字节,当你无法以其他方式初始化它时,可以省去几种麻烦。

答案 2 :(得分:1)

您的字符串必须以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] = '\0';               /* <--- null termination */

calloc用NUL字符填充整个缓冲区,但这是浪费周期。你只需要一个。