【问题标题】:C realloc() Invalid Pointer Error even though malloc was usedC realloc() 无效指针错误,即使使用了 malloc
【发布时间】:2021-08-31 22:02:08
【问题描述】:

我正在为泛型类型开发一个动态数组实现。我的理解是realloc的无效指针错误通常是由于没有使用malloc分配原始指针引起的,但是我使用的是malloc。

这是我的 array.h 代码

#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>

struct array {
    void *elems;
    size_t obj_size;
    size_t size;
    size_t capacity;
};

struct array* new_array(size_t objsize);
int push_back(struct array* a, const void* value); 

数组.c

#include "array.h"
#include <stdio.h>
#include <string.h>
#define INITIAL_SIZE (1)
#define ARR_AT(a, i) ((void *) ((char *) (a)->elems + (i) * (a)->obj_size))

struct array* new_array(size_t objsize) {
    struct array* a;

    a = malloc(sizeof a + INITIAL_SIZE * objsize);
    if (!a) { return NULL; }

    a->elems = malloc(objsize);
    a->capacity = 1;
    a->size = 0;
    return a;
}

int push_back(struct array* a, const void* value) {
    if (a->size == a->capacity) {
        void* temp = realloc(a->elems, a->obj_size * a->capacity * 2); 
        a->elems = temp;
        if (!a) { return -1; }
        a->capacity = a->capacity * 2;
    }

    memcpy(ARR_AT(a, a->size), value, a->obj_size);
    a->size++;
    return 0;
}

main.c

#include "array.h"
#include <stdio.h>

int main(void) {
    struct array* a = new_array(4);
    uint32_t* b = (uint32_t*) 3;
    push_back(a, b);
    printf("Size: %ld \n", a->size);

    for (int i = 0; i < 30; i++) {
        push_back(a, b + i);
        printf("Size: %ld \n", a->size);
    }   
    return 0;
}

我一直在尝试修复此错误,但我的 C 技能欠佳。我在这里错过了什么?

【问题讨论】:

  • a-&gt;obj_size 从未设置,因此 realloc 可能由于大小无效而失败。当您检查错误的指针时,您也不会发现:if (!a) 应该是 if (!temp)if (!a-&gt;elems)
  • 天哪,真是个愚蠢的错误。谢谢。
  • 如果无法分配请求的空间,realloc() 也会失败。您的程序需要保存旧指针,因为在这种情况下它不会被释放。
  • 如果您使用调试器(如 gdb),那么问题会在几分钟内显示出来

标签: c dynamic-arrays realloc


【解决方案1】:

您的malloc 错误:

a = malloc(sizeof a + INITIAL_SIZE * objsize);
           \------/   \----------------------/
       sizeof pointer     some extra bytes

不会struct array 分配空间。它根据指针的大小和一些额外的字节(这里是 1*4)分配内存。

在我的系统上,上述分配是 12 个字节,但 struct array 需要 32 个字节。

因此分配的内存不能容纳struct array,并且您正在访问未分配给您的内存。那么任何事情都可能发生。

有点不清楚你想用这个malloc 实现什么。 “正常方式”很简单:

a = malloc(sizeof *a); // Allocate a single 'struct array'

而且你还需要保存objsizelike

a->obj_size = objsize;

new_array 函数中。如果你不 realloc 使用未初始化的变量:

realloc(a->elems, a->obj_size * a->capacity * 2);
                  \---------/
                   Currently uninitialized

这很奇怪:

uint32_t* b = (uint32_t*) 3;  // Converting the number 3 to a pointer !?
push_back(a, b);              // and then push_back uses that pointer
                              // in memcpy... that has to fail...

我想知道你是否真的想要这样的东西:

uint32_t b = 3;   // Make an ordinary uint variable with value 3
push_back(a, &b); // Pass a pointer to the variable b so that
                  // the raw data representing the value 3 can be
                  // copied to "struct array"->elems

最后一点:

有时您在malloc 之后检查NULL,有时您不检查。要么每次都做,要么根本不做。

【讨论】:

  • 谢谢。是的,所以我在发布并修复它后注意到了 malloc 问题。我真正想要的是您列出的内容,并且我希望 a->elems 成为 malloc(objsize * INITIAL_SIZE)。对于 uint32_t 演员表,是的,我很愚蠢。我正在使用其他代码作为参考来尝试和学习。该代码旨在传递带有地址而不是值的结构。我仍然想知道是否有一种方法可以传递普通的整数、字符等。我想我希望它能够工作,无论你传递给函数的类型是什么。我将此标记为正确答案。有人留下的关于 realloc() 的评论也是正确的。
  • @SeanPayne 查看更新调用push_back。也许这就是您正在寻找的。​​span>
  • 这正是我想要的。谢谢你。对于那个很抱歉。来自 Python 的类型转换非常令人困惑。我被勺子喂得太多了:(
  • @SeanPayne 好吧...当来自 C 语言时,Python 非常令人困惑。;-)
  • @SeanPayne 对选角更加认真……是的,选角有点复杂。然而,好在你不需要在普通的精心设计的程序中进行强制转换。只有在做高级的事情时才需要铸造。顺便说一句:如果您想了解强制转换(和指针处理)的复杂性,请阅读“严格别名”。
猜你喜欢
  • 2017-09-16
  • 1970-01-01
  • 1970-01-01
  • 2021-04-18
  • 1970-01-01
  • 2015-07-13
  • 2013-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多