5

Whenever we use variable argument function in C language, we have to provide the total number of arguments as the first parameter. Is there any way in which we can make a function with variable arguments without giving the total number of arguments?


[update from comment:]

I want to use functions like sum(1,2,3) should return 6. i.e, no counter should be there.

9
  • gnu.org/software/libc/manual/html_node/… Check this example. Commented Oct 5, 2018 at 10:10
  • 1
    @ameyCU Isn't the first parameter count exactly what the OP wants to avoid? Commented Oct 5, 2018 at 10:13
  • 3
    You are free to make up any (in)sane logic the called function can use to learn if there is a next argument and which of type this will be. To do so you need to at least pass one argument. Commented Oct 5, 2018 at 10:23
  • 4
    @500-internal-server-error: An obvious way around passing the number of arguments explicitly is passing the number of arguments implicitly. And there are multiple ways of doing that, including implied by a format string (as printf does), implied by other parameters (e.g. some value parameter is needed if and only if an earlier parameter has a particular option flag set), or held in global state. Commented Oct 5, 2018 at 10:31
  • 2
    @500-InternalServerError In C you need at least one fixed argument. This does not have to be a counter. Calling a function like this is perfectly fine: myfunc(0, "first","second","last",NULL); Commented Oct 5, 2018 at 10:33

5 Answers 5

7

Several ways:

  • pass simple, explicit count (which you don't want in this question)
  • pass some format string, similar to printf and scanf
  • pass some "mode" parameter, and have each mode require specific varargs
  • have all varargs to be of same type, and require last argument to be some special value, AKA sentinel value, such as NULL for pointer list or max/min value of the type for integer types, or NaN for doubles.

However you do it, you have to have some way for the function to know the types of the varargs, as well as a way for it to know when they end. There is no built-in way in C, argument count is not passed to the function.

Sign up to request clarification or add additional context in comments.

1 Comment

The problem is that I don't want to specify the number of arguments. e.g sum(1,2,3) should return 6 while sum(1,2) should return 3
5

I want to use functions like sum(1,2,3) should return 6. i.e, no counter should be there

You could define a sentinel. In this case 0 might make sense.

/* Sums up as many int as required. 
   Stops adding when seeing the 1st 0. */
int sum(int i, ...)
{
  int s = i;

  if (s)
  {
    va_list ap;

    va_start(ap, i); 

    /* Pull the next int from the parameter list and if it is
       equal 0 leave the while-loop: */
    while ((i = va_arg(ap, int))) 
    {
      s += i;
    }

    va_end(ap);
  }

  return s;
}

Call it like this:

int sum(int i, ...);

int main(void)
{
   int s = sum(0); /* Gives 0. */

   s = sum(1, 2, 3, 0); /* Gives 6. */
   s = sum(-2, -1, 1, 2, 0); /* Gives 0. */
   s = sum(1, 2, 3, 0, 4, 5, 6); /* Gives 6. */

   s = sum(42); /* Gives undefined behaviour! */
}

The sum() function alternatively could also look like this (but would do one useless addition of 0):

/* Sums up as many int as required. 
   Stops adding when seeing the 1st 0. */
int sum(int i, ...)
{
  int s = i;

  if (s)
  {
    va_list ap;

    va_start(ap, i); 

    /* Pull the next int from the parameter list and if it is
       equal 0 leave the do-loop: */
    do
    {
      i = va_arg(ap, int);
      s += i;
    } while (i);

    va_end(ap);
  }

  return s;
}

4 Comments

@ShubhamKumar: Sry, fixed.
@ShubhamKumar: Try the code as is now, I had to fix it again. It now does what it should.
Thank you it works now.. can you elaborate what this statment does here "while ((i = va_arg(ap, int)))"
@ShubhamKumar: Please see the comment I added to the code.
4

You don't have to supply that number of arguments. For instance, consider the signature for printf:

int printf( const char* format, ... );

It "finds out" how many arguments it needs by parsing the string you give it. Of course, your function needs to know the amount of arguments in some way, otherwise what sense does it make for it to take a variable number of arguments?

Comments

0

It is possible to create a variadic function which takes a count as the first argument, then use variadic macros to add the count value automatically:

#include <stdarg.h>

#define count_inner(a1, a2, a3, a4, a5, num, ...)  (num)
#define count(...)                                 count_inner(__VA_ARGS__, 5, 4, 3, 2, 1)
#define sum(...)                                   sum_func(count(__VA_ARGS__), __VA_ARGS__)

int sum_func(int count, ...)
{
    va_list ap;
    va_start(ap, count); 

    int total = 0;
    while(count--)
        total += va_arg(ap, int);

    va_end(ap);

    return total;
}

Using the sum macro instead of sum_func allows the count to be omitted, provided there are between 1 and 5 arguments. More arguments/numbers can be added to the count_inner/count macros as required.

int main(void)
{
    printf("%d\n", sum(1));
    printf("%d\n", sum(1, 2));
    printf("%d\n", sum(1, 2, 3));
    printf("%d\n", sum(1, 2, 3, 4));
}

Output:

1
3
6
10

Comments

0

Well, the problem is that you have to somewhat indicate to the function that your argument list is exhausted. You've got a method from printf(3) which is that you can express the order and the type of arguments in your first parameter (forced to be a string arg) you can express it in the first parameter, or, for the adding, as the value 0 doesn't actually add to the sum, you can use that value (or some other at your criteria) to signal the last parameter. For example:

int sum(int a0, ...)
{
    int retval = a0;
    va_list p;
    va_start(p, a0);
    int nxt;
    while ((nxt = va_arg(p, int)) != 0) {
        retval += nxt;
    }
    return retval;
}

This way, you don't have to put the number of arguments as the first parameter, you can simply:

total = sum(1,2,3,4,5,6,7,8,9,10,0);

But in this case you have to be careful, that you never have a middle parameter equal to zero. Or also you can use references, you add while your reference is not NULL, as in:

int sum(int *a0, ...)
{
    int retval = *a0;
    va_list p;
    va_start(p, a0);
    int *nxt;
    while ((nxt = va_arg(p, int*)) != NULL) {
        retval += *nxt;
    }
    return retval;
}

and you can have:

int a, b, c, d, e, f;
...
int total = sum(&a, &b, &c, &d, &e, &f, NULL);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.