Неверная запись при инициализации массива связанных списков - PullRequest
0 голосов
/ 24 марта 2020

Итак, у меня есть эта функция, которая выделяет и инициализирует NULL, что будет массивом связанных списков. На самом деле я хочу, чтобы эта функция возвращала массив NULL указателей, чтобы я мог позже заполнить его связанными списками.

static t_tokens **init_tokens_groups(size_t size)
{
    t_tokens **toks_groups;
    if (!(toks_groups = malloc(sizeof(toks_groups) * size + 1)))
        exit(EXIT_FAILURE);
    while (size + 1)
    {
        printf("size: %zu\n", size);
            toks_groups[size] = NULL;
            size--;
    }
    return (toks_groups);
}

Она работает нормально, но когда я запускаю свою программу (которая является минималистская оболочка) в Valgrind,

valgrind --track-origins=yes ./mysh

Я сталкиваюсь с этим:

==4914== Invalid write of size 8
==4914==    at 0x10AD6B: init_tokens_groups (tokens_split.c:39)
==4914==    by 0x10AE06: split_tokens (tokens_split.c:68)
==4914==    by 0x1093D9: prompt_loop (sh21.c:38)
==4914==    by 0x10944A: main (sh21.c:57)
==4914==  Address 0x4a508f8 is 8 bytes inside a block of size 9 alloc'd
==4914==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4914==    by 0x10AD42: init_tokens_groups (tokens_split.c:35)
==4914==    by 0x10AE06: split_tokens (tokens_split.c:68)
==4914==    by 0x1093D9: prompt_loop (sh21.c:38)
==4914==    by 0x10944A: main (sh21.c:57)
==4914== 
==4914== Invalid write of size 8
==4914==    at 0x10AD6B: init_tokens_groups (tokens_split.c:39)
==4914==    by 0x10AE06: split_tokens (tokens_split.c:68)
==4914==    by 0x109369: dispatch (sh21.c:19)
==4914==    by 0x1093F6: prompt_loop (sh21.c:42)
==4914==    by 0x10944A: main (sh21.c:57)
==4914==  Address 0x4a509f8 is 8 bytes inside a block of size 9 alloc'd
==4914==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4914==    by 0x10AD42: init_tokens_groups (tokens_split.c:35)
==4914==    by 0x10AE06: split_tokens (tokens_split.c:68)
==4914==    by 0x109369: dispatch (sh21.c:19)
==4914==    by 0x1093F6: prompt_loop (sh21.c:42)
==4914==    by 0x10944A: main (sh21.c:57)

Я действительно не понимаю, откуда это происходит, так как я просто инициализирую эти указатели на NULL на этом этапе, и у меня нет проблем или ошибок (ну, не то, что я обнаружил) при заполнении, манипулировании и чтении этих массивов связанных списков в программе. Я предполагаю, что я делаю что-то странное с памятью, но я не вижу, где.

1 Ответ

2 голосов
/ 24 марта 2020

Это:

toks_groups = malloc(sizeof(toks_groups) * size + 1))

неверно и вызывает проблему позже при первом выполнении toks_groups[size] = NULL; (что находится за пределами выделенного региона). Valgrind сообщает вам, что недопустимая запись имеет длину 8 байт, поскольку размер указателя в вашей системе составляет 8 байт.

Если вы хотите выделить size + 1 элементов, вы должны поместить выражение в скобки. То, что вы делаете sizeof(toks_groups), также очень странно и не имеет особого смысла. Вероятно, вы хотели бы сделать следующее:

toks_groups = malloc(sizeof(*toks_groups) * (size + 1)))

Если вы хотите выделить только size элементов (не size + 1), то удалите + 1 из malloc() и измените while (...) состояние. Вам также не нужен while вообще, если вы хотите инициализировать все до NULL, вы можете просто использовать calloc() вместо malloc().

Также, как правило :

  1. Используйте значимые имена. Вызывать что-то size, когда это явно не размер, а просто количество элементов, сбивает с толку.
  2. Используйте правильные конструкции кода. Использование while l oop для итерации по диапазону значений действительно противоречит интуиции и может легко привести к ошибкам.

Лучшая версия приведенного выше кода будет выглядеть следующим образом:

static t_tokens **init_tokens_groups(size_t n)
{
    t_tokens **toks_groups;

    if (!(toks_groups = calloc(sizeof(*toks_groups) * (n + 1))))
        exit(EXIT_FAILURE);

    return toks_groups;
}

Я все еще не уверен, нужен ли вам дополнительный элемент или нет, но вы должны это знать.

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