How to pass each value of an array as parameters to a function? - arrays

I have the following function that accepts a varying number of integer parameters and returns the sum.
int sum(int a, ...){
va_list nums;
va_start(nums, a);
int res=0;
for(int i=0; i<a; i++) {
res += va_arg(nums, int);
}
va_end(nums);
return res;
}
I need to pass each value of the array as a parameter to the function rather than passing the array itself. The array can be of varying length leading to a varying length of arguments to pass too.
printf("The sum is: %d", sum(size, args[0], args[1], ```need all elements of args[] array here```));
To put forth some perspective, I'm using this sum function to understand how I can go about doing this. It would be helpful to know how to achieve this in a more general setting rather than this exact function.
Please let me know if you need any more information.
Please do look at this question, which is similar, however, I require a solution in C.

The short answer is that there's no way to do exactly this in the C language. There is no ES6-like spread operator in C, nor similar functionality. I don't think there's any particular reason why they couldn't (you would just have to push more arguments onto the stack); they just never made one.
However, there are various other things you can do:
If variadic arguments were already passed into the function calling your function, you can pass along the va_list to a function declared to take a va_list. See Passing variable arguments to another function that accepts a variable argument list
As #JonathanLeffer suggests, the most natural way to write this code in C is by constructing an array of what "would be" your variadic arguments, and passing that into a function that expects an array (well, technically, a pointer, because arrays decay to pointers). For example:
int sum_array(int a, int nums[]){
int res=0;
for(int i=0; i<a; i++) {
res += nums[i];
}
return res;
}
In certain circumstances, it may be more convenient for a function like sum_array to take only the nums array/pointer, which would itself indicate the end of the array with a 0 or -1 value in the last slot. This is just another convention for indicating the end, which the caller has to set up.
You could then, if you really wanted to, write a variadic function that collects its arguments into an array and calls sum_array, if you want a variadic version as well. (Of course, you could also just implement the variadic and array versions separately, but for nontrivial functions it may be a pain to implement them twice.)
int sum_variadic(int a, ...){
va_list nums;
va_start(nums, a);
int arr[a];
for(int i=0; i<a; i++) {
arr[i] = va_arg(nums, int);
}
va_end(nums);
return sum_array(a, arr);
}
you could also use a variadic macro for the same purpose:
#define sum_macro(size, ...) sum_array(size, (int[]){__VA_ARGS__})
In summary: going from variadic to array in C is trivial, going from array to variadic is impossible.
You can also use extensions to the C language to do it anyway, as described in Passing a dynamic set of variadic arguments to a C function and In C, given a variable list of arguments, how to build a function call using them?, which #KamilCuk linked to.

You can avoid passing the number of arguments explicitly by using a variadic macro that constructs a compound literal array instead of a vararg function:
#include <stdio.h>
#define sum_int(...) (sum_int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int), (int[]){__VA_ARGS__})
int (sum_int)(size_t count, const int *a) {
int sum = 0;
for (size_t i = 0; i < count; i++) {
sum += a[i];
}
return sum;
}
int main() {
printf("sum = %d\n", sum_int(1, 2, 3));
return 0;
}
This approach can be used for any purpose, as long as the types of the variable arguments are converted implicitly to the array type.
If you want to pass just the arguments to your sum function without changing its definition, you can use a variation of the macro:
#include <stdio.h>
int sum(int a, ...) {
va_list nums;
va_start(nums, a);
int res = 0;
for (int i = 0; i < a; i++) {
res += va_arg(nums, int);
}
va_end(nums);
return res;
}
#define sum(...) (sum)((int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int)), __VA_ARGS__)
int main() {
printf("sum = %d\n", sum(1, 2, 3));
return 0;
}
Note however that there is no type checking with this approach and sum(1, 2.0, 3) would have undefined behavior.

Related

Passing list as a parameter to a function in c

