【问题标题】:ERROR "realloc(): invalid next size" when allocating memory to const char*** variable将内存分配给 const char*** 变量时出现错误“realloc(): invalid next size”
【发布时间】:2020-01-15 13:56:28
【问题描述】:

我有一个函数

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 中的元素数量

【问题讨论】:

  • 您能否将整个代码粘贴到您的问题中?
  • 这不是完整的代码,availableExtensionProperties 是什么? sizeof(availableExtensionProperties[i].name); 是什么? I allocate initial memory to that array using malloc(0) 不要那样做,只需分配 NULLNULL 也可以传递给 free。如果您只使用结构而不是三星级程序员,您的设计会更容易。您能否将它们全部发布在一个可编译的代码块中,以便于阅读、复制、扫描和搜索错误?
  • @KamilCuk 这是一个结构,问题中的第 6 个代码块。实现类似于VkExtensionPropertiessizeof(availableExtensionProperties[i].name) 应该返回字符串的大小并将其存储在 sizeOfAvailableExtensionName 变量中。
  • &amp;(*gAvailableExtensions)[currentAvailableExtensionCount] 我想你想要(*gAvailableExtensions)[currentAvailableExtensionCount]。还有&amp;availableExtensionProperties[i].name,只是availableExtensionProperties[i].name(以防您稍后将name 更改为指针)。不用担心 - 我了解 sizeof 的作用。但是您的帖子被格式化为单独的代码 sn-ps 的方式使我无法阅读。最好发布代码而不是描述代码的作用。我知道“返回”或“复制”是什么,或者代码在 for 中,等等。
  • populateAvailableExtensions() 的第一行中的 sizeof() 没有达到您的预期。两者都将返回指针大小。您不能使用sizeof() 来确定作为参数传递的数组的大小,因为它已衰减为指针

标签: c memory-management malloc realloc


【解决方案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 &lt; 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 *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;

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

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

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

【讨论】:

    【解决方案2】:
    int currentAvailableExtensionCount =
         sizeof(*gAvailableExtensions) / sizeof(**gAvailableExtensions) - 1;
    

    只是一种混淆的说法

    int currentAvailableExtensionCount = 0;
    

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

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

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

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

    【讨论】:

    • 已修复。现在函数接受一个计数器变量,该变量保存数组中已有元素的数量。因为函数是例程中的第一个函数,所以该变量应该始终为 0。所以int currentAvailableExtensionCount = 0; 也是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 2022-07-22
    • 2012-04-23
    • 2013-10-07
    • 2014-07-04
    • 1970-01-01
    相关资源
    最近更新 更多