Easy Tutorial
❮ These Pain Only Programmers Know C Dynamic Array ❯

Implementing Generic Programming in C Language

Category Programming Techniques void*.

Here is an example of a function swap that exchanges the contents of two elements, using int as an example:

void swap(int* i1, int* i2) {
    int temp;
    temp = *i1;
    *i1 = *i2;
    *i2 = temp;
}

When you want to swap two char types, you also need to rewrite a function with parameters of type char. Can you use a typeless pointer as a parameter? See the following modification:

void swap(void *vp1, void *vp2) {
    void temp = *vp1;
    *vp1 = *vp2;
    *vp2 = temp;
}

This code is incorrect and will not compile. First, variables cannot be declared as void typeless. Since you do not know what type of argument is passed into this function, you cannot determine a type declaration. At the same time, * cannot be used on a typeless pointer because the system does not have information about the size of the object pointed to by this address. At compile time, the compiler cannot determine the type of the argument passed into this function. To implement a generic function here, you need to pass in the size of the address space of the object to be exchanged at the call site, and use the memcpy() function defined in the header file string.h to implement it. The modification is as follows:

void swap(void *vp1, void *vp2, int size) {
    char buffer[size]; // Note that gcc compiler allows such a declaration
    memcpy(buffer, vp1, size);
    memcpy(vp1, vp2, size);
    memcpy(vp2, buffer, size);
}

When calling this function, you can call it like this (also applicable to other types of x, y):

int x = 27, y = 2;
swap(&x, &y, sizeof(int));

Now let's look at another function with a different functionality:

int lsearch(int key, int array[], int size) {
    for (int i = 0; i < size; ++i)
        if (array[i] == key)
            return i;
    return -1;
}

This function searches for the key element in the array, returns its index if found, and returns -1 if not found.

As above, a generic function can also be implemented:

void* lsearch(void* key, void *base, int n, int elemSize) {
    for (int i = 0; i < n; ++i) {
        void *elemAddr = (char *)base + i * elemSize;
        if (memcmp(key, elemAddr, elemSize) == 0)
            return elemAddr;
    }
    return NULL;
}

In the third line of the code: The array's first address is forcibly converted to a pointer of type char, taking advantage of the characteristic that the size of char is 1 byte, making elemAddr point to the first address of the i-th element of this "generic" array. As previously mentioned, at this time you do not know what type of data you are passing in, and the system cannot determine how long an element of this array is, how many bytes are needed to jump to the next element, so it is forcibly converted to a pointer of type char, plus the element size information passed in as a parameter and the product of the accumulated number i, that is, the offset address, to obtain the first address of the i-th element of this array. This makes it possible to get the correct element pointer regardless of what type of pointer is passed in, achieving generic programming.

The prototype of the function memcmp() is: int memcmp(void *dest, const void *src, int n), which compares the contents in the address spaces of lengths n with the first addresses dest and src.

This function searches for the key element in the array base, and returns its address information if found, or returns NULL if not found.

If you use a function pointer, you can achieve generic behavior:

void *lsearch(void *key, void *base, int n, int elemSize, int(*cmpfn)(void*, void*, int)) {
    for (int i = 0; i < n; ++i) {
        void *elemAddr = (char *)base + i * elemSize;
        if (cmpfn(key, elemAddr, elemSize) == 0)
            return elemAddr;
    }
    return NULL;
}

Define a function to be called:

``` int

❮ These Pain Only Programmers Know C Dynamic Array ❯