c-大小为8的读/写无效



在我的学校项目中,在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] != '')
            {
                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] != '')
            {
                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成功构建了此代码,并且运行时没有出现任何错误。非常感谢。John

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

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

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

这里还有一个问题:

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

首先,不需要对malloc的返回进行类型转换,因此删除(tNodePtr*)。其次,您再次假设malloc成功了。您应该通过比较G->NodesNULL的地址来确保它确实做到了。CCD_ 13将指示故障。

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

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

这意味着您正在超额支付Nodes的大小(Nodes[i]的错误读取)和在未分配的内存地址上写入(Deg的错误写入)。

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

最新更新