I want to pass multiple values as a comma separated list to a function and accepting that list into an array variable. Something like(though it is not compilable):
#include <stdio.h>
void passValueAsList (int arr [],int len) {
int i;
for (i=0;i <len;i++)
printf ("%d, ",arr [i]);
}
int main () {
passValueAsList ({1,2,43,5,4,21},6);
return 0;
}
I don't want to store list into array before passing rather I just want to pass array in place.
Thanks.
You can use compound literals. to pass an array like that.
ISO C99 supports compound literals. A compound literal looks like a cast containing an initializer. Its value is an object of the type specified in the cast, containing the elements specified in the initializer; it is an lvalue.
#include <stdio.h>
void passValueAsList (int arr [],int len) {
int i;
for (i=0;i <len;i++)
printf ("%d, ",arr [i]);
}
int main () {
passValueAsList ((int []) {1,2,43,5,4,21}, 6);
return 0;
}
passValueAsList ({1,2,43,5,4,21},6);
This is invalid C syntax, plain and simple.
The correct syntax is:
#include <stdio.h>
void passValueAsList (int arr [], size_t len) {
size_t i;
for (i=0;i <len;i++)
printf ("%d, ",arr [i]);
}
int main () {
int arr[] = {1,2,43,5,4,21};
passValueAsList(arr, sizeof arr / sizeof *arr);
return 0;
}
edit
C99 introduces compound literals, so this would be also
possible:
#include <stdio.h>
void passValueAsList (int arr [], size_t len) {
size_t i;
for (i=0;i <len;i++)
printf ("%d, ",arr [i]);
}
int main () {
passValueAsList((int[]){1,2,43,5,4,21}, 6);
return 0;
}
I don't want to store list into array before passing rather i just want to pass it into array. As storing may take some space in the memory and that's why i wanna pass as comma seperated list.
Note that even with the compound literals the array will be still stored
somewhere in memory, passValueAsList gets still a pointer to the start of the
location of the array. The only difference with the previous code is that you
don't have a variabe in the main function.
The assembly of both versions is identical.
With C, you can do that with a variable argument list:
https://www.tutorialspoint.com/c_standard_library/c_macro_va_arg.htm
But you have to somehow have a marker so that the function you're calling knows when to stop pulling items off of the call stack.
Your example calling code, as written, requires C++. In C++11, you can have the function take a std::vector as a parameter, and pass the values as in your example calling code.

qsort() can't understand the detail in C

Why when we use qsort(), int(*compar)(const void*,const void*) haven't add any paraments in, but can also do their functions?
Such as this :
double vals[NUM];
qsort(vals,NUM,sizeof(double),mycomp);
When you append parenthesis to the identifier representing a function, with a list of parameters between, you're calling the function.
In this case, you don't want to call the function, however. You want qsort to call the function to determine whether or not one element is larger or smaller than the other.
It seems you are asking about function pointers in general.
Here is a simple example of function pointer:
int compare(int i, int j)
{
return i > j ? i : j;
}
void process(int i, int j, int(*pfunc)(int, int))
{
printf("%d\n", pfunc(i, j));
}
int main(void)
{
process(1, 2, compare);
return 0;
}
In this example process is sort of like qsort, while compare is the function which we define ourselves. We need to tell qsort how to compare data, but we can't access qsort directly, so pass our own function to it which tells qsort how to compare.
qsort is generic. It doesn't know what type of data it is processing, so it can't simply compare elements using <. What it does instead is let you, the programmer, give it a function to use to compare elements. So, yes you do care about how mycomp works, you need to define it.
int mycomp(const void *a, const void *b) {
const double *lhs = a;
const double *rhs = b;
if (*lhs < *rhs) return -1;
if (*lhs > *rhs) return 1;
return 0;
}
inside of qsort, every time it needs to compare two elements it will pass them to your mycomp function and examine the result. If you define it wrong, your array will be incorrectly arranged (unsorted).

Create a C function that accepts parameters of different data types

