【问题标题】:Simple average calculation简单的平均计算
【发布时间】:2010-05-19 21:28:02
【问题描述】:

我正在尝试编写程序来计算存储在数组中的给定数字的平均值。数字的数量不应超过 100,用户应输入它们直到给出 !int 变量:

#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;
}

为什么在给出 char 后,它会为我的数组的所有空单元格打印“给 n 号:”?它应该结束并只使用给定的数字。

【问题讨论】:

  • 不,这不是家庭作业。我只是在 cpp 中重做我的 java 程序来学习它。

标签: c++ average


【解决方案1】:

您在这里错误地使用了 isdigit - 它用于测试 char 是否为数字 - 您不能使用它来测试 int。

您可能需要考虑使用特殊值来终止输入,例如-1-999。如果这不可接受,那么您需要读取字符串而不是 int,然后确定它是否为数字。

【讨论】:

    【解决方案2】:

    isdigit 测试字符是否为数字。仅在将 0 分配给数字后才能进行测试,并且 0 是控制码,而不是数字,因此 isdigit(0) 始终为 false,因此您的 while 条件始终为 true。

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

    相反,测试输入流以确定它是否成功读取了一个值。

    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;
    }
    

    【讨论】:

    • cin 无论如何都与 cout 相关联:§27.3.1/2
    • 我确信我遇到过不是这样的情况。
    【解决方案3】:

    除了误用 isdigit() 应该使用一些哨兵机制之外,没有必要将数字存储在数组中。运行总和和数字计数足以计算平均值。

    此外,应该检查输入的零元素,以防止除以零错误。

    【讨论】:

    • 顺便说一句,isdigit 函数不会检查有效的数字字符,例如“.”、“-”和“+”。对于科学记数法,常见的“E”也是数字的有效字符。查看 C、C++、Java 等的任何语法规则。
    • @Thomas:他只读取整数,所以 '.' 'E' 在这里不适用。
    【解决方案4】:
    #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;
    }
    

    【讨论】:

    • 为什么不用cout 而不是cerr 进行交互?
    • @Bill: cerr 交给用户; cout 是程序输出。这个程序在“批处理模式”下更容易使用。
    • 嗯。我总是使用cerr 输出错误,使用cout 输出非错误输出。我也不清楚这在批处理模式下如何更容易使用。
    • @Bill:这个程序将接受一个包含一系列数字的文件。用作avg &lt; numbers_file &amp;&gt; /dev/null &gt; avg_file。使用cout 作为提示会导致avg_file 充满它们。无论如何,任何 CLI 应用程序都应向用户报告内联错误。
    【解决方案5】:

    检测非数字输入的更好方法是读取一个值后测试cin的状态:

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

    还要记住,除了没有输入有效数字之外,输入失败可能还有其他原因。

    【讨论】:

    • 是的,我知道这一点,但我们不要把这个想法复杂化 :)
    • @sasquatch90:@Thomas 的回答比你的回答更复杂吗?他的代码当然更简单。
    • @sasquatch90:检测不是数字有两种算法:1.使用转换函数并测试错误或2.检查每个包含有效数字的字符。实际上,最后一种方法必须包含可选字符,例如小数点、+ 和“-”。后一种方法要求将数据作为字符串输入,然后进行测试。顺便说一句,无论如何您都需要检查cin 是否成功。
    • 我的意思是这部分'另外请记住,除了没有输入有效数字之外,输入失败可能还有其他原因。'
    【解决方案6】:

    您的代码存在一些问题:

    cin >> number;
    

    您不检查流提取操作是否失败。一种简单的方法是利用operator void*() 转换运算符:

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

    上面的代码相当于检查failbitbadbit

    您对isdigit() 的使用也是错误的,因为您传递的是数字(例如1234 而不是字符(例如'z')。无论如何,添加流提取操作失败检查可以避免需要这种基于数字的支票。

    【讨论】:

    • 建议:将代码添加到else 语句中(例如cin.reset() 之类的,我记不太清了)。
    • @RaphaelISP,适当的方法是cin.clear()清除状态位。
    【解决方案7】:

    您可以使用 boost 中的lexical_cast。您将输入读入字符串,lexical_cast 将检查它是否可以转换为字符串。这也将确保您的字符串不会太长而无法转换,如果它是负数或根本不是数字。

    #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;
    }
    

    【讨论】:

      【解决方案8】:

      isdigit 会告诉你字符集的字符代码是否代表数字 0 - 9 之一。

      因此,(我假设您使用的是 ASCII),您可以简单地使用一个字符并测试其 ASCII 代码范围:

          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; 
      

      您也可以使用cin.getlineatoistrtod

      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; 
      

      您还可以使用其他方法,但是,这些方法应该会给您一些想法。

      【讨论】:

      • > isdigit 实际上会告诉您 ASCII 字符的 ASCII 码是否是数字 0 - 9 之一。--- 什么,即使在 EBCDIC 机器上?
      • @Pete - 不错的刺拳。我正在简化对 OP 的理解。显然,在 EBCDIC 机器上它应该与 EBCDIC 字符一起使用,但是,在过去,像 gcc 这样的编译器中存在一些错误,它不能在 EBCDIC 机器上工作......mail-archive.com/gcc-bugs@gcc.gnu.org/msg92614.html。看来 OP 正在使用 ASCII 因此我的例子......
      猜你喜欢
      • 1970-01-01
      • 2012-10-04
      • 2021-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-14
      • 1970-01-01
      相关资源
      最近更新 更多