大小为8的读/写无效

时间:2013-12-05 21:12:51

标签: c malloc valgrind

在我的学校项目工作期间,在Unix学校服务器上编译项目后,我一直收到Valgrind的错误信息。

==2951== Memcheck, a memory error detector
==2951== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==2951== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==2951== Command: ./Euler
==2951==
==2951== Invalid read of size 8
==2951==    at 0x400B65: GInit (Euler.c:64)
==2951==    by 0x400DD1: main (Euler.c:118)
==2951==  Address 0x1786100 is 0 bytes after a block of size 48 alloc'd
==2951==    at 0x100688B: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so)
==2951==    by 0x400A80: GInit (Euler.c:43)
==2951==    by 0x400DD1: main (Euler.c:118)
==2951==
==2951== Invalid write of size 4
==2951==    at 0x400B6B: GInit (Euler.c:64)
==2951==    by 0x400DD1: main (Euler.c:118)
==2951==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==2951==
==2951==
==2951== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==2951==  Access not within mapped region at address 0x0
==2951==    at 0x400B6B: GInit (Euler.c:64)
==2951==    by 0x400DD1: main (Euler.c:118)
==2951==  If you believe this happened as a result of a stack
==2951==  overflow in your program's main thread (unlikely but
==2951==  possible), you can try to increase the size of the
==2951==  main thread stack using the --main-stacksize= flag.
==2951==  The main thread stack size used in this run was 16777216.
==2951==
==2951== HEAP SUMMARY:
==2951==     in use at exit: 32,981 bytes in 16 blocks
==2951==   total heap usage: 16 allocs, 0 frees, 32,981 bytes allocated
==2951==
==2951== LEAK SUMMARY:
==2951==    definitely lost: 0 bytes in 0 blocks
==2951==    indirectly lost: 0 bytes in 0 blocks
==2951==      possibly lost: 0 bytes in 0 blocks
==2951==    still reachable: 32,981 bytes in 16 blocks
==2951==         suppressed: 0 bytes in 0 blocks
==2951== Reachable blocks (those to which a pointer was found) are not shown.
==2951== To see them, rerun with: --leak-check=full --show-reachable=yes
==2951==
==2951== For counts of detected and suppressed errors, rerun with: -v
==2951== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault: 11

使用malloc时,我似乎错误地分配了内存。我知道没有释放内存,因为我还没有实现删除功能。 函数GInit应从文件Graph1.txt读取格式化数据,并创建由节点组成的图形。文件包含节点数和关联矩阵。

这是我的代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAXFILENAME 20

typedef struct tNode{
    int Deg;
    int Val;    
    int* Neigh; 
} *tNodePtr;

typedef struct tGraph{
    int Num;    
    tNodePtr* Nodes;    
} *tGraphPtr;


void GInit(tGraphPtr G, const char *FNum)
{
    char FileName[MAXFILENAME];
    char *FileNamePrefix = "Graph";
    char *FileNamePostfix = ".txt";
    FILE *FilePtr;
    int FileBrowser;
    int i, j, k, countNeigh;
    char *line;
    char c;

    strcpy(FileName, FileNamePrefix);
    strcat(FileName, FNum);
    strcat(FileName, FileNamePostfix);

    FilePtr = fopen(FileName, "r");

    if(!FilePtr)
        printf("Can't open file \"%s\"\n", FileName);
    else
    {
        fscanf(FilePtr, "%d", &FileBrowser);

        G->Num = FileBrowser;
        G->Nodes = (tNodePtr*) malloc(sizeof(tNodePtr) * G->Num);

        for(i = 0; i < G->Num; i++)
            G->Nodes[i] = (tNodePtr) malloc(sizeof(struct tNode));

        line = (char*) malloc(sizeof(char) * (2*G->Num + 1));   

        i = 0;
        fscanf(FilePtr, "%c", &c);
        fgets(line, 2*G->Num + 1, FilePtr); 
        while(!feof(FilePtr))
        {
            countNeigh = 0;
            j = 0;
            while(line[j] != '\0')
            {
                if(line[j] == '1')
                    countNeigh++;
                j++;
            }

            G->Nodes[i]->Deg = countNeigh;
            G->Nodes[i]->Val = i;
            G->Nodes[i]->Neigh = (int*) malloc(sizeof(int) * countNeigh);

            j = 0;
            k = 0;
            while(line[j] != '\0')
            {
                if(line[j] == '1')
                {
                    G->Nodes[i]->Neigh[k] = j/2;
                    k++;
                }
                j++;
            }

            i++;    
            fgets(line, 2*G->Num + 1, FilePtr); 
        }

        free(line);
    }

    fclose(FilePtr);
}

void GPrint(const tGraphPtr G)
{
    int j, k;

    printf("Graph demonstration:\n");
    for(j = 0; j < G->Num; j++)
    {
        printf("I'm Node: %d , my degree is: %d and my neighbours are:\t", G->Nodes[j]->Val, G->Nodes[j]->Deg);
        for(k = 0; k < G->Nodes[j]->Deg; k++)
            printf("%3d", G->Nodes[j]->Neigh[k]);
        printf("\n");
    }
}

void GDelete(tGraphPtr G)
{

}

int main(int argc, char *argv[])
{

    tGraphPtr TmpGraph;
    char *FNum;
    FNum = "1";

    TmpGraph = (tGraphPtr) malloc(sizeof(struct tGraph));

    GInit(TmpGraph, FNum);

    GPrint(TmpGraph);


    return(0);  
}

以下是我正在阅读的文件Graph1.txt

6
0 1 0 1 0 0
1 0 1 0 1 1
0 1 0 1 1 1
1 0 1 0 0 0
0 1 1 0 0 0
0 1 1 0 0 0

如何解决此错误的任何建议表示赞赏。 BTW Microsoft VS2013成功构建此代码并运行,没有错误。 谢谢。 约翰

2 个答案:

答案 0 :(得分:2)

您应该进行更多错误检查。以下是一些地方:

fscanf(FilePtr, "%d", &FileBrowser)

您假设fscanf已成功从文件中检索int。您应该通过验证从fscanf返回的值是1来检查这一点。如果它为0,则您在FileBrowser中有一个垃圾值。

这是另一个问题:

G->Nodes = (tNodePtr*) malloc(sizeof(tNodePtr) * G->Num);

首先,没有必要对malloc的返回进行类型转换,因此请删除(tNodePtr*)。其次,你再次假设malloc成功了。您应该通过比较G->NodesNULL的地址来确保确实这样做。 NULL表示失败。

答案 1 :(得分:0)

只是为了扩展Bit Fiddling Code Monkey的响应,Valgrind抱怨读取错误和第64行写错,这是:

G->Nodes[i]->Deg = countNeigh;

意味着您要超越节点的大小(错误读取Nodes[i])并写入未分配的内存地址(Deg中的错误写入)。

这可能是因为fscanf失败或因为该文件包含最初在FileBrowser中声明的更多行。例如,文件末尾的额外空行会导致无效的读/写。