Function Pointers

Void * Pitfalls

  • void *s are powerful, but dangerous - C cannot do as much checking!
  • E.g. with int, C would never let you swap half of an int. With void *s, this can happen!
int x = 0xffffffff;
int y = 0xeeeeeeee;
swap(&x, &y, sizeof(short)); 
// now x = 0xffffeeee, y = 0xeeeeffff!
printf("x = 0x%x, y = 0x%x\n", x, y);

Stack Structs

Each node can no longer store the data itself, because it could be any size!
Instead, it stores a pointer to the data somewhere else.

typedef struct node {
    struct node *next;
    void *data;
} node;

typedef struct stack {
    int nelems;
    int elem_size_bytes;
    node *top;
} stack;

stack *stack_create(int elem_size_bytes) {
    stack *s = malloc(sizeof(stack));
    s->nelems = 0;
    s->top = NULL;
    s->elem_size_bytes = elem_size_bytes;
    return s;
}

void stack_push(stack *s, const void *data) {
    node *new_node = malloc(sizeof(node));
    new_node->data = malloc(s->elem_size_bytes);
    memcpy(new_node->data, data, s->elem_size_bytes);
    new_node->next = s->top;
    s->top = new_node;
    s->nelems++;
}

void stack_pop(stack *s, void *addr) {
    if (s->nelems == 0) {
        error(1, 0, "Cannot pop from empty stack"); 
    }
    node *n = s->top;
    memcpy(addr, n->data, s->elem_size_bytes);
    s->top = n->next; 
    free(n->data);
    free(n);
    s->nelems--;
}

Function Pointers

Definition: A function pointer is a variable that stores the address of a function. This allows functions to be passed as arguments to other functions.  

Syntax: The syntax for declaring a function pointer includes the return type and parameter types of the function it can point to.

return_type (*function_pointer_name)(parameter_types);

Generic Bubble Sort

// Comparison function for integers
int int_compare(const void *a, const void *b) {
    return *(int*)a - *(int*)b;
}

void bubble_sort(void *arr, int n, int elem_size_bytes, int (*compare_fn)(const void *, const void *)) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            void *a = (char *)arr + j * elem_size_bytes;
            void *b = (char *)arr + (j + 1) * elem_size_bytes;
            if (compare_fn(a, b) > 0) {
                // Swap elements
                char temp[elem_size_bytes];
                memcpy(temp, a, elem_size_bytes);
                memcpy(a, b, elem_size_bytes);
                memcpy(b, temp, elem_size_bytes);
            }
        }
    }
}

int main() {
    int nums[] = {5, 2, 9, 1, 5, 6};
    int n = sizeof(nums) / sizeof(nums[0]);
    bubble_sort(nums, n, sizeof(int), int_compare);
    for (int i = 0; i < n; i++) {
        printf("%d ", nums[i]);  // Output: 1 2 5 5 6 9
    }
    printf("\n");
    return 0;
}