Home > Enterprise >  How to properly cast to a void type as an array in C
How to properly cast to a void type as an array in C

Time:03-26

I am working on a problem in C where I want to create a dynamic growing array, and if possible utilize the same functions for different data types. Presently I have a struct titled Array that uses a void data type titled *array which is a pointer to the array. It also holds len which stores the active length of the array, size which holds that length of the allocated memory, and elem which stores the length of a datatype that is used to dynamically grow th earray.

In addition, I am using three functions. The function initiate_array does the heavy lifting of allocating memory for the array variable in the struct and instantiating all but one of the struct elements. The function init_array acts as a wrapper around initiate_array and also instantiates the variable elem in the struct. Finally, the function append_array adds data/indices to the array and reallocates memory if necessary. At this point the Array struct, and the functions initiate_array and init_array are independent of data type; however, append_array is hard coded for int variables. I have tried to make append_array somewhat data type independent by making the input int item into void item, but then I get a compile time error at each location with the code ((int *)array->array)[array->len - 1] = item that tells me I cannot cast to a void. My code is below, does anyone have a suggestion on how I can implement the append_array function to be independent of the datatype of item? NOTE: I also have a function to free memory at the end of execution, but I am omitting it from this question since it is not relevant.

array.h

#ifndef ARRAY_H
#define ARRAY_H

#include <stdlib.h>
#include <stdio.h>

typedef struct
{
    void *array;
    size_t len;
    size_t size;
    int elem;
} Array;

void initiate_array(Array *array, size_t num_indices);
Array init_array(int size, size_t num_indices);
void append_array(Array *array, int item);

#endif /* ARRAY_H */

array.c

#include "array.h"

void initiate_array(Array *array, size_t num_indices) {
    void *pointer;

    pointer = malloc(num_indices * array->elem);

    if (pointer == NULL) {
        printf("Unable to allocate memory, exiting.\n");
        free(pointer);
        exit(0);
    }
    else {
        array->array = pointer;
        array->len = 0;
        array->size = num_indices;
    }
}

Array init_array(int size, size_t num_indices) {
    Array array;
    array.elem = size;
    initiate_array(&array, num_indices);
    return array;
}

void append_array(Array *array, int item) {
    array->len  ;
    if (array->len == array->size){
        array->size *= 2;
        void *pointer;
        pointer = realloc(array->array, array->size * array->elem);

        if (pointer == NULL) {
            printf("Unable to reallocate memory, exiting.\n");
            free(pointer);
            exit(0);
        }
        else {
            array->array = pointer;
            ((int *)array->array)[array->len - 1] = item;
        }
    }
    else
        ((int *)array->array)[array->len - 1] = item;
}

main.c

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

int main(int argc, char** argv)
{
    int i, j;
    size_t indices = 20;
    Array pointers = int_array(sizeof(int), indices);

    for (i = 0; i < 50; i  )
    {
        append_int_array(&pointers, i);
    }

    for (i = 0; i < pointers.len; i  )
    {
        printf("Value: %d Size:%zu \n",((int *) pointers.array)[i], pointers.len);
    }

    return (EXIT_SUCCESS);
}

CodePudding user response:

The type void is an incomplete type, and one which cannot be completed, so you can't assign to or from it, or use it as an array parameter type.

What you can do is change append_array to take a void * as an argument which points to the data to be added. Then you convert your data pointer to char * so you can do single byte pointer arithmetic to get to the correct offset, then use memcpy to copy in the data.

void append_array(Array *array, void *item) {
    array->len  ;
    if (array->len == array->size){
        array->size *= 2;
        void *pointer;
        pointer = realloc(array->array, array->size * array->elem);

        if (pointer == NULL) {
            printf("Unable to reallocate memory, exiting.\n");
            free(array->array);
            exit(0);
        }
        else {
            array->array = pointer;
        }
    }
    char *p = (char *)array->array   (array->len - 1) * array->elem;
    memcpy(p, item, array->elem);
}

You won't be able to call this function by passing an integer literal to add, but you can use the address of a compound literal.

append_array(array, &(int){ 3 });

CodePudding user response:

It should be something like this, or you could use typeof to improve it. Or, use void **array;

#include <assert.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    void *array;
    size_t size;
    size_t capacity;
    int elem_size;
} Array;

void initiate_array(Array *array, size_t num_indices);
Array init_array(int size, size_t num_indices);
void append_array(Array *array, void *item);

void initiate_array(Array *array, size_t num_indices) {
    void *pointer;

    pointer = malloc(num_indices * array->elem_size);

    if (pointer == NULL) {
        printf("Unable to allocate memory, exiting.\n");
        // free(pointer);
        exit(0);
    } else {
        array->array = pointer;
        array->size = 0;
        array->capacity = num_indices;
    }
}

Array init_array(int elem_size, size_t num_indices) {
    Array array;
    array.elem_size = elem_size;
    initiate_array(&array, num_indices);
    return array;
}

void append_array(Array *array, void *item) {
    if (array->size == array->capacity) {
        // extend the array
    }

    memcpy(array->array   array->size * array->elem_size, item,
           array->elem_size);
    array->size  ;
}

int main(void) {
    Array arr = init_array(sizeof(int), 10);

    int item = 1;
    append_array(&arr, &item);
    item = 2;
    append_array(&arr, &item);
    item = 3;
    append_array(&arr, &item);

    return 0;
}
  • Related