Click here to Skip to main content
14,599,188 members
Rate this:
Please Sign up or sign in to vote.
See more:
I am trying to Pass A Variable number of Arguments to a Function. I have read code from Ivor Horton's "Beginning C++ 2005" and searched online but all examples pass the variables through code, However I want the variables to be passed from user input (The code should not know How many variables are passed Until the user enters them). I Hope You guys get Me.

I have written a simple program to calculate the Average of numbers the user enters, it stores them in an array. Now I want the Items in the array to be read as arguments to the function.

I know there are better ways of implementing the Averages, but my emphasis is on learning the concept of Passing Variable Number of Arguments to a Function. Below is My code, which works fine, and accepts input from the user, storing given numbers in an array, up to 20 numbers. I want to pass on these numbers to the averages function, also defined.

//Find the average of Numbers
//Demonstrates the Passing a variable number of Arguments to a Function Call

#include <iostream>
#include <string>
#include <sstream>
#include "stdarg.h"

using namespace std;

double averages(int count,...);//Prototype for the Function

int main()
{
 
      
 	double Number = 0.00;//Instantiate a double precision floating point valuable
 	int count = 0;//integer to keep count of user entries
 	string input = "";//string to get input from the user
 	double Numbers[20]; //Array to store User entered Numbers
 	
	 while ((input !="x") && (input !="X") && (count <20)) //Unless user Enters 'X' or 20 Numbers, store the number and ask for another
 	{
	 	while(true)
	 	{
		 		   
	     cout<<"Please Enter a Given Number: ";
		 getline(cin,input);//Get user input
		 
		 if((input=="X")||(input=="x"))//If User entered X, break (since loop doesn't run if input is X . . . .)
		 { 
		   cout <<endl<<"You Ended The Sequence";
		   break;
	     }
	     
		 stringstream mystream(input);
		 
		 if (mystream >> Number)//If User enters a Valid number, break 
		  break;
	     cout<<"Invalid Number, Please Try Again";
	     
		 }
		 
    Numbers[count] = Number; //Store currently entered Number in relevant Position in the array
	count++; //Increment the Counter
		 
    }
}

double averages(int count, ...)
{
 	   if (count<=0)//If count is not a whole number greater than zero, return 0.0 as the average
 	   {return 0.0;}
 	   
 	   va_list plist; //Declare a Pointer to the Argument List
 	   va_start(plist,count);
 	   
 	   //First Calculate the sum
 	   double sum = 0.0;//Declare Double Precision floating point Number to store sum of all numbers
 	   
 	   for(int i=0;i<count;i++)
 	   {
	     sum += va_arg(plist, int);//For each of the numbers, add it to the sum
	   }
	   
	   va_end(plist);//Reset the Pointer to Null
	   
	   double avg = sum/count;//Declare Double Precision floating point Number and assign it the value Sum/Count i.e Average
	   
	   return avg;//Return the average
}
Posted
Comments
xenotron 30-Aug-12 5:25am
   
And what is the question?
Legor 30-Aug-12 5:29am
   
This question doesn't deserve a Vote of 1 ...
André Kraak 30-Aug-12 5:30am
   
If you are working with a fixed array you could call the averages function like:
averages( count, Numbers[0], Numbers[1],...,Numbers[18],Numbers[19]);
but why you would do it like this I do not know.
If the size of the array changes you would need to change the call the averages function.

Why not just pass the array to the averages function?
Legor 30-Aug-12 5:33am
   
I guess OP is just using the average as an example of how you can provide a variable number of arguments. He also said he knows there are better ways to do it. The emphasis imo is on how you can provide a different amount of parameters to a function dependent on some user input (during runtime).
Peter Bamuhigire 30-Aug-12 5:49am
   
True, the emphasis is on passing different amount of parameters depending on input.
markkuk 30-Aug-12 8:37am
   
As far as know, the number of arguments to a variadic function must be a compile-time constant so it can't depend on the input. Use a STL container as others have suggested.
xenotron 30-Aug-12 13:55pm
   
"+5", vararg functions can't be used for that
xenotron 30-Aug-12 13:56pm
   
btw, you should use double instead of int here: sum += va_arg(plist, int);
Peter Bamuhigire 30-Aug-12 14:31pm
   
Oh, Thanks.
Peter Bamuhigire 30-Aug-12 14:38pm
   
Thanks Everyone. I guess I will "cram" what the Book says So I can go on to the next Chapter. I am just learning C++, having used only VB.NET and C# for Serious (Work Related) Projects. SO I will try to learn the COncepts in Horton's Book, then practice Until I get It.

