0

I am fairly new to programming languages and wonder if it is possible to pass an argument without specific type to a function. For instance I have the following piece of code that defines a funcion add that will take a block of memory, check it if is filled via another function, and then adds an element to the list related to that block of memory.

This element can be an int, a float or a char. So I would like to write:

add(arrs1,20); //or also
add(arrs2,'b'); //or also
add(arrs3, 4.5);

Where arrs# are defined by struct arrs arrs#, and they refer to arrays of either floats, ints or chars but not mixed. How could I accomplish this?

int add(arrs list, NEW_ELEMENT){//adds NEW_ELEMENT at the end of an arrs
  int check_if_resize;
  check_if_resize=resize(list, list->size + 1);
  list->ptr[list->used++] = NEW_ELEMENT;
  return check_if_resize;
}

I appreciate your help.

Vladimir Vargas
  • 1,744
  • 4
  • 24
  • 48
  • 4
    No, but some people will do this with a macro, or they'll take a `void*` (and memory size) and do a `memcpy` to write the data to the necessary location. – Cornstalks Dec 12 '14 at 23:25
  • @Cornstalks could you give me an example of this using a macro? do you mean something like defining add not as an int function, but rather as a macro, e.g. `#define add(list,NEW_ELEMENT) (here what?)`. – Vladimir Vargas Dec 12 '14 at 23:28
  • Isn't that the way `qsort()` works? Not only the data type, but its `compare()` function arguments. – Weather Vane Dec 12 '14 at 23:38
  • use glib and its variant objects if you *really* need to do this – kdopen Dec 12 '14 at 23:40
  • C is a *strongly typed* language but there are ways to defeat this by type casting. There are several previous SO questions on this topic, eg. http://stackoverflow.com/questions/2351190/static-dynamic-vs-strong-weak – Weather Vane Dec 12 '14 at 23:45

2 Answers2

5

C does, by design, not allow a single function to accept more than a single type for each argument. There are various ways to do something equivalent in C, though:

First and foremost, you can just write multiple different functions that do the same, but on different types. For instance, instead of add you could have three functions named add_int, add_char and add_float. I would recommend doing this in most cases, as it is by far the easiest and least error-prone.

Secondly, you might have noticed how printf can print both strings and numbers? So-called variadic functions, like printf, can take different types of arguments, but in the case of printf, you must still specify the type of arguments you want in the format string.

Finally, you can use void pointers if you need to work with the memory an object occupies, regardless of its type. Functions like memcpy and memset do this, for instance to copy the contents of one object directly to another. This is a bit harder to manage properly, as it is easy to make mistakes and end up corrupting memory, but its still doable (and sometimes even the best option).

But if you're a beginner in C, as you state you are, the first option is probably the easiest, especially when dealing with only a few different data types (in this case, three).

Frxstrem
  • 38,761
  • 9
  • 79
  • 119
  • 1
    I'd add that if you want to do anything (beyond treating it bytewise) with the data pointed to by a void pointer you must provide some kind of runtime type information, e.g. an enum as a type tag or such, because C does not have intrinsic runtime type information, i.e. memory carries no information about how to interpret its contents. – Peter - Reinstate Monica Dec 12 '14 at 23:59
  • `#define ADD(list,new_element) (*(list->ptr+list->used++)=new_element)` why wouldn't this work? – Vladimir Vargas Dec 13 '14 at 00:29
  • @NotStrang That could work, but because `new_element` would be cast into the type of `*(list->ptr)`, you might have loss of information. For instance, if `new_element` is a `float` and `list->ptr` is of type `int*`, then `new_element` would be cast into an `int`, losing all its fractional digits. – Frxstrem Dec 13 '14 at 00:37
  • and if list->ptr is of type void*? – Vladimir Vargas Dec 13 '14 at 00:59
  • 1
    @NotStrang That's not valid C; you cannot do addition with a `void*`, and you cannot dereference `void*` anyway (since `void` isn't really a normal type, but rather the lack thereof). – Frxstrem Dec 13 '14 at 01:01
  • Sorry, I confused C and C++ there (might be why I stuck with Ruby all these days!) – jackyalcine Dec 13 '14 at 01:18
1

You can pass pretty much anything as a void * in a function that will add this content to a linked list by the use of memcpy (or even safe memmove). As long as you have a pointer to the next node of your list, you don't have to worry about the type of the stored data. Just be sure not to dereference a void *, but rather to cast it and use this casted variable (as a char if you want to work on this data byte by byte for instance)

cfz42
  • 384
  • 1
  • 14