I believe indefinite arguments can be defined with '...', but then how do you access them? For instance for the following function:

int test(int n, ...){
	return n;
}

How does one do this with strings or other types than ints?

For instance something like,

#include <iostream>
#include <stdio.h>
#include <stdarg.h>

using namespace std;

void test_args(string cur_s, ...){
	va_list marker;
	va_start(marker, cur_s);
	for(int i=0; i<10; i++){
		string var = va_arg(marker, string);
		cout<<"var: "<<var<<endl;
	}
	va_end(marker);
}

int main(){
	test_args("hello", " ", "world");
}

You can't tell how many arguments have been passed to a varargs function, you have to tell it how many there are. There are several ways of conveying the effective argument count.

printf( const char *format, ... );
printf( "The min is %d, the max is %d\n", min, max );

printf 'knows' the number of arguments from counting the conversion formats.

execl(const char *path, const char *arg, ...);
execl( "/bin/ls", "/bin/ls", "-l", (const char *)NULL );

execl 'knows' the number of arguments by counting through them until a NULL pointer is found.

Besides, I don't think the varargs thing is particularly well defined for a non-POD type such as std::string.

Right. The va_args don't work with object-types.

More precisely: va_args does not work correctly if an argument class objects has non-trivial assignment operator (std::string, for example). You may pass pointers to any class objects safety.
However, look at the trick:

void battleShipIowa(const char* what,...)
{
    va_list p;
    va_start(p,hdr);
    std::string who;

    who = *(std::string*)p; // very dangerous, but...
    if (what)
       cout << what << "...";
    cout <<  who << "!.." << endl;

    va_end(p);
}

void TestArgs()
{
    std::string kamikaze("Kamikaze");
    battleShip("Air-raid alert!",kamikaze);
}

It's not recommendation, of course...

Sorry, must be va_start(p,what); , of course...

Thanks. How does one access the C string arguments then? For example how would one get 'void test_args(int arg_count, char* cur_s, ...){}' to display each C string with 'test_args(3, "hello", " ", "world");'?

It is possible to pass C character arrays as variable arguments, just access them similar to how you would an integer. Your function needs to know the data types of the parameters. If some are integers and other are pointers, you program will have to know about that. There is nothing in vargs that will tell you the data types or types of pointers.

Your function also needs some way to know how many variable parameters have been passed. One way to do that is, for pointers, make the last pointer NULL

#include <stdarg.h>
#include <iostream>
using namespace std;

void battleShip(const char* what,...)
{
    va_list p;
    va_start(p, what);
    char* who;
    while((who = va_arg(p,char*)) != NULL)
        cout <<  who << "!.." << endl;

    va_end(p);
}

void main()
{
    
    battleShip("Air-raid alert!","One","Two","Three",NULL);
}

Thank you :)

Just to note, it seems you have to manually use the first argument.

#include <stdarg.h>
#include <iostream>
using namespace std;

void battleShip(const char* what,...)
{
    va_list p;
    va_start(p, what);
    char* who;
    cout <<  what << "!.." << endl;
    while((who = va_arg(p,char*)) != NULL)
        cout <<  who << "!.." << endl;

    va_end(p);
}

int main()
{
    
    battleShip("Air-raid alert!","One","Two","Three",NULL);
}

Also, is it important for the argument to be const char*? It works without the const as well.

>> it seems you have to manually use the first argument.
No you don't.

>>is it important for the argument to be const char*?
No. The first argument can be any POD you want.

Is there a coding reason why it would be preferable to use "const char *" instead of just "char *"?

>> it seems you have to manually use the first argument.
No you don't.

Odd, when I run your code it outputs just "One!.." "Two!.." "Three!..", without the "Air-raid alert!".

Obviously, it was an accidental Ancient Dragon's inattention. Of course, you have to manually use the first argument if you want to know the reason of that sensation;).

>>>> it seems you have to manually use the first argument.
Alright -- I guess I misunderstood what you meant. You don't have to use the first argument at all if you don't want to. But yes, if you want the first argument displayed then you have to do it yourself.

I have another question regarding this.

I didn't realize that you could pass the first argument as an int regardless of what the other arguments are. But, how does one pass indefinite arguments from one function to another? For example, I tried to pass the va_list as an argument, but that gives the error "error: `va_start' used in function with fixed args":

#include <stdarg.h>
#include <iostream>
using namespace std;

void util_func(int n, va_list p){
    va_start(p, n);
    char* who;
    for(int i=0; i<n; i++){
        who = va_arg(p,char*);
        cout <<  "util_func: " << who << "!.." << endl;
    }
    va_end(p);
}

void battleShip(int n,...)
{
    va_list p;
    va_start(p, n);
    char* who;
    for(int i=0; i<n; i++){
        who = va_arg(p,char*);
        cout <<  "battleShip: " << who << "!.." << endl;
    }
    va_end(p);
    util_func(n, p);
}

int main()                
{

    battleShip(3,"One","Two","Three");
}

There are at least two mistakes in your va_list using:
1. Don't use va_start macros in util_func: this function gets va_list argument ready to use.
2. Every va_arg call modifies va_list variable, so battleShip() passes wrong va_list value to util_func. Possible correction:

void battleShip(int n, ...)
{
     va_list p;
     va_start(p,n);
     va_list q = p;
     ....
     util_func(n,q);
     va_end(p);
}

Warning: variable argument list is a very dangerous (error prone) method. Don't become mad about it...

Thanks, I made those changes and it worked :)

I also tried using va_copy, like below, and that also worked. Don't know if one method is more proper than the other:

void battleShip(int n,...){
//    va_list p;
    va_list p, q;
    va_start(p, n);
//    va_list q = p;
    va_copy(q, p);
    char* who;
    for(int i=0; i<n; i++){
        who = va_arg(p,char*);
        cout <<  "battleShip: " << who << "!.." << endl;
    }
    util_func(n, q);
    va_end(p);
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.