Thanks pasztorpisti and Legor.

Again, Thank You All.
xenotron 30-Aug-12 14:51pm
   
You are welcome! Btw, to understand how vararg functions work in C/C++ you should know a bit of assembly (for example x86 asm) and how the __cdecl calling convention looks in assembly. If you have some x86 asm knowledge I can explain __cdecl and varargs for you in assembly. If you don't have x86 asm then all you have to know is that vararg functions are unsafe (its a heritage of the old C) and you should never write vararg functions for other than string formatting/logging in C++. Even formatting/logging can be done with typesafe methods but those are usually much more uncomfortable and sometimes slower.
Rate this:
Please Sign up or sign in to vote.

Solution 1

This is an interesting question but the example probably isn't suited to explain the problem. Actually for the average you wouldn't pass a different amount of parameters but one parameter (an array) which maybe of different size. For this case you should use
std::vector<int> Numbers;
A vector can be easyily expanded dynamically (e.g. according to some user input). The number of entered values can for example be determined by the size() operator of the vector:
Numbers.size()


But i'm pretty sure this isn't what you're trying to do (although it may be another solution for your problem? ).

Do you want the user to define the parameters a function is called with during runtime of the program?
   
v2
Comments
JackDingler 30-Aug-12 11:18am
   
I gave you a five, because it's what Peter needs to learn, rather than what Peter asked for.

Using a variable arguments in function calls should be constrained to a small niche of uses, not a general purpose technique. I typically use it, only in logging code, where I'm essentially using it like a printf...
xenotron 30-Aug-12 14:12pm
   
Logging/string formatting is pretty much the only place where this stuff is very too comfortable to omit. Our multiplatform system compiles with gcc as well and gcc can check (compile time) whether the vararg function is called with the right number of parameters with the right types by examining the format string if the function is marked with __attribute__ ((format (printf, ...)))
Rate this:
Please Sign up or sign in to vote.

Solution 2

Vararg functions are dangerous, they are typeless and easy to abuse. You should avoid them whenever possible. If you provide vararg functions in your interface for other coders then they will often make difficult-to-find mistakes. If you are passing variable number of arguments then do that in one of the following ways:
- pass a whole container if you have to pass a copy of the arguments
- pass a (const) reference to a container if you don't have to copy the items
- the best solution if you don't have to copy the items: pass in the begin and end iterators of your data

Declare your variables in the innermost scope possibly where you use it the first time, and not at the beginning of your function body!

#include <cstdio>
#include <vector>
#include <cassert>


template <typename ItemType, typename Iterator>
ItemType Average(Iterator first, Iterator last)
{
	assert(first < last);
	ItemType count = (ItemType)(last - first);
	ItemType sum = ItemType();
	while (first < last)
		sum += *first++;
	return sum / count;
}

int main()
{
	static const double DOUBLE_ARRAY[] = { 1.1, 3.3, 4.4 };
	static const int INT_ARRAY[] = { 1, 3, 4 };

	printf("float array average: %Lf\n", Average<double>(DOUBLE_ARRAY, DOUBLE_ARRAY+sizeof(DOUBLE_ARRAY)/sizeof(DOUBLE_ARRAY[0])));
	printf("int array average: %d\n", Average<int>(INT_ARRAY, INT_ARRAY+sizeof(INT_ARRAY)/sizeof(INT_ARRAY[0])));

	std::vector<float> floats;
	printf("Please enter float values and then enter X to print the average of the values entered!\n");
	for (;;)
	{
		char buf[0x100];
		if (!fgets(buf, sizeof(buf), stdin))
			return 1;
		if (!strcmp("x\n", buf) || !strcmp("X\n", buf))
			break;
		float f;
		if (1 != sscanf(buf, "%f", &f))
			printf("Invalid float value: %s\n", buf);
		else
			floats.push_back(f);
	}

	if (floats.empty())
		printf("There are no items.\n");
	else
		printf("The average of %d float values: %f\n", (int)floats.size(), Average<float>(floats.begin(), floats.end()));
	return 0;
}
   
v2
Rate this:
Please Sign up or sign in to vote.

Solution 3

See my question:
http://stackoverflow.com/q/12263745/1000282[^]

And answer:
http://stackoverflow.com/a/12267468/1000282[^]

At StackOverflow. I think you won't need that, as you are a beginner you should get a feeling of the language before dealing with things like that. But, anyway, it's good to know.
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100