C realloc() 无效指针错误,即使使用了 malloc

C realloc() Invalid Pointer Error even though malloc was used

我正在为泛型类型开发一个动态数组实现。我的理解是realloc的invalid pointer错误一般是没有用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); 

Array.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 技能很差。我在这里错过了什么?

你的malloc是错误的:

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

不会 struct array 分配 space。它分配与指针大小和一些额外字节(此处为 1*4)相对应的内存。

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

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

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

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

而且你还需要收藏objsize喜欢

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,有时则不会。要么每次都做,要么根本不做。