How to avoid passing "redundant" arguments in function? - c

I was writing some code and I realised that I kept on passing arguments to functions when the function didn't use the argument. Only the sub-function with the function( or the sub-sub-function within the sub-function and so on...) used it.
The actual function never used the arguments at all, it's only purpose was to "relay" the arguments to the sub-function(or the sub-sub-function and so on)
Eg:
int search(int (*board)[DIM],int search_digit,int * bestRow,int *bestCol)
{
//some code,haven't use arguments bestRow,bestCol
longest=seq_length( board,longest,search_digit,bestRow,bestCol,r,c); //sub-function
//some code,haven't use arguments bestRow,bestCol
}
int seq_length(int board[][DIM],int longest,int search_digit,int * bestRow,int *bestCol,int row,int col)
{
//some code,haven't use arguments bestRow,bestCol
longest=updateLongest_best(bestRow,bestCol,longest,seqLength,row,col); //sub-sub-function
//some code,haven't use arguments bestRow,bestCol
}
int updateLongest_best(int* bestRow,int *bestCol,int longest,int seqLength,int row,int col)
{
//finally used arguments bestRow,bestCol
}
Is there an elegant way to circumvent the passing of redunant arguments? Or is this just inherent part of C?

Converting my comment into an answer.
The 'obvious' alternative is to 'pass' those variables via a global variable. This is not (repeat, NOT) a good idea — the code as written is better.
If you have two or more arguments that are relayed from one function to another (as here), you could consider combining them into a structure that is passed by pointer so there's only one direct argument to each called function.
Note that if the functions that are called from a sub-function need the information passed to the calling function by the user, then the arguments are not 'redundant'; they're necessary, even if verbose.
In outline:
typedef struct BestInfo
{
int row;
int col;
} BestInfo;
int search(int (*board)[DIM], int search_digit, BestInfo *best)
{
// some code; doesn't use argument best
longest=seq_length(board, longest, search_digit, best, r, c); //sub-function
// some more code; doesn't use argument best
}
int seq_length(int board[][DIM], int longest, int search_digit, BestInfo *best, int row, int col)
{
// code that doesn't use argument best
longest = updateLongest_best(best, longest, seqLength, row, col); //sub-sub-function
// more code that doesn't use argument best
return …;
}
int updateLongest_best(BestInfo *best, int longest, int seqLength, int row, int col)
{
// Finally use argument best: best->row, best->col
// You can split the structure when appropriate
int r1 = one_more_function(&best->row);
int r2 = another_function(&best->col);
return computation_using(r1, r2);
}

Related

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

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.

How to convert array to arguments for a function in C?

void test(int a,int b,int c)
{
printf("%d;%d;%d\n",a,b,c);
}
void run(void(*function)(int,int,int),int[] args,int sizeArgs)
{
function(#passing args);
}
run(test,(int[]){4,6,9});
I need a function like run that accepts another function and an array of arguments. It is necessary that the run function enumerates arguments and then calls the passed function.
You could tweak the function to the following:
typedef void func3_t (int, int, int);
...
void run (func3_t* func, int size, const int args[size])
The function pointer syntax in C is hard to read, so therefore use typedef. The typedef here declares a function type and then we let the function take a function pointer to such a function.
I changed the args to const since they shouldn't be modified, this is called const correctness and is overall good practice. By placing the size parameter before the array, we can let the array refer to that variable. (This gives a pointer to a variable-length array, VLA.)
The function body would be trivial, just do some error check and otherwise leave it to the caller to provide the correct array size:
if(size==3)
{
func(args[0], args[1], args[2]);
}
Here's a complete example:
#include <stdio.h>
typedef void func3_t (int, int, int);
void test(int a, int b, int c)
{
printf("%d;%d;%d\n",a,b,c);
}
void run (func3_t* func, int size, const int args[size])
{
if(size==3)
{
func(args[0], args[1], args[2]);
}
}
int main (void)
{
run(test, 3, (int[]){4,6,9});
}
If code such as this is meaningful, well that's another story...
To create a completely variadic function which is also type safe... well, I would consider changing the program design first of all, because it likely does not make any sense. You could replace the function with a very evil macro such as this:
// BAD IDEA
#define run(func, ...) _Generic(&(__VA_ARGS__), \
int(*)[3]: _Generic((func), void(*)(int,int,int): (func)) ) \
(__VA_ARGS__[0], __VA_ARGS__[1], __VA_ARGS__[2])
int main (void)
{
run(test, (int[]){4,6,9});
}
This is actually type safe and can be expanded to support other function types... but if you are a C beginner then forget all about this macro, since it is using some rather advanced language features.
The array can be passed as an agrument to a function by just passing the name of array.
int a[];---> array
fun(a);--->function calling
so we are actually passing the base address of the array.

How can I implement a function lookup table in C?

Say I had a program where the user could select a number between 0-10. Each number would then correspond to the calling of a certain function. In Python, I know I could just create an array of function names, index into it with the selected option, and then call the function. How would I implement this in C? Or is it even possible?
Here is an example how to do it. Please note that all functions must have the same signature, but of course you can change that from my funptr type to for example a function that has void return or takes a char and not two ints.
// Declare the type of function pointers.
// Here a function that takes two ints and returns an int.
typedef int (*funptr)(int, int);
// These are the two functions that shall be callable.
int f1(int a, int b) { return a + b; }
int f2(int a, int b) { return a - b; }
// The array with all the functions.
funptr functions[] = {
f1,
f2,
};
// The caller.
int call(int i, int a, int b)
{
return functions[i](a, b);
}
The only problem that I can see in the solution from above is that there is no check for the array index (you may get some tricky problems).
To make the code more robust, you can add a check for the index (boundaries), like
add one if statement inside of function "call" where you check the parameter i (not to be bigger than the maximum value)

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).

How to define an array of function pointers and the functions don't have same input argument definition?

Is it possible to define an array of function pointers (and the functions don't have se same input argument ) as indicating in the following code ?
If yes what I have to put in the function definition int (*handler)(/*what Ihave to put here ?*/);
struct handler_index {
const char *name;
int (*handler)(/*what Ihave to put here ?*/);
};
int handler0 (int a, int b)
{
printf("%d\n",a+b);
}
int handler1 (int a, int b, int c)
{
printf("%d\n",a+b+c);
}
int handler2 (int a, int b, int c, int d)
{
printf("%d\n",a+b+c+d);
}
const struct handler_index handler_index[] = {
[0] = {"handler0", handler0},
[1] = {"handler1", handler1},
[2] = {"handler2", handler3},
};
Just put nothing:
int (*handler)();
it means the function has an unspecified (but non-variable) number and types of parameters.
Any function that returns an int and with a fixed variable number of parameters can be assigned to handler.
Whilst int (*handler)() will indeed allow variable number of arguments for th function, I fail to see any benefit in this. Function pointers are useful when you have a piece of code that takes something, finds the "right thing to do" (e.g comparing the "name" with some input from elsewhere), and calls the function pointer to do whatever it has to do. The function pointer calling code needs to know how many arguments the function has (how else would it pass the right number and order of arguments.
I don't actually see any meaningful use of this at all. Yes, you can pass a variable number of arguments to a function, but the code HAS to know what arguments the function takes.
Unless the arguments are somehow specified in the definition of the struct - but then you need to define different content for the struct to allow for that.
I would suggest that you need to think about what you are trying to achieve, and then come up with a solution to the problem, most likely using a different method.
Put nothing. Just empty brackets.
int (*handler)();

Resources