简体   繁体   English

操作指针会导致 valgrind 中出现“无效的 realloc()”

[英]Manipulating pointers causes “invalid realloc()” in valgrind

I have a project that involves reading in an indeterminate number of strings and appending them into different char** based on some associated metadata.我有一个项目,涉及读取不确定数量的字符串,并根据一些相关的元数据将它们附加到不同的 char** 中。 I have code that will realloc() a char** to grow dynamically with the data, and it takes as input a pointer to one of the char** so it can be somewhat generic.我的代码将 realloc() 一个 char** 与数据一起动态增长,并且它将指向其中一个 char** 的指针作为输入,因此它可能有点通用。 However, I'm screwing something up with the pointers that causes realloc() to free() the char** too early, resulting in errors.但是,我搞砸了导致 realloc() 过早地释放 char** 的指针,从而导致错误。 I cannot find what I am doing wrong.我找不到我做错了什么。

Here's a stripped-down sample that illustrates what I'm trying to do.这是一个精简的示例,说明了我正在尝试做的事情。 References to metadata are stripped out, and instead the code alternates between one char** and another in a manner that might happen in the full project.对元数据的引用被删除,代码在一个 char** 和另一个 char** 之间交替,这种方式可能在整个项目中发生。 This sample also omits some error checking on malloc() and some appropriate cleanup (ie. free()) that would be present in the full project.此示例还省略了对 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);
    }

}

Typically after no more than 10 runs through the loop the program crashes.通常,在循环运行不超过 10 次后,程序就会崩溃。 Valgrind gives this output: Valgrind 给出了这个 output:

==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

If I don't do all this pointer-switching the program runs fine, but the project would be a lot more complicated and I have to imagine there's a way to do what I'm trying to do.如果我不做所有这些指针切换程序运行良好,但项目会复杂得多,我不得不想象有一种方法可以做我想做的事情。

Can someone tell me what I'm screwing up that makes realloc() go off the rails?有人能告诉我我在搞砸什么导致 realloc() go 脱轨吗?

After you call realloc() you assign the result to pointarray , but this doesn't change array or array2 .调用realloc()后,将结果分配给pointarray ,但这不会更改arrayarray2 Then during a future iteration, you assign one of them to pointarray , but they no longer point to valid storage.然后在未来的迭代中,将其中一个分配给pointarray ,但它们不再指向有效存储。

You need an extra level of indirection, similar to the way you indirect to get to the length and index variables.您需要额外的间接级别,类似于间接访问长度和索引变量的方式。

Also, after you call realloc() you're checking pointarray , but you should be checking newarray .此外,在您调用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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM