I'm reading about how to pass optional arguments to function. But I'm unable to understand those. When I see examples, they are confusing and a bit complex. So I just started with a very simple program with what I have understood up to now.
The below program just prints the variables.
void print(int x, ...)
{
va_list ap;
int i = 4; // I know I'm passing only 4 opt variables.
int num;
va_start(ap, x);
while(i--) { // How to know how many variables came in real time?
num = va_arg(ap, int);
printf("%d\n", num);
}
va_end(ap);
return;
}
int main()
{
print(1,2,3,4,5);
return 0;
}
I don't know above program is right or not. But it's working. When I change the i value to 5 printing garbage. How to know how many arguments I got (like argc in main)?
There is no way of knowing how many arguments are passed from inside a variable-argument function, that's why functions such as printf are using special format strings that tells the function how many arguments to expect.
Another way is of course to pass the number of "extra" arguments as the first argument, like
print(4, 1, 2, 3, 4);
Or to have a special value that can't be in the list as last argument, like
print(1, 2, 3, 4, -1);
You also have to take note that the last non-va argument you pass to the function (the argument named num in your case) is not included in the va_list, so in your case with the shown code with 4 as hardcoded number of arguments you will still print garbage, as you pass 1 for the num argument and then three va_list arguments.
Also take care because you use num as both argument and a local variable name.
You can take a look to NARGS macro
Adapted to your code:
#include <stdio.h>
#include <stdarg.h>
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define print(...) fnprint(NARGS(__VA_ARGS__), __VA_ARGS__)
void fnprint(int n, ...)
{
va_list ap;
int num;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
printf("%d\n", num);
}
va_end(ap);
return;
}
int main(void)
{
print(1, 2, 3, 4, 5);
return 0;
}
EDIT:
If you want to use the same name for macro and function, use () to stop the preprocessor from expanding the function definition:
#define print(...) print(NARGS(__VA_ARGS__), __VA_ARGS__)
void (print)(int n, ...) /* Note () around the function name */
{
...
EDIT 2: Another (ugly) method (but without restriction in the number of args) using compound literals (std 99) and sizeof:
#include <stdio.h>
#include <stdarg.h>
#define print(...) print(sizeof((int []) {__VA_ARGS__}) / sizeof(int), __VA_ARGS__)
void (print)(int n, ...)
{
va_list ap;
int num;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
printf("%d\n", num);
}
va_end(ap);
return;
}
int main(void)
{
print(1, 2, 3, 4, 5);
return 0;
}
print is expanded to:
print(sizeof((int []) {1, 2, 3, 4, 5}) / sizeof(int), 1, 2, 3, 4, 5);
But constructions like print(1, 2, 3, a_var++, 4, 5); or print(1, 2, some_func_returning_int(), 4, 5); evaluates a_var++ and some_func_returning_int() two times, thats a big problem.
Another ugly way for both int and strings:
#include <stdio.h>
#include <stdarg.h>
#define print(...) fnprint("{" # __VA_ARGS__ )
fnprint(char *b) {
int count = 0, i;
if (b[1] != '\0') {
for (i =2; b[i]; i++) {
if (b[i] == ',')
count++;
}
count++;
}
printf("\ncount is %i\n", count);
}
int main(void)
{
print();
print("1", "2");
print(1, 2, 3, 4, 5);
return 0;
}
Related
I would like to make a function that can take a variable number of parameters at once to do something like this:
void function(char *args[]){ ... }
int main(){
function("a","b","c");
}
You are looking for Variadic functions.
Check this example:
#include <stdio.h>
#include <stdarg.h>
double average(int num, ...) {
va_list valist;
double sum = 0.0;
int i;
/* initialize valist for num number of arguments */
va_start(valist, num);
/* access all the arguments assigned to valist */
for (i = 0; i < num; i++) {
sum += va_arg(valist, int);
}
/* clean memory reserved for valist */
va_end(valist);
return sum/num;
}
int main(void) {
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2, 3, 4, 5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5, 10, 15));
}
Output:
Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000
Read more in Variadic Functions in C and the Reference.
Tip: Think twice before using Variadic functions. As #user694733 commented, they have no compile time type safety or protection against invalid number of arguments. They can usually be avoided with better program design.
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.
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.
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;
}
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?
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
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);
I am trying to convert some Java code into C. The Java code goes like this:
public static int minimum( int... minimum ) {
assert( minimum.length > 0 );
if ( minimum.length > 0 )
.... // some code that i am able to translate to C without any hassle
}
Now I understand how to have varargs in C by using the stdarg.h header and using the macros provided. However I am stuck doing the minimum.length part.
I have tried strlen but the terminal is giving me an incompatible integer to pointer conversion warning. Is there any way in C where I can replicate the same thing that Java does?
Not directly, as pointed out by #MichaelBurr, you need to pass the number of elements or use a sentinel.
An indirect way to do this is using compound literals:
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#define minimum(...) fnminimum(sizeof((int []) {__VA_ARGS__}) / sizeof(int), __VA_ARGS__)
static int fnminimum(int n, ...)
{
int num, min = INT_MAX;
va_list ap;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
if (num < min) {
min = num;
}
}
va_end(ap);
return min;
}
int main(void)
{
int a = 1;
printf("%d\n", minimum(2, 30, 7, a++, 4));
return 0;
}
Another (ugly) method using NARGS macros (limited to N args):
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define minimum(...) fnminimum(NARGS(__VA_ARGS__), __VA_ARGS__)
static int fnminimum(int n, ...)
{
int num, min = INT_MAX;
va_list ap;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
if (num < min) {
min = num;
}
}
va_end(ap);
return min;
}
int main(void)
{
printf("%d\n", minimum(2, 30, 7, 1, 4));
return 0;
}
Output:
1
There is no built-in way to get the number of vararg arguments passed in C.
You need to do one of the following:
pass in a count explicitly,
pass in a count implicitly (as printf() does via the number of conversion specifiers)
or use a sentinel value (such as NULL or 0) to indicate the end of the vararg list
I have seen schemes that use macros and the __VA_ARGS__ identifier to automatically place a sentinel at the end of the varargs list when calling a function.
#include <stdio.h>
#include <stdarg.h>
void f(int parameter, ...)
{
va_list ap;
int j;
va_start(ap, parameter);
for (j = parameter; j >= 0; j = va_arg(ap, int))
printf("%d ", j);
va_end(ap);
printf("\n");
}
int main()
{
f(1, 2, 3, 4);
f(1, 2);
f(1);
}
I write this code, but the output is very strange.Who can tell me the reason.
the output:
esekilvxen245 [10:54am] [/home/elqstux/useful] -> ./a.out
1 2 3 4 1748292352 1748370624
1 2 1748295184 1745597392
1 10 1748295184 1745597392
Your ending condition for the loop is for j to be less than zero, but you don't end the argument list with a negative number in your calls. This means that the loop will continue until it finds a negative number, which can be anywhere on the stack far beyond the arguments you pass.
Call it like e.g.
f(1, 2, 3, 4, -1);
I'm writing a simple variadic function that adds together a series of ints and returns the sum. I'm having a bit of trouble understanding how it works and my code doesn't seem to work though I feel I'm in the right direction with my code. (Posted below) The specifications of this function are that it takes at least one param and the last param is always a zero (as seen called in the main). I was also told, based upon my machine, that I wouldn't necessarily get the output I'm looking for which, as you could imagine, further complicates my situation. Some assistance with correcting my Sum() function would be greatly appreciated.
EDIT:
This is supposed to be done w/o the use of stdarg.h header and thus no va_arg functions.
int Sum(int a, ... ) {
int sum = 0, *addy = &a;
while (*addy) {
sum += *addy;
addy += sizeof(a);
}
return sum;
}
int main() {
printf("%d %d %d %d\n", Sum(0), Sum(3, 5, 6, 7, 0),
Sum(7, 2, 42, 3, 5, -4, 0), Sum(-1, 9, 12, 123, -213, 42, 7, 2, 0));
}
//Expected output: 0 21 55 -19
//My output: 0 32770 32770 32776
When you add a number to an int pointer (as in addy += sizeof(a)) the number you add is automatically multiplied by the size of whatever type the pointer is declared as (in this case int). To fix this, just use
addy += 1;
instead. However, I would recommend using variadic macros instead of this method, they are clearer and less error prone.
for variable arguments, you have to use va_start and va_end functions, hope useful..
http://www.gnu.org/software/libc/manual/html_node/Variadic-Example.html#Variadic-Example
Can you please check this
int Sum(int a, ... ) {
int sum = 0, *addy = &a;
while (*addy) {
sum += *addy;
addy ++;
}
return sum;
}
int main() {
printf("%d %d %d %d\n", Sum(0), Sum(3, 5, 6, 7, 0),
Sum(7, 2, 42, 3, 5, -4, 0), Sum(-1, 9, 12, 123, -213, 42, 7, 2, 0));
}
Point to remember is for pointer operations: the number you are adding to the pointer will be multiplied by the size of the type that the pointer is pointing to. So incrementing the pointer addy is enough for geting the next element.
#include <stdarg.h>
#include <stdio.h>
int
add_em_up (int count,...)
{
va_list ap;
int i, sum;
va_start (ap, count); /* Initialize the argument list. */
sum = 0;
for (i = 0; i < count; i++)
sum += va_arg (ap, int); /* Get the next argument value. */
va_end (ap); /* Clean up. */
return sum;
}
int
main (void)
{
/* This call prints 16. */
printf ("%d\n", add_em_up (3, 5, 5, 6));
/* This call prints 55. */
printf ("%d\n", add_em_up (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
return 0;
}