I'm relatively new to the C programming language, and I'm trying to figure out how to create a function that can accept different types of data as parameters. The function is supposed to count and return the number of elements in a character or integer array. I already have two separate functions that will do this, but I would really like to be able to use one function for both tasks. Is there a way to do this in C?
Thanks in advance!
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.
The answer is quite simple. You do need a function for this task. Just try this piece of code
#define len(array) sizeof(array)/sizeof(*array)
and that's it.
Important note: As pointed out in the comments, this will not work for dynamically allocated arrays.
You should make your function arguments take in a void * type. This way, you can pass in different types of data, and type-cast it to the one you want. However, you do need to watch out because there is no guaranteed way to correctly 'guess' the type that a void* points to.
In either case, you will need some sort of type-inferencing system to tell the C compiler which function to call. Which means, you will need to know, before-hand the type of array you might send in as a parameter to this "super function" of yours.
There is no "auto-type-inferencing" in C that can let you reflect upon the type of data at runtime. Better yet, you might have to write your own runtime environment for this to happen.
A slightly trivial hackish way to do this:
#include <stdio.h>
size_t GetLengthOfArray(size_t sizeOfOneElementInArray, size_t sizeOfTheArrayInBytes)
{
return sizeOfTheArrayInBytes/sizeOfOneElementInArray;
}
int main(int argc, char *argv[])
{
char cArr[10] = {'A','B','C','D','E','F','G','H','I','J'};
int iArr[5] = {10,20,30,40,50};
printf("%d is the length of cArr\n%d is the length of iArr",GetLengthOfArray(sizeof(cArr[0]),sizeof(cArr)),
GetLengthOfArray(sizeof(iArr[0]),sizeof(iArr)));
return 0;
}
It's not really possible, but you can make a tagged union
typedef struct {
union {
ssize_t i;
double d;
char *s;
} unknown;
char identity;
} Dynamic;
Or you can use a void pointer:
typedef struct {
void *unknown;
char identity;
} Dynamic;

All the array length methods in C don't work

I have tried (sizeof(array)/sizeof(array[0])). Didn't work.
I wrote a simple function:
int length(int array[]){
int i=0;
while(array[i]) i++;
return i;
}
Worked one minute, didn't work the next.
Someone please help! I'm using Xcode as an IDE
The length of an array is not part of the array in C, so when passing an array as a parameter to a function you should pass its length as a parameter too. Here's an example:
#define ARRLEN(a) (sizeof(a)/sizeof (a)[0]) /* a must be an array, not a pointer */
void printarray(int* a, int alen)
{
int i;
for (i = 0; i < alen; i++)
printf("%d\n", a[i]);
}
main()
{
int a[] = { 3, 4, 5 };
printarray(a, ARRLEN(a));
return 0;
}
However, if your array is defined in such a way as to always end with a sentinel that isn't normal data, then you can traverse the elements until you encounter the sentinel. e.g.,
void printstrings(char** a)
{
int i;
for (i = 0; a[i]; i++)
printf("%s\n", a[i]);
}
main()
{
char* a[] = { "This", "should", "work.", NULL };
printstrings(a);
return 0;
}
Passing an array into a function is the same as passing a pointer to the array.
So sizeof(array)/sizeof(array[0]) does not work.
You can define a global macro:
#define A_LEN(a) (sizeof(a)/sizeof(a[0]))
Try this
main()
{
int a[10] ;
printf("%d\n", sizeof(a)/sizeof(int) ) ;
}
output : 10
See Why doesn't sizeof properly report the size of an array when the array is a parameter to a function? from the comp.lang.c FAQ to understand why the sizeof method doesn't work. You probably should read the entire section on arrays.
Regarding your length function, your "simple" function can work only if your array happens to have the semantic that it is terminated with an element that has the value of 0. It will not work for an arbitrary array. When an array has decayed into a pointer in C, there is no way to recover the size of the array, and you must pass along the array length. (Even functions in the C standard library are not immune; gets does not take an argument that specifies the length of its destination buffer, and consequently it is notoriously unsafe. It is impossible for it to determine the size of the destination buffer, and it therefore cannot prevent buffer overflows.)
There are several methods to get the length of array inside a function (can be in the same file or in different source file)
pass the array length as a separate parameter.
make array length as global extern so that function can directly access global data

