Click here to Skip to main content
15,885,244 members
Please Sign up or sign in to vote.
4.50/5 (4 votes)
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.

C++
//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
pasztorpisti 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.

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
C++
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:
C++
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?
 
Share this answer
 
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...
pasztorpisti 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, ...)))
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!

C++
#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;
}
 
Share this answer
 
v2
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.
 
Share this answer
 

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900