有位同学问怎么读一整行键盘输入,他查到个getline函数,没有看懂,云云。
下面说明一下。

C风格的行输入

while { getc / getchar }

显然一个一个字符拼是肯定可以的,不过要注意1.字符数组不要越界;2.结尾检查要完善。

/**
* \brief while-getchar输入行
* \param[out] line 存放行的数组
* \param[in] arrSize line数组的大小(包括结尾0)
* \return 输入的字符串的长度
*/
int myGetLine(char line[], int arrSize)
{
  int i, c, lineNotEnded = 1;
  for (i = 0; (i < arrSize - 1) && lineNotEnded; ++i)
  {
    switch (c = getchar())     /* 或者 c = getc(stdin) */
    {
    case '\r':                   /* 回车——到行首 */
    case '\n':                   /* 换行——下一行 */
    case EOF:                    /* “文件结束符” */
      line[i] = '\0';
      lineNotEnded = 0;         /* 这里break出不了for,所以要个标志,或者用goto */
      break;
    default:
      line[i] = (char)c;
      break;
    }
  }
  if (lineNotEnded) {           /* 说明是填满了 */
    line[i] = '\0';
    return i;
  } else {                        /* 说明是读到结束了 */
    return i - 1;
  }
}

scanf("%c", &c);不好,因为无法处理EOF情况。

gets

上面的函数还是挺复杂的。读行这么常见的事情,如果C标准里没有提供的话,就不正常了。其实char* gets(char*);函数就足够了。这个函数不大好的地方在于,它不关心输入数组的长度,所以使用的时候最好把数组开长些,以免输入太多而越界。

C++风格的行输入

cin.getline

有两种getline,一种是cin的成员函数,一种是全局函数。
准确地说起来,cin不是“函数”而是“全局变量”,类型是“类”,更准确地说是“istream类的某个实现了>>运算符重载的派生类”。平时大家用cin>>,其实是调用了istream类“重载”的一堆operator>>“成员函数”中的某一个,而operator函数们可以缩写成运算符形式。至于能连续>>,是因为cinoperator>>的返回值是对cin的“引用”。以上“类”、“派生”、“重载”、“成员函数”、“引用”概念,大家先不必理会,下学期C++会讲。
istream类还有其它一些成员函数,比如getline
cin.getline的原型,按C的理解方式来写,有两个,是如下形状的(现在切莫去研究这个函数的实际原型!):

/// \brief cin.getline输入行
/// \param[out] _Str 存放行的数组
/// \param[in] _Count _Str数组的大小(包括结尾0)
/// \param[in] _Delim 如果有,那么表示把_Delim给的字符,而不是换行,当行结束符。
/// \return 其实是cin,不过其状态是被getline读掉一行之后
某奇怪类型  cin.getline(char *_Str, unsigned _Count);
某奇怪类型  cin.getline(char *_Str, unsigned _Count, char _Delim);

如果用了_Delim,那么换行就不是结束符了,这是很有用的。

全局的getline

这个函数在<string>头文件里声明,需要using namespace std;(不要在.h里写这个)。按C的理解方式来写,原型也有两个,如下所示:

/// \brief getline输入行
/// \param[in] _Str 存放行的数组
/// \param[out] _Count _Str数组的大小(包括结尾0)
/// \param[in] _Delim 如果有,那么表示把_Delim给的字符,而不是换行,当行结束符。
/// \return 其实是cin,不过其状态是被getline读掉一行之后
某奇怪类型  getline(cin或某ifstream& _Istr, string变量& _Str);
某奇怪类型  getline(cin或某ifstream& _Istr, string变量& _Str, const char _Delim);

这里_Istr和_Str都是“引用”,所以函数可以改传过去的参数的值。用法如下:

string s;
getline(cin, s);