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