0

I'm trying to write a dynamic array (dynamic in size and type) in C.

First I wrote a function to initialize the array. Input is a enum (TYPE) and according to value of this parameter I allocate memory for corresponding type.

This is how I initialize the array:

...

typedef enum {
    CHAR,
    INT,
    FLOAT,
    DOUBLE,
    BOOLEAN,
} TYPE;

...

struct vector_result {
    TYPE type;
    int len;
    void* data;
};

...

struct vector_result DSTR_vector_init(TYPE type){
    void* data;
    switch (type) {
        case CHAR:
            data = (char*) malloc(0);
            break;
        case INT:
            data = (int*) malloc(0);
            break;
        case FLOAT:
            data = (float*) malloc(0);
            break;
        case DOUBLE:
            data = (double*) malloc(0);
            break;
        case BOOLEAN:
            data = (bool*) malloc(0);
            break;
        default:
            fprintf(stderr, "unknown type to initialize vector\n");
            exit(EXIT_FAILURE);
    }
    struct vector_result result;
    result.type = type;
    result.data = data;
    result.len = 0;
    return result;
}

And this is how I resize and append data to list:

void DSTR_vector_push(struct vector_result* vector, void* value){
    vector->len++;
    switch (vector->type) {
        case CHAR:
            vector->data = (char*) realloc(vector->data, get_type_size(vector->type) * vector->len);
            ((char*)vector->data)[vector->len-1] = *(char*) value;
            break;
        case INT:
            vector->data = (int*) realloc(vector->data, get_type_size(vector->type) * vector->len);
            ((int*)vector->data)[vector->len-1] = *(int*) value;
            break;
        case FLOAT:
            vector->data = (float*) realloc(vector->data, get_type_size(vector->type) * vector->len);
            ((float*)vector->data)[vector->len-1] = *(float*) value;
            break;
        case DOUBLE:
            vector->data = (double*) realloc(vector->data, get_type_size(vector->type) * vector->len);
            ((double*)vector->data)[vector->len-1] = *(double*) value;
            break;
        case BOOLEAN:
            vector->data = (bool*) realloc(vector->data, get_type_size(vector->type) * vector->len);
            ((bool*)vector->data)[vector->len-1] = *(bool*) value;
            break;
        default:
            fprintf(stderr, "unknown type to initialize vector\n");
            exit(EXIT_FAILURE);
    }
}

And below code is initializing and appending an item to list

struct vector_result int_vec = DSTR_vector_init(INT);
DSTR_vector_push(&int_vec, 10);

But I get this error after execution:

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

What is the problem?

pedram
  • 335
  • 1
  • 4
  • 19
  • Post a program not snippets (see [mre]). You don't need to cast void * from realloc. The pattern you use when calling realloc will lead to leaks if realloc fails. You have to assign to a temporary, see if it's null, then figure out what you want to do. – Allan Wind Jan 05 '23 at 07:07
  • First of all, it's implementation defined if `malloc(0)` returns a null-pointer or not. Either way, you can not dereference the pointer, even if it's not a null-pointer. It can only be passed to `realloc` or `free` (or reassigned). – Some programmer dude Jan 05 '23 at 07:07
  • Secondly, in C you [should not cast the result of `malloc`, `calloc` or `realloc`](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc/605858) (or any other function returning `void *`). And considering that `data` is a `void *`, why even cast in the first place? – Some programmer dude Jan 05 '23 at 07:09
  • Run the program in a debugger to see where it crashes. Use the call stack to find your code if it crashes in a library function. Use tools like AddressSanitizer to help track down issues like this. – Retired Ninja Jan 05 '23 at 07:11
  • 2
    Why so much complicated code to _initialise_ a void pointer to NULL... Not sure that `malloc(0);` will be a happy-chappy... The problem with trying to make a generic array like this is that you lose the help of the compiler and open the door to "pushing" `float`s into arrays that were meant to hold `char`s. – Fe2O3 Jan 05 '23 at 07:15
  • Have you read the section of the chapter that discusses `union`s??? It may been a bit wasteful storing a single `char` in an allocation to hold a `double` or a `pointer`, but using `realloc()` to grow an array incrementally won't win any performance awards... – Fe2O3 Jan 05 '23 at 07:22

1 Answers1

1

I'm guessing the main problem is this:

*(int*) value;

You pass the int value 10 to the function. It's not a valid pointer, it can't be dereferenced. Attempting to dereference 10 will lead to undefined behavior (and likely crashes).

You need to use the value as an actual value not a pointer:

DSTR_vector_push(&int_vec, (void *) (intptr_t) 10);

and

((int*)vector->data)[vector->len-1] = (int) (intptr_t) value;

Same problem with almost all the other cases.

The exception is for char, because it's implementation-defined if char is signed or unsigned. You need to use uintptr_t to preserve the bits as is, instead of preserving the value.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621