Valgrind错误,大小为4的无效读/写-调试后找不到问题-C

问题描述 投票:0回答:2

这是我的代码,该代码使用c中的数组实现Queue数据结构。请注意,gMyQueue是我之前定义的Queue类型的全局变量。在此程序上运行Valgrind时-会大声喊出大小为4的无效读写错误。似乎没有什么错。

typedef struct Queue
{
    size_t numOfElems;
    size_t queueCapacity;
    int *data;
} Queue;

Queue gMyQueue;

void printQueue()
{
    for(size_t i = 0; i < gMyQueue.numOfElems; ++i)
    {
      printf("%d, ", gMyQueue.data[i]);
    }

    printf("\n");

    printf("numOfElems: %lu, queueCapacity: %lu\n",
           gMyQueue.numOfElems, gMyQueue.queueCapacity);
}

void cleanQueue()
{
    if (gMyQueue.data != NULL)
    {
        free(gMyQueue.data);
    }
}

void init()
{
    gMyQueue.data = (int *) malloc(sizeof(int));
    gMyQueue.queueCapacity = 1;
    gMyQueue.numOfElems = 0;
}


void enqueue(int n) {
    if (gMyQueue.numOfElems == 0 && gMyQueue.data == NULL) {
        init();
        gMyQueue.data[gMyQueue.numOfElems] = n;
        gMyQueue.numOfElems++;
    }
    else {
        gMyQueue.numOfElems++;
        if (gMyQueue.numOfElems == gMyQueue.queueCapacity) {
            gMyQueue.queueCapacity *= 2;
            gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity);
        }

        gMyQueue.data[gMyQueue.numOfElems - 1] = n;
    }
}

int dequeue(void) {
    int dequeue = 0;
    if (gMyQueue.numOfElems == 0) {
        return dequeue;;
    }
    else {
        dequeue = *(gMyQueue.data);
        for (int i = 0; i < gMyQueue.numOfElems - 1; i++)
        {
            gMyQueue.data[i] = gMyQueue.data[i + 1];
        }
        gMyQueue.numOfElems--;
    }
    return dequeue;
}
int main()
{
    init();
    enqueue(1);
    enqueue(2);
    dequeue();
    printQueue();
    cleanQueue();
    return 0;
}

我已经调试了一段时间,似乎一切正常,也可以使用指针和索引...但是运行valgrind会产生以下结果:

==12905== Invalid write of size 4
==12905==    at 0x108CC9: enqueue (main.c:200)
==12905==    by 0x109071: main (main.c:309)
==12905==  Address 0x522d090 is 0 bytes inside a block of size 2 alloc'd
==12905==    at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12905==    by 0x108CA5: enqueue (main.c:197)
==12905==    by 0x109071: main (main.c:309)
==12905== 
==12905== Invalid write of size 4
==12905==    at 0x108CC9: enqueue (main.c:200)
==12905==    by 0x10907B: main (main.c:310)
==12905==  Address 0x522d0e4 is 0 bytes after a block of size 4 alloc'd
==12905==    at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12905==    by 0x108CA5: enqueue (main.c:197)
==12905==    by 0x10907B: main (main.c:310)
==12905== 
==12905== Invalid read of size 4
==12905==    at 0x108D2B: dequeue (main.c:213)
==12905==    by 0x109080: main (main.c:311)
==12905==  Address 0x522d0e4 is 0 bytes after a block of size 4 alloc'd
==12905==    at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12905==    by 0x108CA5: enqueue (main.c:197)
==12905==    by 0x10907B: main (main.c:310)

有人知道出什么事了吗?谢谢。

c arrays pointers debugging valgrind
2个回答
0
投票

至少功能enqueue错误。

else语句不得以numOfElems的增量开头>

//...
else {
    gMyQueue.numOfElems++;
    //…

因为此数据成员在if语句中的函数的第一次调用中已经递增]

if (gMyQueue.numOfElems == 0 && gMyQueue.data == NULL) {
    init();
    gMyQueue.data[gMyQueue.numOfElems] = n;
    gMyQueue.numOfElems++;
}

此函数realloc的调用

    gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity);

不正确。第二个参数应指定新分配的内存的大小。因此,通话至少应该看起来像

    gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity * sizeof( int ) );

并且您应该使用中间指针,因为该函数可以返回NULL。在这种情况下,先前分配的内存的地址将丢失。

功能看起来像

void enqueue( int n ) 
{
    if ( gMyQueue.data == NULL ) 
    {
        init();
        gMyQueue.data[gMyQueue.numOfElems++] = n;
    }
    else 
    {
        if ( gMyQueue.numOfElems == gMyQueue.queueCapacity ) 
        {
            gMyQueue.queueCapacity *= 2;
            int *tmp = realloc( gMyQueue.data, gMyQueue.queueCapacity ( sizeof( int ) );
            if ( tmp != NULL )
            {
                gMyQueue.data = tmp; 
                gMyQueue.data[gMyQueue.numOfElems++] = n;
            }
        }
    }
}

是的,我在评论中提到的是问题;您没有在realloc() call中分配足够的内存:

void enqueue(int n) {
    if (gMyQueue.numOfElems == 0 && gMyQueue.data == NULL) {
        init();
        gMyQueue.data[gMyQueue.numOfElems] = n;
        gMyQueue.numOfElems++;
    }
    else {
        gMyQueue.numOfElems++;
        if (gMyQueue.numOfElems == gMyQueue.queueCapacity) {
            gMyQueue.queueCapacity *= 2;
            gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity); // HERE
        }

        gMyQueue.data[gMyQueue.numOfElems - 1] = n;
    }
}

您的代码正确扩展了容量-items

的最大数量-但在realloc()期间它不会将items转换为bytes”。您可以在这里这样做:
gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity * sizeof(int));
                                                                    ^^^^^^^^^^^^^^

现在,Valgrind似乎对此很满意。

EDIT

:我建议您实际上从变量而不是类型的名称中得出大小。使用sizeof(* gMyQueue.data)而不是sizeof(int)可以从变量所指向的对象中提取类型,如果更新代码,则只需更改一个即可。

例如,如果您希望datalong而不是int的数组,那么您当然必须更新结构以反映正确的类型,但是不必更新sizeof 。建议在原始文件malloc()中也这样做。

这不是必需的,但这是一个很好的习惯,可以避免并避免日后出现问题。


0
投票

是的,我在评论中提到的是问题;您没有在realloc() call中分配足够的内存:

© www.soinside.com 2019 - 2024. All rights reserved.