Solved

# Function with unlimited arguments???

Posted on 2003-03-17
Medium Priority
2,043 Views
Hi all,
I want to know that how is it possible to have a function that can be called with a variable number of argument of a specific type,
for example:
f1(12,13,24);
f1(12,32,43,43,34);
and there is no idea about number of argument so overloading seems to be useless

0
[X]
###### Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• Learn & ask questions

LVL 48

Accepted Solution

AlexFM earned 152 total points
ID: 8151509
Writing of function with variable number of arguments is not safe and requires some agreements between caller and function. For example, first argument may be number of arguments of the function. Incorrect call effectively crashes a program, as we can see using, for example, scanf.

Take a look at va_arg, va_end and va_start macros. Appropriate MSDN topic shows example of function with variable number of arguments:

// -1 is used as terminator
printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );

int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;

va_start( marker, first );     /* Initialize variable arguments. */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker );              /* Reset variable arguments.      */
return( sum ? (sum / count) : 0 );
}

0

LVL 48

Expert Comment

ID: 8151524
UNIX-compatible version of the same function:

int average( va_alist )
va_dcl
{
int i, count, sum;
va_list marker;

va_start( marker );            /* Initialize variable arguments. */
for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )
sum += i;
va_end( marker );              /* Reset variable arguments.      */
return( sum ? (sum / count) : 0 );
}
0

LVL 22

Expert Comment

ID: 8151896
>> Writing of function with variable number of arguments is not safe and requires some
>> agreements between caller and function. For example, first argument may be number
>> of arguments of the function. Incorrect call effectively crashes a program, as we can
>> see using, for example, scanf.
Agreed!   VA (Variable argument) functions are one of the leading causes of bugs in C programs.  C++ and the STL were developed in part to prevent these bugs by eliminating the need for VA functions.   So I really think you should reconsider using VA functions.  C++ provides many alternative techniques that elminate the need for resorting to VA.  We might be able to sugest some if you coudl explain what it is you are trying to do.
0

LVL 12

Assisted Solution

Salte earned 148 total points
ID: 8152211
This is possible but the problem is to find out when to stop reading arguments.

This is done in one of two ways:

a) Having a "stop value" to indicate when there are no arguments.

For example you can write a concat function which concatenates a number of strings and allocates them on heap:

char * concat(const char * s, ...)
{
va_list v;
// first go through the arguments to find the length
// of all the strings.
size_t len = 0;
const char * t;
if (s != 0) {
len = strlen(s);
va_start(v,s);
t = va_arg(v,const char *);
while (t != 0) {
len += strlen(t);
t = va_arg(v,const char *);
}
va_end(v);
}
char * dst = new char[len + 1];
if (s != 0) {
strcpy(dst,s);
va_start(v,s);
size_t x = strlen(s);
t = va_arg(v,const char *);
while (t != 0) {
strcpy(dst + x,t);
x += strlen(t);
t = va_arg(v,const char *);
}
va_end(v);
}
dst[len] = 0;
return dst;
}

This function can be called like this:

char * s = concat("hello"," ","there",0);

It stops when you give a 0 pointer argument.

You must specify a 0 value as the last argument to any call to this function, if you do not it will just continue to read garbage until that garbage happen to have the value of a NULL pointer.

Also, you can't give 0 arguments, if you want to allow for concat() giving an empty string out you must specify that as an extra overload:

char * concat()
{
char * d = new char[1];
*d = 0;
return d;
}

The other way is to provide a first argument that give info about how many arguments that follows and possibly also their type. This is the way that printf() does. For example a poly function computing polynomials can be made like this:

poly(2,5,1,-3,2); // compute 1 * 5 * 5 - 3 * 5 + 2

poly(n,x,c[n],c[n-1],c[n-2],....c[1],c[0]);

compute c[n]*pow(x,n) + c[n-1]*pow(x,n-1)...etc..

so poly(n,x,cn,...c0) == poly(n-1,x,cn,....,c1)*x + c0

double poly(int n, double x, ...)
{
va_list v;
double res = 0;

va_start(v,x);
for (int i = 0; i <= n; ++i) {
double c = va_arg(v,double);
res = x * res + c;
}
va_end(v);
return res;
}

a function like printf also indicate the type of the element so you need to decode the format argument and if it indicate 'int' you do va_arg(v,int) etc.

Alf
0

LVL 1

Expert Comment

ID: 8153075
One solution might be to use an array and count. like this
func(int CountofElements, int *ArgArray);
It requires that you trust the caller only slightly less than the VA situation.
0

LVL 12

Expert Comment

ID: 8153399
The reason why VA is not safe is that it is perfectly possible to do mistakes, referring to my two methods of providing VA arguments above.

If you have a 'stop value' you can simply call the function without having the stop value at the end.

concat("hello ", "there");

will crash.

The other method you can give fewer or more arguments than your info argument indicate. If the poly is called like this:

poly(15, 0.5, 2, 3, 7);

it will crash, similarly:

poly(3, 0.5, 2, 3, 7, 11, 19);

This will compute f(x) with x = 0.5 for
2 * x*x*x + 3*x*x + 7*x + 11. The argument 19 is not read or used.

A similar situation occur in method 1 above if you provide arguments after the stop-value:

concat("hello, ", 0, "how are you?");

will only return a string containing "hello, ", the "how are you?" part is never read or used.

Avoiding va args eliminate these problems. However, this elmination isn't really very true. The problem is that the only other way to provide a variable number of arguments to one single function call is to provide an array and using that array you can lie about the size of it, it is also more troublesome to set up an array so it doesn't really solve it.

This leaves you to using a set of functions to provide the functionality and in this C++ provide a very good mechanism as shown by iostream. Creating an object and then "stuff" values into that object can

1. Preserve type of the value.
2. Preserve the number of values.
3. is safe.

Then providing that object as argument to your function will the process the values as you should.

For example a concat using this method is easy to write using stringstream:

stringstream ss;
ss << "string one";
ss << "string two";
...

ss.c_str() is now the concatenated string.

Similar method for printf is found in the boost formatter library where you create a format class with format and then give it values in a similar manner.

Using overloads you also get it so that you can remember the type of the value provided etc and you can use type specific overloads for using the value.

However, if you don't want to use this technique, then I doubt that using arrays is any safer than va_args, giving an array and saying it has 10 elements is just as bad as calling a VA function with the wrong setup. I would think it is also just as easy to make both those mistakes because they are fundamentally the same error - mismatch between how the function call should be and how it is.

Alf
0

LVL 9

Expert Comment

ID: 9502217
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Split Points between AlexFM & Salte

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Tinchos
EE Cleanup Volunteer
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their waā¦
Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, whā¦
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
###### Suggested Courses
Course of the Month13 days, 23 hours left to enroll

#### 801 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.