简体   繁体   中英

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

I have a dynamic array implementation I'm working on for generic types. My understanding is that the invalid pointer error for realloc is usually caused by not using malloc to allocate the original pointer, however, I am using malloc.

Here is my array.h code

#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;
}

I've been trying to fix this error, but my C skills are subpar. What am I missing here?

Your malloc is wrong:

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

This does not allocate space for a struct array . It allocates memory corresponding to the size of a pointer and some extra bytes (here 1*4).

On my system the above allocation is for 12 bytes but struct array requires 32 bytes.

So the allocated memory can't hold a struct array and you are accessing memory that isn't assigned to you. Then anything may happen.

It's a bit unclear what you are trying to achieve with this malloc . The "normal way" is simply:

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

And you also need to save objsize like

a->obj_size = objsize;

in the new_array function. If you don't the realloc uses an uninitialized variable:

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

Further this is very strange:

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...

I wonder if you really want something like:

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

As a final note:

Sometimes you check for NULL after malloc and sometimes you don't. Either do it every time or don't do it at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM