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

标签 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

如有任何修复此错误的建议,我们将不胜感激。 顺便说一句,Microsoft VS2013 成功构建了这段代码并且运行没有错误。 谢谢。 约翰

最佳答案

你应该做更多的错误检查。以下是一些地方:

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

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

还有一个问题:

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

首先,不需要对malloc 的返回进行类型转换,所以删除(tNodePtr*)。其次,您再次假设 malloc 成功。您应该通过将 G->Nodes 的地址与 NULL 进行比较来确保确实如此。 NULL 表示失败。

关于c - 大小为 8 的无效读/写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20410825/

相关文章:

c - 如何设置寄存器中的位?

c++ - 如何知道应用程序中可用的虚拟内存

c - 如何更改函数中参数的值

c - 为什么我的程序有内存泄漏检查错误?

c++ - valgrind 检测到内存泄漏,但找不到我忘记释放的行

预处理器后的 C 代码

c++ - 轻量级 Windows 应用程序的最佳开源示例是什么?

c - 当父亲在等待信号量时避免僵尸

c - C 中的 malloc() 函数

posix - 对于有缺陷、内存泄漏的 POSIX API,我们该怎么办?