tags:

views:

224

answers:

8

I'm trying to write program calculating average of given numbers stored in an array. Amount of numbers should be not more than 100, and user should input them until a !int variable is given :

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

double average(int tab[], int i){

    int sum=0;

    for(int j=0; j<i; ++j){
            sum+=tab[j];
    }
    return (double)sum/i;

}

int main()
{
    int tab[100];
    int n=0;   
    int number=0;


    do {
       if(n < 100){
           cout << "Give " << n+1 << " number : ";
           cin >> number;
           tab[n]=number;
           number=0;
           ++n;       
       }
       else{
            break;
       }
    } while( !isdigit(number) );      

    cout << average(tab, n) << endl;

    getch();
    return 0;
}

Why after giving char, it prints me 'Give n number:' for all empty cells of my array ? It should end and use only given numbers.

+5  A: 

You're using isdigit incorrectly here - it's used to test whether a char is numeric or not - you can't use it to test an int.

You probably want to consider using a special value to terminate input, e.g. -1 or -999. If that's not acceptable then you'll need to read in a string rather than an int and then decide whether it's numeric or not.

Paul R
so how to do this in different way ? use ascii codes ?
sasquatch90
@sasquatch90: see updated answer above...
Paul R
+1  A: 

Besides the misuse of isdigit() which should instead use some sentinel mechanism, there's no need to store the numbers in an array. A running sum and a count of numbers is sufficient for calculating an average.

Also, there should be a check for zero elements entered to prevent a divide by zero error.

wallyk
BTW, the `isdigit` function does not check for valid numeric characters such as '.', '-' and '+'. For scientific notation a common 'E' is also a valid character for a number. Check out any grammar rule for C, C++, Java, etc.
Thomas Matthews
@Thomas: he's only reading integers, so '.' and 'E' would not apply here.
Paul R
A: 

The better method for detecting the input of a non-number is to test the state of cin after reading a value:

// ...
if (cin >> number)
{
  tab[n++] = number;
}
else
{
  break;  // break out of loop
}

Also remember that there may be other reasons the input failed other than not inputting a valid number.

Thomas Matthews
yeah I'm aware of that, but let's not overcomplicate the idea :)
sasquatch90
@sasquatch90: How is @Thomas's answer more complicated than what you had? His code is certainly simpler.
Void
@sasquatch90: There are two algorithms for detecting *not a number*: 1. Use a conversion function and test for error or 2. Check **each** character to contain a valid digit. Actually this last method must include optional characters such as decimal point, + and '-'. The latter method requires the data to be input as a string then tested. BTW, you need to check `cin` for success anyway.
Thomas Matthews
I meant this part 'Also remember that there may be other reasons the input failed other than not inputting a valid number.'
sasquatch90
A: 

There are a few problems with your code:

cin >> number;

You don't check if the stream extraction operation failed. A simple way to do that is to leverage the operator void*() conversion operator:

if (cin >> number)
  ... operation succeeded ...

The above code is equivalent to checking the failbit and badbit.

Your usage of isdigit() is also wrong in that you're passing a number (e.g. 1234 of instead of a character (e.g. 'z'). Regardless, adding a stream extraction operation failure check obviates the need for such a digit based check.

Void
Suggestion: add the code that goes into the `else` statement (i.e. something like `cin.reset()`, I don't remember exactly).
RaphaelSP
@RaphaelISP, the appropriate method is `cin.clear()` to clear the status bits.
Thomas Matthews
+1  A: 

isdigit tests whether the character is a digit. The test is only reached following assigning 0 to number, and 0 is a control code, not a digit, so isdigit(0) is always false, and so your while condition is always true.

 ...
       number=0;
 ...
} while( !isdigit(number) );      

Instead, test the input stream to determine whether it successfully read a value.

