I am trying to produce a library that contains C functions to create a dynamically allocated array as well as other basic array operations. I have defined a typedef struct
that contains a pointer variable array
which stores the data points in the array. The struct
also contains other variables such as the allocated array size
the array length (i.e. len
) as well as the array name and datatype. The goal is that the array should be dynamically allocated and the array container should be able to hold any data type. I have created a function titled init_array
, which is a wrapper around array_mem_alloc
to instantiate the array container. Finally I have another function titled append_array
where the user can pass a scalar or another defined array that will be appended to the data already within array
.
I am trying to create a function titled pop_array
, but I am struggling with how to write it. Normally you could just iterate over a for loop from indice to the assigned length, overwrite the first indice and move all others to the left. Unfortunately in this case array
is a void variable, and I run into problems assigning data to a void. I have tried some implementations with memcp
and memmove
, but I can not find a solution where the compiler allows me to assign the data to a void type. Any thoughts or help would be appreciated. The code is shown below.
array.h
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
void *array; // Pointer to array
size_t len; // Active length of array
size_t size; // Number of allocated indizes
int elem; // Memory consumption per indice
char *name; // The array name
char *dtype; // A string representing the datatype
} Array;
void array_mem_alloc(Array *array, size_t num_indices);
Array init_array(char *dtype, size_t num_indices, char *name);
int append_array(Array *array, void *elements, size_t count);
int pop_array(Array *array, int indice);
Array.c
void array_mem_alloc(Array *array, size_t num_indices) {
// Determine the total memory allocation and assign to pointer
void *pointer;
pointer = malloc(num_indices * array->elem);
// If memory is full fail gracefully
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(pointer);
exit(0);
}
// Allocate resources and instantiate Array
else {
array->array = pointer;
array->len = 0;
array->size = num_indices;
}
}
// --------------------------------------------------------------------------------
Array init_array(char *dtype, size_t num_indices, char *name) {
// Determine memory blocks based on data type
int size;
if (strcmp(dtype, "float") == 0) size = sizeof(float);
else if (strcmp(dtype, "int") == 0) size = sizeof(int);
else if (strcmp(dtype, "double") == 0) size = sizeof(double);
else if (strcmp(dtype, "char") == 0) size = sizeof(char);
else {
printf("Data type not correctly entered into init_array, exiting program!\n");
exit(0);
}
// Allocate indice size and call array_mem_alloc
Array array;
array.dtype = dtype;
array.elem = size;
array_mem_alloc(&array, num_indices);
array.name = name;
return array;
}
// --------------------------------------------------------------------------------
int append_array(Array *array, void *elements, size_t count) {
// Allocae more memory if necessary
if (array->len count > array->size) {
size_t size = (array->len count) * 2;
void *pointer = realloc(array->array, size * array->elem);
// If memory is full return operations
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
return 0;
}
// Allocate memory to variables and increment array size
array->array = pointer;
array->size = size;
}
// Append variables and increment the array length
memcpy((char *)array->array array->len * array->elem, elements, count * array->elem);
array->len = count;
return 1;
}
// --------------------------------------------------------------------------------
int pop_array(Array *array, int indice) {
if (indice >= array->len) {
printf("Indice %d out of bounds for pop_array", indice);
return 0;
}
for (int i = index; i < array->len; i ) {
// This does not work because I cannot assign to a void type
// - I have tried to several solutions with append_array and memcpy
// but all solutions seem to run into a problem where assigning data
// already in the array is not possible.
array->array[i] = array->array[i 1];
}
// Decrement array length
array->len -= 1;
return 1;
}
CodePudding user response:
Belaying potential alignment issues, you don't need a loop. I believe this is all you need to shift the right-most desired elements 'back' one 'slot':
unsigned char *dst = (unsigned char*)array->array indice * array->elem;
memmove(dst, dst array->elem, array->elem * (array->len - indice - 1));
CodePudding user response:
There are lot of things that go wrong in your implementation.
For example, the way you use your name char pointer can lead to it pointing to deallocated memory. The following code :
void foo(Array *array) {
char name[] = "abc";
char type[] = "int";
init_array(type, name, array);
}
int main(int args, char **argv) {
Array array;
foo(&array);
puts(array.name);
}
leads to undefined behavior, because array.name
and array.dtype
point to chunks of memory which have been popped from the stack.
One can also mention that you only manage very few cases. What happens if the user input "short"
as dtype ?
For your specific problem, memmove
is your friend :
void* slot = array->array array->elem * indice;
memcpy(array->array array->len * array->elem, slot, array->elem);
--vector->len;
memmove(slot, (const void *) slot array->elem, (array->len - indice) * array->elem);