【问题标题】:Why does this call to isspace() never return true? [duplicate]为什么这个对 isspace() 的调用永远不会返回 true? [复制]
【发布时间】:2014-01-18 13:15:59
【问题描述】:

这可能之前被问过 100 次,但我找不到或提出解决方案。 一切(据我测试)都被识别,只有紧迫的空间不起作用。我正在输入一个空格+回车,光标只是移动到下一行,没有任何反应。我怎样才能做到这一点?

#include <cstdlib>
#include <iostream>
#include <cctype>

using namespace std;


int main(int argc, char** argv) {
    cout << "Press a key please:  " << endl;
    char key;
    cin >> key;

    if (isalpha(key))
        cout << key << " is a letter." << endl;
    else if (isdigit(key))
        cout << key << " is a number." << endl;
    else if (isspace(key))
        cout << key << " is a space." << endl;
    else if (ispunct(key))
        cout << key << " is a punctuation" << endl;
    return 0;
}

【问题讨论】:

  • 做一些调试。当你按下空格时,key 里面是什么?
  • “这可能之前被问了 100 次” 是的,一个简单的搜索就会显示 this
  • @DavidHeffernan 32 ' ' 。我找了空间的 ANSII 代码,它是 32,但不知道如何使用它。
  • 这不是真的。 cin &gt;&gt; key 没有在 key 中添加空格。
  • @P0W 我已经搜索过了。我能找到的唯一参考是如何用isspace 识别字符串中的空格。那是在cplusplus.com/reference/locale/isspace

标签: c++


【解决方案1】:

当您使用格式化输入函数(即operator&gt;&gt;())时,默认情况下输入将跳过前导空格。如果您想读取可能是空格的char,则需要使用std::noskipws 操纵器来禁用此跳过:

if (std::cin >> std::noskipws >> c) {
    // ...
}

或者,您可以使用未格式化的输入函数,例如get(),在不更改流设置的情况下读取单个字符:未格式化的输入函数不会跳过前导空格(在格式化输入之间切换时,这通常会导致悲伤,例如, 对于int 和未格式化的输入,例如,使用std::getline() 读取一行):

if (std::cin.get(c)) {
    // ...
}

另外,请注意,您只能将正值(和EOF)传递给任何is....() 函数,但char 已在许多平台上签名。您需要先将您的 char 转换为合适的值,例如使用以下值之一

isspace(static_cast<unsigned char>(c))
isspace(std::char_traits<char>::to_int_type(c))

【讨论】:

  • 您也可以将 EOF 传递给 is*() 函数,但这并不会影响您的观点,即参数应该是 unsigned char 字符表示的 int 值(或 EOF)。
  • @JonathanLeffler:谢谢!我已经更正了答案。
  • 我会提到istream::get()。一般单字符输入的最自然选择,恕我直言。对于 OP 的具体情况,我还建议添加 istream::ignore( -1, '\n' )。在检查 -1 会产生必要的最大值之后很好(虽然很确定)。
  • @Cheersandhth.-Alf:我在get() 上添加了一条声明。是否需要忽略任何事情是一个不同的主题(并且看不到任何原因)。当然,合适的常量的拼写是 not -1 而是 std::numeric_limits&lt;std::streamsize&gt;::max()
【解决方案2】:

问题是,cin 使用空格作为分隔符(也是制表符、换行符)。因此,您必须阅读您的输入忽略分隔符:

cin >> noskipws >> x;

也可以将get 用于单个字符:

cin.get(x);

也可以看看How to cin Space in c++?

【讨论】:

  • 这行得通。几乎有它,cin.get(key) &gt;&gt; key;,但这并没有计算出来。
  • 因为这没有任何意义......
  • 奇怪的是他们在书中没有使用cin.get(),而且互联网上至少有一个例子没有使用它。书上说cin &gt;&gt; key
  • 因为这是在 C++ 中阅读某些内容以及他们应该提到的书中某处的方式,它将空格和内容作为分隔符处理。
  • 第 537 页:重载运算符&gt;&gt; 自动跳过空格,一次只返回一个单词(字符串)。
【解决方案3】:

cin 默认跳过所有空格(空格、制表符、换行符等)。您可以更改其行为,或使用稍微不同的机制。要更改其行为,请使用操纵器 noskipws,如下所示:

char key;
cin >> noskipws >> key;

您可以在此处“How to cin Space in c++?”阅读更多相关信息。

【讨论】:

  • 感谢您改进答案!
  • 感谢指导,不断学习!
【解决方案4】:

如何读取空格字符。

替换这个:

cin >> key;

跳过空格将文本留在输入缓冲区中,这样:

auto const max_streamsize = numeric_limits<streamsize>::max();

key = char( cin.get() );
cin.ignore( max_streamsize, '\n' );

不跳过空格,并消耗所有输入行。

不使用所有输入行(例如终止符'\n')的问题在于,接下来的输入操作将读取剩余的文本,而无需首先等待物理用户输入。


如何使用 C 字符分类函数。

isalpha 等 C 函数需要 非负 字符代码,或者特殊值 EOF 作为参数。

但是,对于大多数 C++ 编译器,char 是默认签名的。一般来说,这意味着正式的 Undefined Behavior 如果它直接传递给例如isalpha。例如,通过将char 直接传递给isalpha,检查char 值'ø'(挪威小写Ø)是否按字母顺序排列,对于大多数C++ 编译器来说是未定义行为,并且可能在Visual C++ 和其他一些编译器的调试模式下崩溃编译器。

一个简单的解决方案是将其转换为unsigned char(注意:不能通过这种方式传递EOF):

typedef unsigned char UChar;

... isalpha( UChar( ch ) ) ...

完整示例,如原代码:

#include <iostream>
#include <limits>       // std::numeric_limits
#include <ctype.h>      // isalpha etc.
using namespace std;

auto main()
    -> int
{
    typedef unsigned char UChar;
    auto const max_streamsize = numeric_limits<streamsize>::max();

    for( ;; )
    {
        cout << "Type a character please (x to exit):  ";
        char const key = char( cin.get() );
        cin.ignore( max_streamsize, '\n' );

        if( key == 'x' ) { break; }

        if( isalpha( UChar( key ) ) )
            cout << key << " is a letter." << endl;
        else if( isdigit( UChar( key ) ) )
            cout << key << " is a number." << endl;
        else if( isspace( UChar( key ) ) )
            cout << key << " is a space." << endl;
        else if( ispunct( UChar( key ) ) )
            cout << key << " is a punctuation" << endl;
        else
            cout << key << " is some unknown kind of character" << endl;
    }
}

【讨论】:

    猜你喜欢
    • 2016-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    相关资源
    最近更新 更多