Jump to content
  • Advertisement
Sign in to follow this  
The Orange Peanut

What is wrong with this code? (variable argument lists in C++)

This topic is 3810 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm following the code here: http://www.cprogramming.com/tutorial/lesson17.html That code, when copied and pasted, works. However, when I run my own code (which is basically the code from the site, except not CP'ed), I get garbage for output. I've looked my code over and I don't see how it differs from the code on the website except for spacing and variable names. Could someone take a look and see what I'm doing wrong?
#include <iostream>
#include <cstdarg>
using namespace std;

double average(int num, ...)
{
    va_list arguments;    //a place to store the list of arguments
    double sum = 0;

    va_start(arguments, num);   //initializing arguments to store all values after num
    for(int i = 0; i < num; i++)    //loop until all numbers are added
    {
        sum += va_arg(arguments, double);  //adds the next value in argument list to sum
    }

    va_end(arguments);  //cleans up the list

    return sum / num;       //casting ensures accuracy
}

int main()
{
    cout << average(5, 10) << '\n';
    
    return 0;
}

Share this post


Link to post
Share on other sites
Advertisement
Now that you know how this works, please don't do it any more in C++. There are many limitations and subtle gotchas for a "convenience" that that isn't really.

Share this post


Link to post
Share on other sites
And now for something completely different.

#include <boost/preprocessor.hpp>
#include <cassert>

#define AVERAGE_ADD_IMPL(z,n,arg) + arg ## n
#define AVERAGE_IMPL(z,n,unused) \
template < typename T > T average( BOOST_PP_ENUM_PARAMS( n, T arg ) ) { \
return ( BOOST_PP_REPEAT( n, AVERAGE_ADD_IMPL, arg ) ) / n; \
}

BOOST_PP_REPEAT_FROM_TO( 1, 11, AVERAGE_IMPL, ~ )
#undef AVERAGE_IMPL
#undef AVERAGE_ADD_IMPL

int main() {
assert( average(1,2,3,4,5) == 3 );
}


EDIT: Fixed
NOTE: To use, remove whitespaces trailing backslashes added to prevent gdnet from joining all the lines.




And now for something else completely different.

template < typename T, typename Iterator > T average( Iterator begin, Iterator end ) {
unsigned n = 0;
T value = T();
for ( Iterator i = begin ; i != end ; ++i, ++n ) {
value += *i;
}
return value / n;
}
template < typename T, unsigned N > T average( const T (&array)[N] ) {
return average<T>( array+0, array+N );
}

int main() {
int values[] = { 1, 2, 3, 4, 5 };
assert( average(values) == 3 );

std::list<int> container;
container.push_back(1);
container.push_back(2);
container.push_back(3);
container.push_back(4);
container.push_back(5);

assert( average<int>( container.begin(), container.end() ) == 3 );
}

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
template < typename T, typename Iterator > T average( Iterator begin, Iterator end ) {
unsigned n = 0;
T value = T();
for ( Iterator i = begin ; i != end ; ++i, ++n ) {
value += *i;
}
return value / n;
}


Bug: for an arbitrary type, the default constructor is not guaranteed to be the additive identity. Instead, if begin != end, you should copy construct from the first element instead, and start your loop from begin+1.

Bug: if begin == end, you divide by zero. This is undefined behavior. You should detect the condition and do something sane.

Share this post


Link to post
Share on other sites
Quote:
Original post by frob
Bug: if begin == end, you divide by zero. This is undefined behavior. You should detect the condition and do something sane.


Average of zero numbers is undefined per se, and should trigger a division by zero exception.

There's nothing else you can return in this case, at least not with function in this form.

Share this post


Link to post
Share on other sites
I once wrote some weird template code where you could pass the number of arguments as a template parameter. I cannot, for the life of me, remember how I did that... probably for the best anyway, I'm sure it was full of bugs.

Share this post


Link to post
Share on other sites
I can't see any weaknesses with something like this compared to the above samples


template<typename T>
class Accumulator
{
T sum;
int count;

public:

Accumulator() : sum(0), count(0) {}

friend Accumulator& operator << (Accumulator& a, T number)
{
a.sum += number;
a.count++;
return a;
}

void reset() { sum = 0; count = 0; }

T average() const { return sum / count; }
};

#include <iostream>

int main()
{
Accumulator<double> accumulator;

accumulator << 3.0 << 4.3 << 5.8 << 6.2 << 7.0;

std::cout << "Average: " << accumulator.average() << std::endl;
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!