| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 712 人关注过本帖
标题:以回车键停止字符读入的问题
只看楼主 加入收藏
xiedj
Rank: 1
等 级:新手上路
帖 子:62
专家分:0
注 册:2013-5-30
结帖率:66.67%
收藏
已结贴  问题点数:20 回复次数:9 
以回车键停止字符读入的问题
核心代码如下:
void input(char* p)
{
    int i=1;
    do
    {
        cin>>p[i++];
    }while(cin.peek()!='\n');//可行
    //while(_getch()!='\n');//不可行
    //while(getchar()!='\n');//不可行
    //while(cin.get()!='\n');//不可行
    //while(p[i]!='\n');//不可行
    //while(getch()!='\n');//不可行
    p[size-1]='\0';

    return;
}
形参p接收一个字符数组的首地址,程序的要求是输入字符直至遇到回车键退出输入,但是只有一个while条件可行,求逐条解释,不可行的原因,谢谢!
搜索更多相关主题的帖子: return 
2015-05-07 15:41
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9025
专家分:54030
注 册:2011-1-18
收藏
得分:5 
先问一下,为什么不直接用 std::getline 来读取一行?

回正题:因为 getchar() 等将字符取走了,而 peek() 并没有将字符取走。
伪代码大体如下
size_t i = 0;
for( int c; c=getchar(), c!=EOF && c!='\n'; )
    p[i++] = c;
p[i] = '\0';

2015-05-07 16:01
xiedj
Rank: 1
等 级:新手上路
帖 子:62
专家分:0
注 册:2013-5-30
收藏
得分:0 
因为要从字符数组的第二个字符开始读入(第一个预留有其他用处),getline()和cin.get()都可以实现读入,尝试了一下单个读入就发现了问题,之后查了各种资料,各种尝试,还是有各种问题,而且这样单个输入还有溢出的问题,会使程序崩溃。
能详细说明一下“getchar() 等将字符取走了,而 peek() 并没有将字符取走。”吗?
MSDN上也没有很详细的说明这几个的函数的具体实现过程,只说是从输入流读入字符,倒是cin.peek()在MSDN上详细的说明了
“Returns the next character without extracting it from the stream”。
2015-05-07 21:24
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:5 
peek是探测下一个数据,即只看一看,但没有实际提取的动作,当发现下一个字符是'\n',就结束循环,然后在结束后还需要实际把'\n'字符提取出来,不然堵塞住后面的读取动作。getchar()才是实际提取数据的。其实,这种peek方案也并不总是有效的,实际多操作就知道了。

授人以渔,不授人以鱼。
2015-05-07 22:28
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:10 
不能仅靠检测到'\n'字符来结束循环,那仍然免不了溢出,因为在遇到回车之前,你无法预测有多少字符,而这些字符是你需要储存起来的,你预留的空间无法保证大于用户可能的输入数。所以,本质上这与预留足够大的空间简单读取没什么区别。要避免溢出,你必须结合限制長度来实现——这就是vc++扩展scanf_s()、gets_s()之类函数带计数参数的原因,所有“安全类型函数”,本质上都是附加了计数器参数,这在原始的C库函数中是没有的,也没有任何更有效的办法去取代,避免不用那些函数(自己写)才是唯一的办法。

授人以渔,不授人以鱼。
2015-05-07 23:08
xiedj
Rank: 1
等 级:新手上路
帖 子:62
专家分:0
注 册:2013-5-30
收藏
得分:0 
查了各种博客和资料,大致知道了原因:这些具体输入的具体执行情况是不一致的,汇总如下:
/*
    cin.peek()返回输入流的下一个字符,其不会从输入流提取字符,
    故当其检测到'\n'时即结束输入,但由于其不提取输入流的字符,
    故要注意对输入流中的'\n'进行处理,即在其后添加fflush(stdin),
    以清空缓存。
    */
   
    //while(ch!='\n');或者while(ch!='\n');//不可行
    /*
    getchar()(cin.get()同理)的过程详细分析:
    输入的数据实际上的流向是: 输入设备->内存缓冲区->程序getchar  
    首先,先读入p[1](即对p[1]赋值),ch=getchar()读取下一个字符,即ch=p[2],
    再读入p[2],ch=getchar()读取下一个字符,即ch=p[4],以此类推下去。
    */

    //while(p[i]!='\n');//不可行
    /*
    cin根据后面变量的类型读入数据,其输入结束条件是遇到空格、回车或Tab键;
    其对结束字符的处理是:丢弃缓冲区中的结束符(即空格、回车或Tab键),
    因此,使用cin>>p[i]会对回车等结束符,故这是一个永真循环,永远无法得到回车符,
    也就不能依此写循环判别的条件了。
    */

    //while(getch()!='\n');//不可行
    /*getch()的过程详细分析:
    首先读入p[1],之后等待键盘输入,如果键盘输入为回车(其ASC码为13,注意:不能写成ch!='\n'),
    因为ch存放的并不回车(可以通过输出验证:当输入回车时ch=' '),则输入退出,此时只得到p[1]的输入
    (即使输入的是"123"),否则继续输入p[2],以此类推下去。
    由此可知,采用该方法输入显得异常麻烦,故不推荐。
    */
2015-05-08 14:33
xiedj
Rank: 1
等 级:新手上路
帖 子:62
专家分:0
注 册:2013-5-30
收藏
得分:0 
谢谢各位了
2015-05-08 14:34
xiedj
Rank: 1
等 级:新手上路
帖 子:62
专家分:0
注 册:2013-5-30
收藏
得分:0 
另外,关于cin.get()和cin.getline()也顺带提一下,具体的可查阅其他资料:
cin.getline(数组名,读入长度,结束符) 大体与 cin.get(数组名,读入长度,结束符)类似。
它们都会丢弃缓冲区中的结束符(如回车);
两者的区别在于:
cin.get()当输入的字符串超长时,不会引起cin函数的错误,后面的cin操作会继续执行,只是直接从缓冲区中取数据。
但是cin.getline()当输入超长时,会引起cin函数的错误,后面的cin操作将不再执行。

2015-05-08 14:46
快速回复:以回车键停止字符读入的问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.012778 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved