您的位置:首页 > 其它

Windows 上 cin>> 与 cin.getline() 混用的问题

2012-11-26 20:55 393 查看
经常看到类似下例的问题:

int main()
{
char buf1[5]={0};
char buf2[5]={0};

cin >>buf1;
cin.getline(buf2,5); // 这里似乎不等待输入

return 0;
}


而解决办法如下:

int main()
{
char buf1[5]={0};
char buf2[5]={0};

cin >>buf1;
cin.ignore(); // 或者 cin.sync(); 之类的
cin.getline(buf2,5);

return 0;
}


这是为什么呢?

因为,首先, Windows 上敲一下回车键,实质上是输入两个字符:回车符,紧跟着换行符。这两个字符的 ASCII 码分别为 0x0D 和 0x0A,一般来说,其C++转义表示分别为 '\r' 和 '\n'。然后,cin>> 默认是以一个或多个接连的白空格为间隔,cin.getline
默认则以单个换行符(0x0A)为间隔。回车符和换行符都属于白空格。

这里不讨论为什么 Windows 上敲回车键会输入这两个字符,以及这两个字符本来应该对应什么动作(如果存在“本来应该”这么一说的话)。

为了展示这个看不见的回车键敲击,用 istringstream 举个例子:

void disp(char *buf,int n)
{
for(int i=0;i<n;++i)
printf("0x%02X ",buf[i]);
printf("\n");
}

int main()
{
disp("\r\ns1\r\ns2",9);
// 这相当于在控制台敲回车键,然后敲入s1,然后敲回车键,然后敲入s2
// 0x0D 0x0A 0x73 0x31 0x0D 0x0A 0x73 0x32 0x00
printf("\n");

{
istringstream iss("\r\ns1\r\ns2");
char buf1[5]={0};
char buf2[5]={0};

iss >>buf1;
iss >>buf2;

disp(buf1,5); // 0x73 0x31 0x00 0x00 0x00
disp(buf2,5); // 0x73 0x32 0x00 0x00 0x00
}

printf("\n");

{
istringstream iss("\r\ns1\r\ns2");
char buf1[5]={0};
char buf2[5]={0};

iss.getline(buf1,5);
iss.getline(buf2,5);

disp(buf1,5); // 0x0D 0x00 0x00 0x00 0x00
disp(buf2,5); // 0x73 0x31 0x0D 0x00 0x00
}

return 0;
}


用 cin 的道理是一样的。区别在于相关的标准库函数会把 0x0D 转换为 0x0A,这就相当于回车键最终敲入缓冲区的是接连的两个换行符。由于这不影响讨论,下文还是用 0x0D 指代。

cin>> 每读到其所期待的东西后碰到 0x0D,就“断”一下,紧跟着的 0x0A 还在缓冲里。此时,如果改用 cin.getline() ,0x0A 立即被读入,而该间隔符前面没有字符,于是就有了 getline 已完成却没有 get 到 line 的错觉。而如果没有改用 cin.getline(),继续用cin>>,那么 cin>> 碰到紧跟着的 0x0A 时,这是在还没读到其所期待的东西就碰到了白空格,它的反应就是跳过该字符(这正是
cin.ignore(); 要做的),接着继续去读其所期待的东西。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: