首页 > 解决方案 > 将内存分配给 const char*** 变量时出现错误“realloc(): invalid next size”

问题描述

我有一个功能

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

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

我使用malloc(0). 规范说它要么返回一个空指针,要么返回一个可以传递给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

返回一个字符串。

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

标签: cmemory-managementmallocrealloc

解决方案


这个循环非常混乱:

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总是返回一个编译时间常数,所以realloc实际上没有任何意义。

memcpy实际上也没有任何意义,因为您正在将字符串复制到指针数组的内存中(可能还有额外的缓冲区溢出)。

你说这*gAvailableExtensions是一个指向字符串指针数组的指针。这意味着您必须realloc在缓冲区中保存正确数量的指针,以及malloc要存储的每个字符串的内存。

对于这个例子,我假设它.extensionName的类型是char *or 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比 长,您可以通过将and放入循环中*gAvailableExtensions来简化这一点,并执行以下操作:mallocmemcpy

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

最后用一些刺耳的话:看起来你有“无限数量的猴子”编程方法,只需敲击键盘直到它工作。

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

编程不是猜谜游戏。在移动到下一个代码之前,您必须了解您编写的每一段代码。


推荐阅读