在valgrind中,操纵指针会导致 "无效的realloc()"。

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

我有一个项目,涉及读取不确定数量的字符串,并根据一些相关的元数据将它们追加到不同的char**中。 我有一些代码可以重新分配()一个char**,使其随着数据的增加而动态增长,而且它需要一个指向其中一个char**的指针作为输入,因此它可以具有一定的通用性。 但是,我在指针上搞出了一些问题,导致realloc()过早地释放()了char**,导致错误。 我找不到我做错了什么。

这里有一个脱胎换骨的例子,说明了我想做的事情。 对元数据的引用被剥离出来,取而代之的是代码在一个char**和另一个char**之间交替使用,这在完整的项目中可能会发生。 这个示例还省略了malloc()上的一些错误检查和一些适当的清理(即free()),这些在完整项目中都会出现。

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

void print_elems(char **array, int length) {
    for (int i = 0; i < length; i++) {
        printf("%s", array[i]);
    }
}

void main() {

    char **array = (char**) malloc(sizeof(char*));
    int length = 1;
    int index = 0;
    char **array2 = (char**) malloc(sizeof(char*));
    int length2 = 1;
    int index2 = 0;


    char **pointarray = array2;
    int* pointlen = &length2;
    int* pointidx = &index2;

    char newelem[10];
    while(1) {
        printf("Enter a string: ");
        fgets(newelem, 10, stdin);

        pointarray = (pointarray == array2 ? array : array2);
        pointlen = (pointlen == &length2 ? &length : &length2);
        pointidx = (pointidx == &index2 ? &index : &index2);

        if (*pointlen == *pointidx) {
            printf("Resizing array...\n");
            void* newarray = realloc(pointarray, sizeof(char*)*(*pointlen+1));
            if (pointarray == NULL) {
                perror("Error allocating memory.\n");
                exit(1);
            } else {
                pointarray = (char**) newarray;
            }
            (*pointlen)++;
        }

        pointarray[*pointidx] = strdup(newelem);
        (*pointidx)++;

        print_elems(pointarray, *pointlen);
    }

}

通常在循环运行不超过10次之后,程序就会崩溃。 Valgrind给出了这样的输出。

==11278== Invalid free() / delete / delete[] / realloc()
==11278==    at 0x483AD19: realloc (vg_replace_malloc.c:836)
==11278==    by 0x4012EA: main (test.c:38)
==11278==  Address 0x4a23090 is 0 bytes inside a block of size 8 free'd
==11278==    at 0x483AD19: realloc (vg_replace_malloc.c:836)
==11278==    by 0x4012EA: main (test.c:38)
==11278==  Block was alloc'd at
==11278==    at 0x483880B: malloc (vg_replace_malloc.c:309)
==11278==    by 0x401215: main (test.c:17)
==11278== 
==11278== Invalid write of size 8
==11278==    at 0x401345: main (test.c:48)
==11278==  Address 0x10 is not stack'd, malloc'd or (recently) free'd

如果我不做这些指针切换,程序运行得很好,但项目会复杂得多,我必须想象有一种方法可以做我想做的事。

谁能告诉我,我到底是哪里搞砸了,让realloc()走火入魔?

c pointers valgrind realloc
1个回答
1
投票

在你调用 realloc() 您将结果分配给 pointarray但这并没有改变 arrayarray2. 然后在未来的迭代中,你将其中一个分配给 pointarray但它们不再指向有效的存储。

你需要一个额外的间接层次,类似于你间接获取长度和索引变量的方式。

另外,在你调用 realloc() 你在检查 pointarray但你应该检查 newarray.

void main() {

    char **array = malloc(sizeof(char*));
    int length = 1;
    int index = 0;
    char **array2 = malloc(sizeof(char*));
    int length2 = 1;
    int index2 = 0;

    char ***pointarray = array2;
    int* pointlen = &length2;
    int* pointidx = &index2;

    char newelem[10];
    while(1) {
        printf("Enter a string: ");
        fgets(newelem, 10, stdin);

        pointarray = (pointarray == &array2 ? &array : &array2);
        pointlen = (pointlen == &length2 ? &length : &length2);
        pointidx = (pointidx == &index2 ? &index : &index2);

        if (*pointlen == *pointidx) {
            printf("Resizing array...\n");
            void* newarray = realloc(*pointarray, sizeof(char*)*(*pointlen+1));
            if (newarray == NULL) {
                perror("Error allocating memory.\n");
                exit(1);
            } else {
                *pointarray = newarray;
            }
            (*pointlen)++;
        }
        (*pointarray)[*pointidx] = strdup(newelem);
        (*pointidx)++;

        print_elems(*pointarray, *pointlen);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.