scanf for only ONE char - c++

I need to be able to detect extraneous input and exit my program.
If I input a string of more than 1 char into scanf("%c", &var); it takes the first letter and stores it into var but the programs continues.
I tried to use if (scanf("%c", &var) != 1) but it returns 1 every time no matter the input so its no difference.
I know other functions like fgets() may be better suited for this but I have been instructed to use the scanf() function.
How should I do this?

When reading user input scanf can take its input from a file, or the console.
When reading from the console, the data becomes available to the program only when a line break is added. This means anything that was typed on the same line, is read.
Imagine I have a maze program, and it wants me to choose which way to go....
while( !atGoalLocation() ) {
printf( "Which direction (f)orward (l)eft (r)ight?\n" );
scanf( "%c", &dir );
processDirection( dir );
}
I could either enter the route through the maze as
f
l
f
r
f
f
Or it may also be correct to enter my input as
flfrff
Depending on your task, they may mean the same thing.
If you want to allow either of these inputs, then make sure you eat the white space by adding " " to the scanf.
if( scanf( " %c", &dir ) == 1 )
If the line break version is the only method you want to accept, then you should separate the lines and then try the scan.
char line[200];
while( fgets( line, sizeof( line ), stdin ) != NULL ){
sscanf( line, "%c", &dir );
Also for C++ we should be using the std::cin and std::cout. However the same complications occur for unread characters on the same line, so I would still use a line based parser.
std::string line;
while( std::getline( std::cin, line ) ){
// here we could parse the line using std::strstream to decode more complext things than a char.
dir = line[0];

You need to add a space before the %c:
scanf(" %c",&var);

And if you just dont want your program to wait for an enter after typing the character, use getch() defined in "conio.h"
c = getch();
OR
In scanf("%c",&var); you could add a newline character \n after %c in order to absorb the extra characters.
scanf("%c\n",&in);

Related

How does C++ buffer work(about whitespace)?

Assume that i put ' 123abc' as input in C++ console application.
if i get input as
int a; char ch;
scanf("%d", &a);
scanf("%ch", &ch);
i got 123 in a, 'a' in ch. Right?
Then, where does 4 blanks go? scanf just blow away blanks?
Is there no way can i get that blanks after i get 123abc?
To sum it up my question,
When i get int input with scanf, does scanf blow away blank in buffer?
What does happen i execute that code?
Can i get 4 blanks in ' 123abc' after i get '123' and 'a'?
As others pointed out, you really should read scanf documentation so you can see which specifier will be able to read whitespaces.
Regarding your first question:
When i get int input with scanf, does scanf blow away blank in buffer? What does happen i execute that code?
For numeric inputs, scanf will ignore any whitespace character.
When you execute scanf("%d", &a); it will go over the spaces (or any other whitespace character) until it finds a digit and start reading a decimal integer (as specified by %d).
Regarding your second question:
Can i get 4 blanks in ' 123abc' after i get '123' and 'a'?
I'm not sure what you mean here, you want to read a past value after having gone through the whole buffer?
You won't be able to do this.
If you need the spaces, get them before reading anything else.
Or read the whole buffer into your own buffer and deal with it.
There are many ways to deal with this.
Here's an example:
#include <cstdio>
int main()
{
{
printf( "Reading into your own buffer:\n" );
char my_buffer[128];
scanf( "%127[^\n]%*c", my_buffer ); // the %*c is to throw away the trailing \n
printf( "my_buffer: [%s]\n", my_buffer );
}
{
printf( "Reading each part separately:\n" );
char spaces[5];
int number;
char remaining_chars[4];
scanf( "%4[ ]", spaces );
scanf( "%d", &number );
scanf( "%3s", remaining_chars );
printf( " spaces: [%s]\n", spaces );
printf( " number: [%d]\n", number );
printf( "remaining_chars: [%s]\n", remaining_chars );
}
return 0;
}
And here is a sample run:
Reading into your own buffer:
123abc
my_buffer: [ 123abc]
Reading each part separately:
123abc
spaces: [ ]
number: [123]
remaining_chars: [abc]
I recommend you to read this documentation about scanf.
Whitespace character: the function will read and ignore any whitespace
characters encountered before the next non-whitespace character
(whitespace characters include spaces, newline and tab characters --
see isspace). A single whitespace in the format string validates any
quantity of whitespace characters extracted from the stream (including
none).
and if you wont to read sentence you can use fscanf or getline
EDIT This is how to do it -
scanf(" %[^\n]",str);
the anser is from this qustion here

C++ strtok - multiple use with more data buffers

I have little issue with using strtok() function.
I am parsing two files. Firts I load file 1 into buffer. This file constains name of the second file I need to load. Both files are read line after line. My code looks like this:
char second_file_name[128] = { "" };
char * line = strtok( buffer, "\n" );
while( line != NULL )
{
if ( line[0] = 'f' )
{
sscanf( line, "%*s %s", &second_file_name );
LoadSecondFile( second_file_name );
}
// processing other lines, not relevant for question
line = strtok( NULL, "\n" );
}
While the LoadSecondFile(...) function works in pretty same way, thus:
char * line = strtok( buffer, "\n" );
while( line != NULL )
{
// process file data
line = strtok( NULL, "\n" );
}
What my problem is, after calling the LoadSecondFile(...) function, the strtok() pointer used for parsing the first file gets "messed up". Instead of giving me line that follows the name of the second file, it gives me nothing - understand as "complete nonsense". Do I get it right that this is caused by strtok() pointer being shared in program, not only in function? If so, how can I "back up" the pointer of strtok() used for parsing first file before using it for parsing second file?
Thanks for any advice.
Cheers.
strtok is an evil little function which maintains global state, so (as you've found) you can't tokenise two strings at the same time. On some platforms, there are less evil variants with names like strtok_r or strtok_s; but since you're writing C++ not C, why not use the C++ library?
ifstream first_file(first_file_name); // no need to read into a buffer
string line;
while (getline(first_file, line)) {
if (!line.empty() && line[0] == 'f') { // NOT =
istringstream line_stream(line);
string second_file_name;
line_stream.ignore(' '); // skip first word ("%*s")
line_stream >> second_file_name; // read second word ("%s")
LoadSecondFile(second_file_name);
}
}
You can use strtok_r which allows you to have different state pointers.
Which is why it is constantly recommended to not use strtok
(not to mention the problems with threads). There are many
better solutions, using the functions in the C++ standard
library. None of which modify the text they're working on, and
none of which use hidden, static state.

How can you ignore from cin until it goes to the next line?

If you have a text file that you're reading character by character with cin:
char text;
cin >> text;
cout << char << endl;
Suppose you want to ignore any lines that start with ">" until the new line, how can you do that?
You can compare the char read for '>' using::
int strncmp ( const char * str1, const char * str2, size_t num );
If found, skip till char read equals '\n' i.e., skip till strncmp returns 0 for ( char, '\n', 1 )
Typically you want to use std::istream::ignore, something like:
static const int max_line = 65536;
if (text == ">")
std::cin.ignore(max_line, '\n');
Note that I've specified a maximum distance to skip of 64K bytes. Many people recommend something like std::numeric_limits<std::streamsize>::max(), which basically means to skip any amount of text until you find the delimiter (new-line, in this case).
IMO, specifying such a huge number is usually a poor idea -- if you go for too long without seeing a new-line, it's safe to stop and assume that you've gotten bad data. As soon as you've read enough to be reasonably certain there's a problem, it's better to stop and warn the user, rather than spending minutes with the program apparently locked up, reading gigabytes of useless data (and then probably giving the user an error message anyway).
Another possibility (especially if you're fairly sure you'll get good input) is to start by reading a full line (e.g., with std::getline), then if it starts with a >, just skip processing the line, and go back to read the next one.

C++, user input check for '\0' stops at spaces?

If the user inputs a sentence containing spaces the while loop stops at one of these spaces. Why is this happening? are '\0' and a space the same or did i do something else wrong?
int main ( )
{
char user_input[200];
cin>>user_input;
int i=0;
while(user_input[i]!='\0')
{
i++;
}
cout<<i;
return 1;
}
Thanks everyone, I appreciate your help.
\0 is the null terminating character with ASCII code 0.
Space is another character with ASCII 32 i suppose.
In fact you are doing this.
cin >> user_input;
It takes input till you press space or enter. So no space is present in your user_input string.
Use this instead of cin.
cin.getline (user_input, 200, '\0') ;
This is an issue with reading using >> into a char array. It splits at whitespace when tokenizing. Try printing user_input to screen to confirm this.
Using getline into a std::string is generally safer in this context (as mentioned by daknøk). And I assume the input is likely to be terminated by a carriage return?
std::string user_input;
std::getline( std::cin, user_input, '\n' );
This is because your input stops reading when white space is entered. You can use
cin.unsetf(ios::skipws)
By default it is set to skip white spaces. With this you will get your desired result.

Using cin.eof()

I have some code and I wanted to use cin.eof() to stop my program from reading the input. I was thinking of doing:
char array[10]
while(!cin.eof())
{
for(int i = 0; i < 10; i++)
{
cin >> array[i];
}
}
And the code goes on. However, when I click '\n', my output is outputted. When i click cntrl + d, (on a UNIX terminal) the program performs the output again and then proceeds to end. How do I get it so that my program stops reading at a newline and prints my output when I type cntrl + d only once?
Thanks.
First, cin.eof() doesn't do anything useful until input has failed.
You never want to use it at the top of a loop.
Secondly, it's not really clear to me what you are trying to do.
Something like:
std::string line;
while ( std::getline( std::cin, line ) ) {
// ...
}
perhaps? This will read a line of text into the variable line, until
end of file; when you encounter an end of file, the input will fail, and
you will leave the loop.