Манипулирование указателями вызывает в valgrind "недопустимое reallo c ()" - PullRequest
1 голос
/ 05 мая 2020

У меня есть проект, который включает чтение неопределенного количества строк и добавление их в разные символы ** на основе некоторых связанных метаданных. У меня есть код, который будет reallo c () char ** для динамического роста с данными, и он принимает в качестве входных данных указатель на один из char **, поэтому он может быть несколько общим c. Однако я что-то делаю с указателями, из-за чего reallo c () слишком рано освобождает () char **, что приводит к ошибкам. Я не могу найти, что делаю неправильно.

Вот урезанный образец, который иллюстрирует то, что я пытаюсь сделать. Ссылки на метаданные удаляются, и вместо этого код чередуется между одним char ** и другим способом, который может произойти в полном проекте. В этом примере также отсутствует проверка ошибок в mallo c () и соответствующая очистка (ie. 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 проходит через l oop программа вылетает. 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

Если я не сделаю все это переключение указателей, программа будет работать нормально, но проект будет намного сложнее, и я должен представить, что есть способ сделать то, что Я пытаюсь это сделать.

Может кто-нибудь сказать мне, что я делаю, что сбивает reallo c () go с рельсов?

1 Ответ

1 голос
/ 05 мая 2020

После вызова realloc() вы назначаете результат pointarray, но это не меняет array или array2. Затем во время будущей итерации вы назначаете одному из них 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);
    }
}
...