【问题标题】:Reading numbers with getChar() in C++在 C++ 中使用 getChar() 读取数字
【发布时间】:2014-03-16 17:27:26
【问题描述】:

我想让一个函数以最快的方式从stdin 中读取整数。更具体地说,我有一个很长的ints 序列,以EOF 结尾的空格分隔,我必须对其进行一些操作。我使用了cin,但由于这个功能在它的可能性方面非常强大,我想做一些更小、更具体的东西,因此更快、更高效。我读过阅读stdin 的最快方法是getChar() 函数。我已经在 C 中找到了这个问题的一些实现,但是字符只是整数的另一种形式,而在 C++ 中它们不是。我的想法是做一个bool类型的函数

bool myIntRead( int *num);

它基本上会读取整数的字符,直到出现“空格符号”,然后以某种方式将这些字符放回int 数字中。 bool 类型将用于通知stdin 为空。

int main() {
    int num;
    while (myIntRead(&num) ) {
        myIntRead(&num)
        //some operations on num
    }
}

我完全意识到这种处理输入的方式要复杂得多,也更加困难,但我真的很想找到解决这个问题的方法。我真的会从你们那里得到一些帮助,以找出这个概念的实现。 最好的问候!

【问题讨论】:

  • char 是一个整数类型。您可以将其视为一个小整数。我认为“C++ 他们不是”你在谈论 字符文字,而不是 getchar() 的结果。
  • 顺便提一下,为 getchar() 可能从 line buffered 的终端读取数据的可能性做好准备,这样在完成整个数字后输入换行符之前,您通常不会收到任何输入,然后您将开始从输入缓冲区中逐个字符地获取它。

标签: c++ io getchar


【解决方案1】:

如果您只想处理 ASCII 输入,并且您确定输入将以预期的格式(即数字 0-9 后跟 b 空格)提供给您,那么您所要做的就是读取每个字符并那么:

  • 判断是空格还是数字
  • 如果是空格,开始读一个新的数字
  • 如果是数字,则将数字附加到当前数字

以下说明了这一点。但它不处理任何溢出,也没有停止条件..

int c;
int current_number;
std::vector<int> numbers;


do {
   c = getchar();

   if(c == 0x20)                      // it's a space
   {
       numbers.push_back(current_number);    // add the current number to the list of numbers
       current_number = 0;                   // reset the current_number variable back to 0
   }else if(c >= 0x30 && c <= 0x39)   // it's a digit
   {
       current_number = current_number * 10 + (c - 0x30);   // add next digit..
       // you may want to deal with overflow here (ie. if number of digits > MAX_DIGITS or similar)
   }

} while (TRUE);           // there should be a stop condition here..

【讨论】:

  • 谢谢,我正在考虑类似的方法。但是我仍然找不到任何解决方案来解决如何从一个数字组成一个整数。在 Java 中我会连接它,但在 C++ 中没有这样的方法。如果我使用int n = (int) getChar() 我有一个完整的int。那我该怎么处理呢?
  • 哇,这看起来很棒,从我看到的 U 使用 ASCII 的十六进制表示,但我总是难以记住它们,所以我可以使用它们的 char 表示吗?所以不是c &gt;= 0x30 &amp;&amp; c &lt;= 0x39 而是c &gt;= '0' &amp;&amp; c &lt;= '9' 嗯?请向我解释current_number = current_number * 10 + (c - 0x30);,因为我不明白你为什么要乘以十,并进行其他操作?
  • 还有一个问题要问你。由于整数序列最多为 10^7,我担心将它们全部收集到向量中可能是一个坏主意,那么我们可以摆脱它吗?我想快速阅读并显示它而不在堆栈中保存任何内容?你认为我们可以做到吗?
  • 是的,您可以使用字符表示。 current_number = current_number * 10 + (c - 0x30) 只是执行以 10 为基数的数字组合。只需通过一个示例来了解它的工作原理(即537 = (5*10 + 3)*10 + 7)。最后,由你决定如何处理这些数字。我只是举了一个例子来说明如何阅读它们。如果您不需要存储它们,那么请务必不要存储它们。
  • 我刚才想到了结果的产生方式,但现在我有最后一个问题:如果我将这些东西装扮成一个返回整数的好函数,我可以写
    @ 987654328@
    (当然在首先声明while循环变量'n'之前)这样做的原因是对于一个序列中的一个数字只调用一次这个读取函数。对吗?
