Странная проблема при перераспределении памяти в C - PullRequest
0 голосов
/ 10 февраля 2020

Я пытаюсь войти в C и в качестве учебного примера я решил написать простой динамически изменяемый список. Но я сталкиваюсь со странной проблемой, когда код работает только до начального размера списка 4. Начиная с размера списка 5, я получаю сообщение об ошибке.

typedef struct {
    int* data;
    int alloc_size;
    int length;
} List;

List create(int init_size) {
    List out;
    out.data = (int*) malloc(init_size * sizeof(int));
    out.alloc_size = init_size;
    out.length = 0;
    return out;
}

void list_push(List* list, int elem) {
    if (list->length == list->alloc_size) {
        list->data = (int*) realloc(list->data, 2 * list->alloc_size);
        list->alloc_size *= 2;
    }
    *(list->data + list->length) = elem;
    list->length++;
}

int list_pop(List* list) {
    list->length--;
    return *(list->data + list->length);
}

int main() {

    List list = create(5);

    for (int i = 0; i < 100; i++) {
        list_push(&list, i);
    }

    while (list.length > 0) {
        printf("%d\n", list_pop(&list));
    }

    return 0;
}

До create(4), все работает как и ожидалось. Но если список создается с create(5) (т.е. с начальным размером 5), я получаю следующую ошибку: malloc: Incorrect checksum for freed object 0x7f7ff5c01778: probably modified after being freed. Corrupt value: 0x700000006. Я не могу действительно обернуть голову, что заставило бы это работать только к указанным c начальным размерам, поскольку размер списка все равно динамически перераспределяется.

Ответы [ 2 ]

0 голосов
/ 10 февраля 2020

Есть несколько проблем с этой строкой

list->data = (int*) realloc(list->data, 2 * list->alloc_size);

Наиболее очевидным является то, что 2 * list->alloc_size следует умножить на размер в байтах каждого элемента (sizeof(int) или sizeof(*(list->data)) в этом case).

Наиболее тонким является то, что возвращаемое значение realloc (и предыдущего malloc) не проверяется, а безусловно присваивается list->data. Проблема заключается в том, что при ошибке он возвращает NULL, в то время как переданный указатель (list->data) не признан недействительным и должен быть освобожден во избежание утечек.

0 голосов
/ 10 февраля 2020

изменить на оператор перераспределения

list->data = (int*) realloc(list->data,sizeof(int) *  2 * list->alloc_size);

Во второй раз вы пытаетесь перераспределить меньшее количество байтов, чем вы уже выделили, вот причина этого

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...