0

Probably this is asked 100 times before, but i can't find or produce a solution. Everything (as far as i have tested) is recognized, only pressing space is not working. I'm typing a space + hit enter, the cursor just moves to the next line and nothing happens. How can i make this work?

#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;
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
WonderWorld
  • 956
  • 1
  • 8
  • 18
  • Do some debugging. What is in `key` when you press space? – David Heffernan Dec 31 '13 at 16:16
  • _"Probably this is asked 100 times before"_ yes a simple search would have shown [this](http://stackoverflow.com/q/2765462/1870232) ! – P0W Dec 31 '13 at 16:24
  • @DavidHeffernan `32 ' '` . I have looked for the ANSII code for space and it is 32, but couldn't figure out how to use it. – WonderWorld Dec 31 '13 at 16:25
  • 1
    That's not true. `cin >> key` does not put a space in `key`. – David Heffernan Dec 31 '13 at 16:27
  • @P0W i have searched. Only reference i could find is how to identify spaces in a string with `isspace`. That is in the http://www.cplusplus.com/reference/locale/isspace/ – WonderWorld Dec 31 '13 at 16:27
  • @Xbit `isspace` works fine. But `key` does not contain a space. Seriously what you really need to do is to learn some debugging. Almost any debugging would have led you to the realisation that a space was not being placed in `key`. – David Heffernan Dec 31 '13 at 16:31
  • @DavidHeffernan you are right, it gave `32 ' '` with `cin.get(key)`. Usually i do use breakpoints and debug, but for some reason it wasn't working before. – WonderWorld Dec 31 '13 at 16:40
  • Try doing this: cin >> noskipws >> key; – João Pinho Dec 31 '13 at 16:42
  • That is because the whitespace was eaten. The debugging showed you that. – David Heffernan Dec 31 '13 at 16:42

4 Answers4

5

When you use the formatted input functions (i.e., operator>>()) the input will skip leading whitespace by default. If you want to read a char which may be a space, you'll need to use the std::noskipws manipulator to disable this skipping:

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

Alternatively, you can use unformatted input functions, e.g., get() to read individual characters without changing the stream setup: the unformatted input functions don't skip leading whitespaces (which is often causing grief when changing between formatted input, e.g., for an int, and unformatted input, e.g., reading a line using std::getline()):

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

Also, note that you can only pass positive values (and EOF) to any of the is....() functions but char is signed on many platforms. You need to turn your char into a suitable value first, using, e.g., one of

isspace(static_cast<unsigned char>(c))
isspace(std::char_traits<char>::to_int_type(c))
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 2
    You can also pass EOF to the `is*()` functions, but that doesn't detract from your point that the argument is supposed to be the `int` value of an `unsigned char` representation of the character (or EOF). – Jonathan Leffler Dec 31 '13 at 16:22
  • @JonathanLeffler: Thanks! I have corrected the answer. – Dietmar Kühl Dec 31 '13 at 16:31
  • I would mention `istream::get()`. the most natural choice for general single-character input, imho. for the OP's specific case I would also recommend adding a `istream::ignore( -1, '\n' )`. well after checking that -1 would produce the requisite max value (pretty sure of that though). – Cheers and hth. - Alf Dec 31 '13 at 17:00
  • @Cheersandhth.-Alf: I added a statement on `get()`. Whether anything needs to be ignored is a different topic (and don't see any reason it is). Of course, the spelling for the suitable constant is _not_ `-1` but `std::numeric_limits::max()`. – Dietmar Kühl Dec 31 '13 at 17:08
4

The problem is, that cin uses whitespace as a separator (also tab, newline). Therefore, you have to read your input ignoring the separator:

cin >> noskipws >> x;

Alternatively use get for single characters:

cin.get(x);

Also have a look at How to cin Space in c++?

Community
  • 1
  • 1
Sebastian
  • 8,046
  • 2
  • 34
  • 58
3

cin skips all whitespace (spaces, tabs, new lines, etc.) by default. You can either change its behavior, or use a slightly different mechanism. To change its behavior, use the manipulator noskipws, as follows:

char key;
cin >> noskipws >> key;

You can read more about this here 'How to cin Space in c++?'.

Community
  • 1
  • 1
João Pinho
  • 3,725
  • 1
  • 19
  • 29
1

How to read a space character.

Replace this:

cin >> key;

which skips whitespace and leaves text in the input buffer, with this:

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

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

which doesn't skip whitespace, and consumes all of the input line.

The problem with not consuming all of an input line, such as the terminating '\n' character, is that this remaining text will then be read by the next input operation, without first waiting for physical user input.


How to use the C character classifier functions.

The C functions such as isalpha require a non-negative character code, or else the special value EOF, as argument.

With most C++ compilers the char is, however, signed by default. In general that means formal Undefined Behavior if it's passed directly to e.g. isalpha. For example, checking whether a char value 'ø' (Norwegian lowercase Ø) is alphabetical, by passing it straight to isalpha, is Undefined Behavior with most C++ compilers, and may crash in debug mode with Visual C++ and some other compilers.

A simple solution is to cast it to unsigned char (note: cannot pass EOF this way):

typedef unsigned char UChar;

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

Complete example, like the original code:

#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;
    }
}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331