C reallo c () в массиве гибких длин - PullRequest
0 голосов
/ 05 апреля 2020

У меня есть структура вместе с этими функциями. Цель состоит в том, чтобы имитировать c хранение / доступ к списку с использованием предварительно выделенного массива.

#define ALLOC_INC_COUNT 100

typedef struct
{
  size_t count, el_size, alloc_count;
  char data[];
} bl_t;

bl_t *bl_new(size_t el_size)
{
  bl_t *list = malloc(sizeof *list + ALLOC_INC_COUNT * el_size);

  if (list == NULL)
    return NULL;

  list->count = 0;
  list->el_size = el_size;
  list->alloc_count = ALLOC_INC_COUNT;
  return list;
}

Мой вопрос: если я хочу изменить размер структуры с помощью функции, такой как bl_add (), программа некорректно работает на строка memcpy в тех случаях после перераспределения структуры. Я не совсем понимаю, почему.

bool bl_add(bl_t *list, void *data)
{
  if (list->count > list->alloc_count - 1)
  {
    bl_t *swap = realloc(list, sizeof *swap + (list->count + ALLOC_INC_COUNT) * list->el_size);

    if (swap == NULL)
      return 0;

    list = swap;
    list->alloc_count += ALLOC_INC_COUNT;
  }

  memcpy(list->data + list->count * list->el_size, data, list->el_size);
  list->count++;
  return 1;
}

1 Ответ

1 голос
/ 05 апреля 2020

Проблема здесь в том, что bl_add может перераспределить bl_t*, который передается в качестве аргумента, но он не может сообщить вызывающей стороне, что он это сделал, или каким должно быть новое значение аргумента. Таким образом, list вызывающего абонента становится висящим указателем, и в следующий раз, когда он его использует, наступит хаос (или неопределенное поведение).

Одно из решений - вернуть новое значение list (или * 1007). * в случае сбоя), требуя от вызывающего абонента написать:

 list = bl_add(list, data);

Другая возможность - попросить вызывающего абонента передать указатель указателю list (дескриптор "" "), позволяя bl_add обновить указатель:

 status = bl_add(&list, data);
...