For a homework assignment I need to write a function that computes the average value of an array of floating-point data:

double average(double* a, int a_size)

In the function, use a pointer variable, and not an integer index, to traverse the array elements.

The code below is what I have so far but I don't know what I can do to make it better. Any help or comments will be appreciated!

Dennis

#include <iostream>

using namespace std;

double average (double* a, int a_size)
{
	double total;
	double average;
	double* p = a;

	for (int i = 1; i < a_size; i++)
	{
		total = total + a[i];
		average = total / a_size;
	}
    return average;
}
      
int main()
{
     return 0;
}

Dani AI

Generated

A few concrete problems to fix first: total (and average) must be initialized, the loop should start at element zero, the pointer you created was never used, and you must not compute the average on every iteration (divide only once, after summing). correctly called out the unused pointer; showed a compact pointer-walk style. For correctness and clarity, prefer a clear pointer-range loop and explicit checks for bad inputs (null pointer or zero length).

A robust, pointer-based implementation pattern (keeps the pointer requirement, checks inputs, and computes average only once) looks like this:

double average(const double* a, std::size_t n) {
    if (!a || n == 0) throw std::invalid_argument("empty array");
    const double* end = a + n;
    double sum = 0.0;
    for (; a != end; ++a) sum += *a;
    return sum / n;
}

If the homework forbids exceptions, use an assertion or return a sentinel (NaN) — but document your choice.

For numeric robustness, consider compensated summation (Kahan) when elements vary greatly in magnitude or when n is large; it reduces rounding error without changing the pointer-style traversal:

double average_kahan(const double* a, std::size_t n) {
    if (!a || n == 0) throw std::invalid_argument("empty array");
    const double* end = a + n;
    double sum = 0.0;
    double c = 0.0; // compensation
    for (; a != end; ++a) {
        double y = *a - c;
        double t = sum + y;
        c = (t - sum) - y;
        sum = t;
    }
    return sum / n;
}

Tie-in to earlier replies: 's running-mean (online) approach is useful to avoid overflow in extreme cases but has different rounding tradeoffs; 's flag for const is valid (use const double*). For production code prefer iterator/pair or std::span so the same logic works for vectors, arrays, or other containers. Finally, add unit tests for empty arrays, very large values, and mixed magnitudes to validate both correctness and numeric stability.

Recommended Answers

All 11 Replies

Line 9 - You create the pointer variable, but never use it.

Line 13 - You're using an array index, which the assignment does not allow.

You need to change line 13 to this:

total = total + *p;

and you need to adjust the p pointer. If p points to a[5], then this line:

p++;

will make it point to a[6].

But there are other problems too. I suggest you write it using array indexes first, then when that works, convert it to use pointers.

I'm just wondering, is there a way to compute the arithmetic mean without using a summation like the normal algorithm does?

I'm just wondering, is there a way to compute the arithmetic mean without using a summation like the normal algorithm does?

The "accumulate" function will add it up for you.

http://www.cppreference.com/wiki/algorithm/accumulate

But with the "no array indexes, must use pointers" stipulation, I think the OP is expected to loop through the elements and add them, then divide by the number of elements. I can't think of any other way.

After a google search I found out that Knuth (the programming book author) has in his second edition something like this (this is my implementation):

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>

int main()
{
	typedef unsigned int uint;
	const uint cSize = 99999;
	uint data[cSize] = {0};
	srand(uint(time(nullptr)));
	std::for_each( data, data+cSize, [](uint &n) {
		//
		n = rand();
	});

	double M = 0.0;//,
		//S = 0.0;
	for(uint i = 0; i < cSize; ++i){
		//
		M += (data[i] - M)/(i+1);// <<<----ATTENTION HERE.
		if( (std::numeric_limits<double>::max() - M) < 1000 )
			std::cerr << "WARNING!!!" << std::endl;
	}
	//std::for_each(data, data+cSize, [](uint n){
	//	std::cout << n << ' ';
	//});
	std::cout << M << std::endl;
	std::cin.get();
}

I used a lambda or two so if you want to use it with an older compiler you will need to make adjustments.

Line 19 - 24 --> If you are worried about overflow errors, you are correct. You can't add everything up, then stick it in a variable, then divide, because it's overflowed, so your method would work in that case, whereas adding them all up, then dividing them would not.

If you are not worried about overflow, however (i.e. 100 numbers, all less than a million), you're making far more calculations (100 additions, 100 divisions, 100 subtractions) than the other method (100 additions, 1 division), so it's slower.

I'm not sure which method is better as far as round-of error.

Can you post a link? I'd be interested in reading that page to see if Knuth talks about overflow and when he suggests to use which methods.

My source is stack overflow, a person citing Knuth as his source. Unfortunately I've lost the page, and there wasn't a better answer as far as I was concerned. You can google it, however.

Perhaps I should re-phrase my previous post in which it sounded as if it was fact that Knuth had something to say about this--it was another who claimed so. I would have to read it myself to know for certain.

No need to create extra pointers - just dereference and increment.

double average (double* a, int a_size){
    double total = 0.0;     
    for (int i = 0; i < a_size; i++)
        total += *a++;
    return total / a_size;
}

user422, it's perfectly fine if you understand the order of operations with regard to * and ++, but I don't remember them exactly so I typically will include parentheses, even when not required, so as to make more clear the intent.

user422, it's perfectly fine if you understand the order of operations [...]

Good point. Just make sure its *(a++) and not (*a)++
Or try both and observe what happens.

Surprised none mentioned the use of const.

float computeAverage(const float data[], const int DATA_SIZE){
   return std::accumulate(data, data + DATA_SIZE, 0)/ float(DATA_SIZE);
}

Thanks Everyone for your help.

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.