Create a C function that accepts parameters of different data types

There is no standard function overloading in C (nor are there templates), but you could probably look into "printf-like" functions (or variadic functions) and maybe they can do what you need. If anything they allow for a flexible parameter list.

There is an example here of such a function that takes a variable size integer array.

Perhaps you could have a function signature such as void iterate(const char* format, ...); that you use in the following ways:

iterate("char", some_char_array); // for char arrays/strings

Or

iterate("int", some_int_array); // for integer arrays

Aniket makes a good point though, how do you count the elements in an integer array? If you pass an int array as an argument, you would need to pass the size too which defeats the purpose of counting the elements in the array (as you already know that i.e. the size).

I assume you don't know the size but you have a terminator value in the array (such as -1).

I've hacked something quick that kinda does what you need with the above assumption in mind.

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
 
int iterate(const char* format, ...)
{
    va_list ap;
    va_start(ap, format);

    if (strcmp(format, "char") == 0)
    {
        char* array = va_arg(ap, char*);

        va_end(ap);
        return strlen(array);
    }
    else if (strcmp(format, "int") == 0)
    {
        int j = -1;
        int* int_array = va_arg(ap, int*);
        while (int_array[++j] != -1)
                    ;   
        va_end(ap);  
        return j;
    }
    va_end(ap);
    return 0;
}

int main()
{
    printf("%d\n", iterate("char", "abcdef"));
    int arr[] = {5, 4, 3, 2, 1, 0, -1};
    printf("%d\n", iterate("int", arr));

    return 0;
}

This prints:

$ ./a.out 
6
6

So, let's assume your two functions are called sizeof_char_array and sizeof_int_array.

In C11, there is a new feature called "generic selection" that will let you do what you want with a relatively simple macro:

#define sizeof_array(X) \
    _Generic (*(X), \
              char: sizeof_char_array, \
              default: sizeof_int_array) (X)

(I don't even have a C11 implementation to test this against, so caveat emptor!)

Prior to C11, this was sometimes accomplished with a macro using regularly named functions. You can define a macro that will call one function or the other depending on a macro argument hint:

#define sizeof_array(xtype, x) sizeof_ ## xtype ##_array(x)

int a[] = { 1, 2, 3, 4, -1 };
char b[] = "abc";

sizeof_array(int, a);   /* macro expands to sizeof_int_array(a) */
sizeof_array(char, b);  /* macro expands to sizeof_char_array(b) */

If the input argument is truly an array, you can use a macro to compute its size directly:

#define ARRAY_SZ(x) (sizeof(x)/((void *)x == &x ? sizeof(x[0]) : 0))

In the case of an array, the following expression is true:

(void *)arr == &arr

Because the address of an array has the same location in memory as the address of its first element.

So, the macro computes: sizeof(arr)/sizeof(arr[0]). Since the sizeof operator reports the size in bytes of its argument, the computed expression results in the number of elements in the array. However, if you are using a sentinel to compute the length, the ARRAY_SZ macro will result in a size at least one larger than the length found traversing the array for the sentinel.

In the case that the argument is not an array, then the expression results in a divide by 0 exception.

Tags:

C

Function