ОШИБКА "reallo c (): неверный следующий размер" при выделении памяти для переменной const char *** - PullRequest
1 голос
/ 15 января 2020

У меня есть функция

populateAvailableExtensions(const char** gAvailableExtensions[], int gCounter)

, которая принимает указатель на массив строк и количество элементов в массиве в качестве параметров.

Я выделяю начальная память для этого массива, используя malloc(0). Спецификации говорят, что он вернет либо нулевой указатель, либо уникальный указатель, который можно передать в free().

  int currentAvailableExtensionCount = gCounter;

Эта переменная будет хранить номер строки в gAvailableExtensions.

Внутри этого for l oop

for (int i = 0; i < availableExtensionCount; ++i)

у меня есть этот фрагмент кода

    size_t sizeOfAvailableExtensionName =
        sizeof(availableExtensionProperties[i].name);

    reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);

    memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
           &availableExtensionProperties[i].name,
           sizeOfAvailableExtensionName);

    ++currentAvailableExtensionCount;

, где

availableExtensionProperties[i].name

возвращает строку.

Вот как определяется struct

typedef struct Stuff {
    char        name[MAX_POSSIBLE_NAME];
    ...
    ...
} Stuff;

realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);

должно добавить память размером sizeOfAvailableExtensionName к *gAvailableExtensions массиву без ссылок.

memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
           &availableExtensionProperties[i].name,
           sizeOfAvailableExtensionName);

следует скопировать строку (это sizeOfAvailableExtensionName много памяти) из

&availableExtensionPropterties[i].name

адреса в

&(*gAvailableExtensions)[currentAvailableExtensionCount]

адреса.


Но я не не думаю, что код делает то, что я думаю, потому что я получаю эту ошибку

realloc(): invalid next size
Aborted
(core dumped) ./Executable

РЕДАКТИРОВАТЬ: Полный код

uint32_t populateAvailableExtensions(const char** gAvailableExtensions[], int gCounter) {

  int currentAvailableExtensionCount = gCounter;

  void* reallocStatus;

  uint32_t availableExtensionCount = 0;

  vkEnumerateInstanceExtensionProperties(
      VK_NULL_HANDLE, &availableExtensionCount, VK_NULL_HANDLE);

  VkExtensionProperties availableExtensionProperties[availableExtensionCount];

  vkEnumerateInstanceExtensionProperties(
      VK_NULL_HANDLE, &availableExtensionCount, availableExtensionProperties);

  for (int i = 0; i < availableExtensionCount; ++i) {

    size_t sizeOfAvailableExtensionName =
        sizeof(availableExtensionProperties[i].extensionName);

    reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);

    memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
           availableExtensionProperties[i].extensionName,
           sizeOfAvailableExtensionName);

    ++currentAvailableExtensionCount;
  }

  return currentAvailableExtensionCount;
}

Это то, как вызывает внешняя функция для этого в заголовочном файле объявлено

  uint32_t availableExtensionCount = 0;
  availableExtensions              = malloc(0);
  availableExtensionCount          = populateAvailableExtensions(&availableExtensions);

и

const char** availableExtensions;

.

EDIT 2: обновлен код, теперь gCounter содержит число элементы в gAvailableExtensions

Ответы [ 2 ]

1 голос
/ 15 января 2020

Это l oop совершенно грязно:

for (int i = 0; i < availableExtensionCount; ++i) {

    size_t sizeOfAvailableExtensionName =
        sizeof(availableExtensionProperties[i].extensionName);

    reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);

    memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
           availableExtensionProperties[i].extensionName,
           sizeOfAvailableExtensionName);

    ++currentAvailableExtensionCount;
  }

Я предполагаю, что единственные строки, которые делают то, что вы ожидаете, это строки for (int i = 0; i < availableExtensionCount; ++i) и ++currentAvailableExtensionCount;

Во-первых, типичный способ использования realloc выглядит следующим образом:

foo *new_p = realloc(p, new_size);
if (!new_p)
   handle_error();
else
   p = new_p;

Дело в том, что realloc не будет обновлять значение p, если произойдет перераспределение. Это ваша обязанность обновить «р». В вашем случае вы никогда не обновите *gAvailableExtensions. Я также подозреваю, что вы не правильно рассчитали sizeOfAvailableExtensionCount. Оператор sizeof всегда возвращает постоянную времени компиляции, поэтому realloc не имеет никакого смысла.

На самом деле memcpy также не имеет никакого смысла, так как вы копируете строку в память массива указателей (возможно, с дополнительным переполнением буфера).

Вы сказали, что *gAvailableExtensions - это указатель на массив указателей на строки. Это означает, что вам нужно realloc буфер для хранения правильного количества указателей и malloc память для каждой строки, которую вы хотите сохранить.

Для этого примера я предполагаю, что .extensionName имеет введите char * или char[XXX]:

// Calculate new size of pointer array
// TODO: Check for overflow
size_t new_array_size = 
  (currentAvailableExtensionCount + availableExtensionCount) * sizeof(*gAvailableExtensions);

char **tmp_ptr = realloc(*gAvailableExtensions, new_array_size);
if (!tmp_ptr)
    {
       //TODO: Handle error;
       return currentAvailableExtensionCount;
    } 
*gAvailableExtensions = tmp_ptr;

// Add strings to array
for (int i = 0; i < availableExtensionCount; ++i) 
  {
    size_t length = strlen(availableExtensionProperties[i].extensionName);

    // Allocate space for new string
    char *new_s = malloc(length + 1); 
    if (!new_s)
       { 
         //TODO: Handle error;
         return currentAvailableExtensionCount;
       }

    // Copy string
    memcpy (new_s, availableExtensionProperties[i].extensionName, length + 1);

    // Insert string in array
    (*gAvailableExtensions)[currentAvailableExtensionCount] = new_s;

    ++currentAvailableExtensionCount;
  }

Если вы можете гарантировать, что время жизни availableExtensionProperties[i].extensionName длиннее *gAvailableExtensions, вы можете немного упростить это, опустив malloc и memcpy в l oop и выполните:

char *new_s  = availableExtensionProperties[i].extensionName;
(*gAvailableExtensions)[currentAvailableExtensionCount] = new_s;

Несколько хар sh слов в конце: похоже, у вас есть подход к программированию "Бесконечное число обезьян", просто нажмите Клавиатура, пока она не работает.

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

Программирование - это не игра в догадки. У вас есть , чтобы понять каждый фрагмент кода, который вы пишете, прежде чем переходить к следующему.

0 голосов
/ 15 января 2020
int currentAvailableExtensionCount =
     sizeof(*gAvailableExtensions) / sizeof(**gAvailableExtensions) - 1;

- это просто запутанный способ сказать

int currentAvailableExtensionCount = 0;

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

Указатели в c не знают, сколько элементов в последовательности они указывают. Они знают только размер одного элемента.

В вашем случае *gAvailableExtensions имеет тип char **, а **gAvailableExtensions имеет тип char *. Оба указателя имеют одинаковый размер в типичной настольной системе. Таким образом, в 64-битной настольной системе выражение превращается в 8/8 - 1, что равно нулю.

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

...