【解决方案2】:

以下代码在 61 毫秒(几年前的普通 PC)内读取 1000000(一百万)个数字。文件大小为 3.8MB。

#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>

template< typename T, typename Out >
struct IntReader_type
{
    IntReader_type( Out out ) : out_( out ) {}
    template< typename E, typename Traits >
    friend std::basic_istream< E, Traits >& operator>>( std::basic_istream< E, Traits >& in, IntReader_type rdr )
    {
        std::basic_istream< E, Traits >::sentry ok( in );
        if( ok )
        {
            std::ios_base::iostate state = std::ios_base::goodbit;
            try
            {
                const std::ctype< E >& ct = std::use_facet< std::ctype< E > >( in.getloc() );
                while( state == std::ios_base::goodbit )
                {
                    T result = T(0);
                    for( Traits::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() )
                    {
                        if( Traits::eq_int_type( m,  Traits::eof() ) )
                        {
                            state |= std::ios_base::eofbit; // EOF is not an error
                            break;
                        }
                        const E c = Traits::to_char_type( m );
                        if( ct.is( std::ctype_base::space, c ) )
                            break;
                        if( ct.is( std::ctype_base::digit, c ) )
                        {
                            (result *= 10) += T(c - E('0'));
                        }
                        else
                        {
                            state |= std::ios_base::failbit; // not a digit
                            break;
                        }
                    }
                    *(rdr.out_)++ = result; // store the number
                    // skip white space character
                    for( Traits::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() )
                    {
                        if( Traits::eq_int_type( m,  Traits::eof() ) )
                        {
                            state |= std::ios_base::eofbit;
                            break;
                        }
                        if( !ct.is( std::ctype_base::space, Traits::to_char_type( m ) ) )
                            break;
                    }
                }
            }
            catch( ... )
            {
                state |= std::ios_base::badbit;
                if( in.exceptions() & std::ios_base::badbit )
                    throw;
            }
            in.setstate( state );
        }
        return in;
    }
private:
    Out out_;
};
template< typename T, typename Out >
IntReader_type< T, Out > read_ints( Out out )
{
    return IntReader_type< T, Out >( out );
}

以这种方式调用整数阅读器:

vector< int > numbers;
if( cin >> read_ints< int >( back_inserter(numbers) ) ) 
{   // read is done without error

小心 - 在这个版本中,只能读取无符号数字,并且不检查整数溢出。

【讨论】:

  • 如果您不想保存数字,而只想显示它们,那么只需将迭代器更改为 std::ostream_iterator&lt; int &gt;( cout, " " ) 在这种情况下,由于输出,程序运行速度要慢得多!跨度>
  • 非常感谢您提供如此详尽的答案!这段代码对我来说是一个很好的知识来源,研究它将阐明我还不知道的领域。 :) 但是,现在,我将尝试实现@MikyDinescu 的答案,这似乎足够简单,让我可以全神贯注地使用它。无论哪种方式 - 非常感谢你!
【解决方案3】:

好的,所以c = getchar();

您必须将其存储在一个数组中才能对其进行处理。

如果c 包含一位数字,则乘以 c[0] * 1。

如果c 包含两位数,则乘以 c[1] * 1 + c[0] * 10。

如果c 包含三个数字,则乘以 c[2] * 1 + c[1] * 10 + c[0] * 100。

如果c 包含四位数字,则乘以 c[3] * 1 + c[2] * 10 + c[1] * 100 + c[0] * 1000 等。

输入代码如下所示:

   while(digitInput!=13)
   {
       if (kbhit())
       {
           digitInput=getch();
           if (digitInput==27) exit(0);

           if ((digitInput>47) && (digitInput<59))
           {
             digitArray[digit]=(unsigned char)digitInput-48;
             digit++;

             printf("%d",digitInput-48);

           }
           if (digitInput==13)  { digitn=digitArray[0]; break; }
       }
   }



