I have been working on a simple library in C to handle arrays, dynamic arrays and linked lists. As a starting point I have been working on a function to pop a user defined index from an array. For starters I am working an an integer array and came upon this solution.
int pop_int_array(int *array, int index, int size) {
int type = sizeof(int);
if (index >= size) return 0;
unsigned char *dst = (unsigned char*) array index type;
memmove(dst, dst type, type * (size - index - 1));
return 1;
}
int main(int argc, const char * argv[]) {
int a[5] = {1, 2, 3, 4, 5};
pop_int_array(a, 2, 5);
for (int i = 0; i < 4; i ) {
printf("%d\n", a[i]);
}
}
This yields the following output as expected
1
2
4
5
If I wanted to pop a float
array, I would need to create a new function titled pop_float_array
that copied all of the contents from pop_int_array
but instead of using int type = sizeof(int)
I would replace it with int type = sizeof(float)
, and of course the array data type would be a float
instead of an int
. However, this violates a core principle of software development by repeating the same code several times, where each time would be an implementation for a data type. In order to get around this I re-wrote the function in the following way where the array is declared as a void
data type. In addition I cast the array to a void *
in the main program before or during the process of passing it to the function.
int pop_array(void *array, int index, int size, int type) {
if (index >= size) return 0;
unsigned char *dst = (unsigned char*) array index type;
memmove(dst, dst type, type * (size - index - 1));
return 1;
}
int main(int argc, const char * argv[]) {
int a[5] = {1, 2, 3, 4, 5};
pop_array((void *)a, 2, 5);
for (int i = 0; i < 4; i ) {
printf("%d\n", a[i]);
}
float b[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
pop_array((void *)a, 2, 5);
for (int i = 0; i < 4; i ) {
printf("%f\n", a[i]);
}
}
As expected this yields
1
2
4
5
1.1
2.2
4.4
5.5
This allows me to only create and maintain one function. However, this seems so simple that I am surprised it is not a more widely used technique, or at least that I am aware of in my little experience. Is there some consequence of writing the function this was or casting the array to a void *
that I am not seeing, or is this a legitimate way to make a function type agnostic in C?
CodePudding user response:
The way you're doing this is fine. But you do have one mistake:
unsigned char *dst = (unsigned char*) array index type;
You're not moving up by the right amount. This should be:
unsigned char *dst = (unsigned char*) array (index * type);
Also, you don't need to cast to void *
when you call the function:
pop_array(a, 2, 5, sizeof(int));
This technique is used in the qsort
function which can sort an array of an arbitrary type. It's signature is as follows:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
As with your function, it takes a void *
to the start of the array as well as the number of elements and the size of each element. It also takes a function pointer whose job is to perform the type specific comparison.