Do C functions support an arbitrary number of arguments?

PHP has a func_get_args() for getting all function arguments, and JavaScript has the functions object.
I've written a very simple max() in C
int max(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
I'm pretty sure in most languages you can supply any number of arguments to their max() (or equivalent) built in. Can you do this in C?
I thought this question may have been what I wanted, but I don't think it is.
Please keep in mind I'm still learning too. :)
Many thanks.
You could write a variable-arguments function that takes the number of arguments, for example
#include <stdio.h>
#include <stdarg.h>
int sum(int numArgs, ...)
{
va_list args;
va_start(args, numArgs);
int ret = 0;
for(unsigned int i = 0; i < numArgs; ++i)
{
ret += va_arg(args, int);
}
va_end(args);
return ret;
}
int main()
{
printf("%d\n", sum(4, 1,3,3,7)); /* prints 14 */
}
The function assumes that each variable argument is an integer (see va_arg call).
Yes, C has the concept of variadic functions, which is similar to the way printf() allows a variable number of arguments.
A maximum function would look something like this:
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
static int myMax (int quant, ...) {
va_list vlst;
int i;
int num;
int max = INT_MIN;
va_start (vlst, quant);
for (i = 0; i < quant; i++) {
if (i == 0) {
max = va_arg (vlst, int);
} else {
num = va_arg (vlst, int);
if (num > max) {
max = num;
}
}
}
va_end (vlst);
return max;
}
int main (void) {
printf ("Maximum is %d\n", myMax (5, 97, 5, 22, 5, 6));
printf ("Maximum is %d\n", myMax (0));
return 0;
}
This outputs:
Maximum is 97
Maximum is -2147483648
Note the use of the quant variable. There are generally two ways to indicate the end of your arguments, either a count up front (the 5) or a sentinel value at the back.
An example of the latter would be a list of pointers, passing NULL as the last. Since this max function needs to be able to handle the entire range of integers, a sentinel solution is not viable.
The printf function uses the former approach but slightly differently. It doesn't have a specific count, rather it uses the % fields in the format string to figure out the other arguments.
In fact, this are two questions. First of all C99 only requires that a C implementation may handle at least:
127 parameters in one function
definition
127 arguments in one function call
Now, to your real question, yes there are so-called variadic functions and macros in C99. The syntax for the declaration is with ... in the argument list. The implementation of variadic functions goes with macros from the stdarg.h header file.
here is a link to site that shows an example of using varargs in c Writing a ``varargs'' Function
You can use the va_args function to retrieve the optional arguments you pass to a function. And using this you can pass 0-n optional parameters. So you can support more then 2 arguments if you choose
Another alternative is to pass in an array, like main(). for example:
int myfunc(type* argarray, int argcount);
Yes, you can declare a variadic function in C. The most commonly used one is probably printf, which has a declaration that looks like the following
int printf(const char *format, ...);
The ... is how it declares that it accepts a variable number of arguments.
To access those argument it can uses va_start, va_arg and the like which are typically macros defined in stdarg.h. See here
It is probably also worth noting that you can often "confuse" such a function. For example the following call to printf will print whatever happens to be on the top of the stack when it is called. In reality this is probably the saved stack base pointer.
printf("%d");
C can have functions receive an arbitrary number of parameters.
You already know one: printf()
printf("Hello World\n");
printf("%s\n", "Hello World");
printf("%d + %d is %d\n", 2, 2, 2+2);
There is no max function which accepts an arbitrary number of parameters, but it's a good exercise for you to write your own.
Use <stdarg.h> and the va_list, va_start, va_arg, and va_end identifiers defined in that header.
http://www.kernel.org/doc/man-pages/online/pages/man3/stdarg.3.html

Resources