将内存分配给 const char*** 变量时出错 "realloc(): invalid next size"

ERROR "realloc(): invalid next size" when allocating memory to const char*** variable

我有一个功能

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

它以指向字符串数组的指针和数组中元素的数量作为参数。

我使用 malloc(0) 为该数组分配了初始内存。规范说它将 return 一个空指针或一个可以传递给 free().

的唯一指针
  int currentAvailableExtensionCount = gCounter;

此变量将存储 gAvailableExtensions 中的字符串数。

在这个 for 循环中

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

return一个字符串。

这就是 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;

在头文件中声明。

编辑 2:更新了代码,现在 gCounter 包含 gAvailableExtensions

中的元素数
int currentAvailableExtensionCount =
     sizeof(*gAvailableExtensions) / sizeof(**gAvailableExtensions) - 1;

只是

的一种混淆方式
int currentAvailableExtensionCount = 0;

之后我就停止阅读了,因为我认为那不是你打算写的。

c 中的指针不知道它们指向的序列中有多少个元素。他们只知道单个元素的大小。

在您的例子中,*gAvailableExtensionschar ** 类型,**gAvailableExtensionschar * 类型。两者都是指针,在典型的桌面系统上具有相同的大小。所以在 64 位桌面系统上表达式变成 8/8 - 1,等于零。

除非您修复此错误,或者明确您确实希望该值始终为零,否则其余代码没有任何意义。

这个循环完全是乱七八糟的:

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 的值。更新 'p' 是你的责任。在您的情况下,您永远不会更新 *gAvailableExtensions。我还怀疑你没有正确计算 sizeOfAvailableExtensionCount 。运算符 sizeof 总是 return 编译时间常量,因此 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 长,你可以通过在循环中删除 mallocmemcpy 来稍微简化一下,然后做:

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

最后说句狠话:看来你有"Infinite number of Monkeys"的编程方法,敲键盘就可以了。

这样的程序只会给人一种工作的错觉。他们迟早会以惊人的方式打破。

编程不是猜谜游戏。您必须 理解您编写的每一段代码,然后再转到下一段代码。