Swap ends
You’re asked to write a function that swaps the first and last elements in an array of numbers not knowing the type.
Here is an example of the function we want to write but with ints:
void swap_ends_int(int *arr, size_t nelems) {
int tmp = arr[0];
arr[0] = arr[nelems – 1];
arr[nelems – 1] = tmp;
}
Now let us write it generically. We will use our swap
function that we wrote previously.
But we have a slight problem. We need to pass in generic pointers to swap
but we need to use some pointer arithmetic. The problem is that without types, we can't really perform pointer arithmetic because the compiler does not know how many bytes it should advance the pointer. Thus, you must perform some additional operations.
For example, this would not work.
void swap_ends(void *arr, size_t nelems) {
swap(arr, arr + nelems – 1, sizeof(*arr));
}
First, we no longer know the element size. Second, pointer arithmetic depends on the type of data being pointed to (so it knows how many bytes to move). With a void *
, we lose that information!
So we must do some extra things:
- We need to know the size of each element in the array but we are only give the number of elements (e.g. the size of the array). So we should take in an additional parameter in that regard,
size_t elem_bytes
, that gives us the size of each element in bytes.
- So in sum, we want to be able to perform arithmetic in terms of bytes. But how do we tell C to do this? Remember the fundamental unit: chars. Thus, we cast the generic pointer to a char pointer and then perform the arithmetic.
So in sum we have:
void swap_ends(void *arr, size_t nelems, size_t elem_bytes) {
swap(arr, (char *)arr + (nelems – 1) * elem_bytes, elem_bytes);
}
As a recap, we calculated the number of bytes we need to move by multiplying the amount of elements we need to move (to get to the last element) by the size of each element. Then, we cast to a char pointer because a char is exactly one byte.
Pitfalls
- If you pass in the wrong size, then it may swap the first and middle element for example instead of the first and last.