switch(digit)
   {
       case 0:
       case 1:
            digitn=digitArray[0]*1 ;
       break;

       case 2:
            digitn= digitArray[1]*1  +digitArray[0]*10  ;
       break;

       case 3:
            digitn=  digitArray[2]*1+digitArray[1]*10 +digitArray[0]*100  ;
       break;

       case 4:
             digitn=digitArray[3]*1+digitArray[2]*10+digitArray[1]*100+digitArray[0]*1000 ;
       break;
}

代码中的完整应用程序。

#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>


int digit=0,digitInput=0;
int digitArray[10]={0},digitn;
int numberOfInputDigits=4;

/*********************************
 *                               *
 ********************************/

void getIntKey(void)
{
   digitArray[0]=0;
   digitArray[1]=0;
   digit=0;
   digitInput=0;

   while(digitInput!=13)
   {
       if (kbhit())
       {
           digitInput=getch();
           if (digitInput==27) exit(0);

           if ((digitInput>47) && (digitInput<59))
           {
             digitArray[digit]=(unsigned char)digitInput-48;
             digit++;

             printf("%d",digitInput-48);

           }
           if (digitInput==13)  { digitn=digitArray[0]; break; }
       }
   }

   switch(digit)
   {
       case 0:
       case 1:
            digitn=digitArray[0]*1 ;
       break;

       case 2:
            digitn= digitArray[1]*1  +digitArray[0]*10  ;
       break;

       case 3:
            digitn=  digitArray[2]*1+digitArray[1]*10 +digitArray[0]*100  ;
       break;

       case 4:
             digitn=digitArray[3]*1+digitArray[2]*10+digitArray[1]*100+digitArray[0]*1000 ;
       break;

       case 5:
             digitn=digitArray[4]*1+digitArray[3]*10+digitArray[2]*100+digitArray[1]*1000+digitArray[0]*10000 ;
       break;

       case 6:
             digitn=digitArray[5]*1+digitArray[4]*10+digitArray[3]*100+digitArray[2]*1000+digitArray[1]*10000 
                   +digitArray[0]*100000;
       break;


       case 7:
             digitn=digitArray[6]*1+digitArray[5]*10+digitArray[4]*100+digitArray[3]*1000+digitArray[2]*10000 
                   +digitArray[1]*100000 +digitArray[0]*1000000;
       break;


       case 8:
             digitn=digitArray[7]*1+digitArray[6]*10+digitArray[5]*100+digitArray[4]*1000+digitArray[3]*10000 
                   +digitArray[2]*100000 +digitArray[1]*1000000+digitArray[0]*10000000;
       break;

       case 9:
             digitn=digitArray[8]*1+digitArray[7]*10+digitArray[6]*100+digitArray[5]*1000+digitArray[4]*10000 
                   +digitArray[3]*100000 +digitArray[2]*1000000+digitArray[1]*10000000 +digitArray[0]*100000000;
       break;


   }


  // if (digitInput!=13)  digitn=digitArray[3]*1+digitArray[2]*10+digitArray[1]*100+digitArray[0]*1000 ;
   printf("\n%i\n\n",digitn);
}

/*********************************
 *                               *
 ********************************/

int main()
{
    system("color 1F");     //Blue background       
   printf("Digits Into decimal numbers \n ");
   printf("Max Input is %d Digits   \n ",numberOfInputDigits);
   printf("\nInput Digit >");
   getIntKey();

   printf("\nThe input was   digitArray[7]=%d \n",digitArray[7]);

   printf("digitArray[6]=%d \n",digitArray[6]);
   printf("digitArray[5]=%d \n",digitArray[5]);
   printf("digitArray[4]=%d \n",digitArray[4]);

   printf("digitArray[3]=%d \n",digitArray[3]);
   printf("digitArray[2]=%d \n",digitArray[2]);
   printf("digitArray[1]=%d \n",digitArray[1]);
   printf("digitArray[0]=%d \n",digitArray[0]);
   printf("\n%i\n\n",digitn);




    return 0;
}

【讨论】:

  • 虽然我不是反对这一点的人,但它确实看起来相当迂回。为什么您认为有必要将输入存储在一个数组中,而不是每次输入另一个有效数字时简单地将累加值乘以 10?
  • 非常感谢你,但像@ChrisStratton 我认为存储所有这些值并“手动”选择乘法方式是多余的。不管怎样,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-14
  • 1970-01-01
相关资源
最近更新 更多