int main()
{
    const size_t COUNT = 100;
    int tab[COUNT];
    size_t n;   

    cin.tie(&cout); // ensures cout flushed before cin read
    // (not required if your runtime complies with that part of the standard)

    for (n = 0; n < COUNT; ++n ) {
        cout << "Give " << n+1 << " number : ";
        cin >> tab[n];

        if (!cin)
            break;
    }

    if (n > 0) // average is undefined if n == 0
        cout << average(tab, n) << endl;

    return 0;
}
Pete Kirkham
cin is tied to cout anyway: §27.3.1/2
Potatoswatter
I'm sure I have had cases where it wasn't.
Pete Kirkham
+1  A: 
#include <iostream> // <conio.h> is nonstandard
using namespace std;

int main() {
    long total = 0, cnt = 0, num;

    while ( cerr << "Enter " << ++ cnt << " number" << endl, // use cerr for interaction
              // use comma operator to produce a side effect in loop expression
            cin >> num ) { // use Boolean value of (cin >> ...) to end loop on input failure
        total += num; // just keep a running total
    }
    -- cnt; // cnt went one too far :(

    cout << static_cast<double>( total ) / cnt << endl;
}
Potatoswatter
Why not `cout` for interaction instead of `cerr`?
Bill
@Bill: cerr goes to the user; cout is program output. This program is much easier to use in "batch mode."
Potatoswatter
Huh. I always use `cerr` to output errors and `cout` for non-error output. I'm also not clear how this would be easier to use in batch mode.
Bill
Potatoswatter
A: 

You could use lexical_cast from boost. You read the input into a string and the lexical_cast will check if it can be converted into a string. This will also make sure that your string is not to long to be converted, if it is a negative number or a number at all.

#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>

using std::cout;
using std::cin;
using std::endl;
using std::string;
using boost::lexical_cast;
using boost::bad_lexical_cast;

double average(int tab[], int i){

    int sum=0;

    for(int j=0; j<i; ++j){
            sum+=tab[j];
    }
    return (double)sum/i;

}

int main()
{

    int tab[100]; //this is a fairly low level construct which might want to
                  // into a std::vector 

    string input; 

    int n;
    try{
        for (n = 0 ;n < 100; n++) {
           cout << "Give " << n+1 << " number : ";
           cin >> input;                          //read number into string
           tab[n]= lexical_cast<int>(input);     //conversion with lexical_cast
                                                 //if not possible exception is 
                                                 //thrown
        }
     }
     catch(bad_lexical_cast &){
        cout << "not a number" << endl;
     } 

    cout << average(tab, n) << endl;

    return 0;
}
Lucas
A: 

isdigit will tell you if a character code of a character set represents one of the digits 0 - 9.

Therefore, (I'm assuming you are using ASCII), you could simply use a character and test its ASCII code range:

    int tab[100]; 
    int n = 0;    
    char c;

    while (n++ < 100)
    {
       cout << "Give " << n << " number : "; 
       cin >> c;
       if (c < 48 || c > 57)
          break;
       tab[n - 1] = c - 48;            
    }

    cout << average(tab, n - 1) << endl; 

    getch(); 
    return 0; 

You could also use cin.getline and atoi or strtod:

int tab[100]; 
int n=0;    
int number=0; 
char input[10];

while (n++ < 100)
{     
   cout << "Give " << n << " number : ";
   memset(input, 0x00, 10);
   cin.getline(input, 10);
   number = atoi(input);
   if (number > 0)
      tab[n-1] = number; 
   else
      break;
}

cout << average(tab, n-1) << endl; 

getch(); 
return 0; 

There are other methods you can use, however, these should give you some ideas.

> isdigit actually tells you if the ASCII code of an ASCII character is one of the digits 0 - 9. --- what, even on an EBCDIC machine?
Pete Kirkham
@Pete - Nice jab. I'm simplifying the understanding for the OP. Obviously on an EBCDIC machine it should work with EBCDIC characters, however, in the past there have been bugs in compilers like gcc where it does not work on EBCDIC machines... http://www.mail-archive.com/[email protected]/msg92614.html. It appears the OP is using ASCII thus my examples...