What does this do : while((c= getchar()) != '\n' && c != EOF); - c++

while((c= getchar()) != '\n' && c != EOF);
I was facing a problem by using gets() to enter strings. I found on google that it was keeping the value of '\n' in the input buffer. I searched here and found the above code to solve my problem. However I don't quite get the hold of it. What does this do ?? Anybody please enlighten me.

An assignment in C++ will also yield the value being assigned. So c= getchar() is reading the next character from the file, and (c= getchar()) != '\n' is comparing that read character to the newline character. There's another test for the special EOF value, to make sure it doesn't keep trying to read once you reach the end of the file.
There's no statement between the while and the closing semicolon because nothing else needs to be done, you're throwing the input away.

The code introduces a while-loop. Its exit condition assigns the integer c the value that getchar() returns, and checks whether it is equal to the newline character ('\n') or EOF. If it is, the loop exits. If it isn't, the next character is extracted, and so on.
The code basically skips all characters until the next newline or EOF is reached. It is equivalent to:
for (;;)
{
c = getchar(); // c has been declared elsewhere
if (c == '\n' || c == EOF)
break;
}

Related

Issues with reading from a .txt file c++

I was seeking some help on an issue. I have to read certain "passwords" from a .txt file, like "abE13#" and do some simple error checking to make sure they fit certain requirements. But at the current moment, it's printing out the passwords (which is meant to be done), but it's ignoring the checking and gets stuck in a loop where new lines are being printed out. I'm sure it has to do something with while(ch!='\n') but I'm not all that sure what is needed there in place of that to check.
ch = inFile.get();
while(!inFile.eof())
{
while(ch != '\n')
{
cout << ch;
if(isalpha(ch))
{
charReq++;
if(isupper(ch))
uppercaseReq++;
else
lowercaseReq++;
}
else if(isdigit(ch))
{
charReq++;
digitReq++;
}
else if(isSpecial(ch))
{
charReq++;
specialCharReq++;
}
if(uppercaseReq < 1)
cout << "\n missing uppercase" << endl;
ch = inFile.get();
}
}
It's supposed to kind of follow this format,
Read a character from the password.txt file
while( there are characters in the file )
{
while( the character from the file is not a newline character )
{
Display the character from the file
Code a cascading decision statement to test for the various required characters
Increment a count of the number of characters in the password
Read another character from the password.txt file
}
Determine if the password was valid or not. If the password was invalid,
display the things that were wrong. If the password was valid, display that it
was valid.
Read another character from the file (this will get the character after the
newline character -- ie. the start of a new password or the end of file)
}
Display the total number of passwords, the number of valid passwords, and the
number of invalid passwords
It keeps prints because of this while(inFile). This is always true. Change it to an if statement just to check if file is open:
if ( inFile )
EDIT: It will stop at the first password because of this while(ch != '\n'). When he gets to the end of the first password ch will be '\n', while fails and stop reading. Change it to:
while( !inFile.eof() )
while( the character from the file is not a newline character )
You have converted this line of pseudocode into this line of c++ code:
while (ch != '\t')
'\t' is the tab character, not the newline character. This could definitely cause problems as to why you are never ending and instead just printing out new lines (Really EOF, but you don't see that).
'\n' is the newline character.
Give that a try.
EDIT:
Also, your only checking for an entire ifstream to be false. I don't quite know when that would happen, but I would recommend checking for the EOF flag. Your code should turn into something along the lines of this:
while( !inFile.eof() )
{
while(ch != '\n' && !inFile.eof() )
{
// ...
}
}
If you don't check for infile twice, you may end up in an infinite loop.
while(infile.good())
{
while (inFile.good() && ch != '\n')
{
...
}
if (ch == '\n')
{...}
else
{...}
}

Simple C++ not reading EOF

I'm having a hard time understanding why while (cin.get(Ch)) doesn't see the EOF. I read in a text file with 3 words, and when I debug my WordCount is at 3 (just what I hoped for). Then it goes back to the while loop and gets stuck. Ch then has no value. I thought that after the newline it would read the EOF and break out. I am not allowed to use <fstream>, I have to use redirection in DOS. Thank you so much.
#include <iostream>
using namespace std;
int main()
{
char Ch = ' ';
int WordCount = 0;
int LetterCount = 0;
cout << "(Reading file...)" << endl;
while (cin.get(Ch))
{
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
cout << "Number of words => " << WordCount << endl;
return 0;
}
while (cin >> Ch)
{ // we get in here if, and only if, the >> was successful
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
That's the safe, and common, way to rewrite your code safely and with minimal changes.
(Your code is unusual, trying to scan all characters and count whitespace and newlines. I'll give a more general answer to a slightly different question - how to read in all the words.)
The safest way to check if a stream is finished if if(stream). Beware of if(stream.good()) - it doesn't always work as expected and will sometimes quit too early. The last >> into a char will not take us to EOF, but the last >> into an int or string will take us to EOF. This inconsistency can be confusing. Therefore, it is not correct to use good(), or any other test that tests EOF.
string word;
while(cin >> word) {
++word_count;
}
There is an important difference between if(cin) and if(cin.good()). The former is the operator bool conversion. Usually, in this context, you want to test:
"did the last extraction operation succeed or fail?"
This is not the same as:
"are we now at EOF?"
After the last word has been read by cin >> word, the string is at EOF. But the word is still valid and contains the last word.
TLDR: The eof bit is not important. The bad bit is. This tells us that the last extraction was a failure.
The Counting
The program counts newline and space characters as words. In your file contents "this if fun!" I see two spaces and no newline. This is consistent with the observed output indicating two words.
Have you tried looking at your file with a hex editor or something similar to be sure of the exact contents?
You could also change your program to count one more word if the last character read in the loop was a letter. This way you don't have to have newline terminated input files.
Loop Termination
I have no explanation for your loop termination issues. The while-condition looks fine to me. istream::get(char&) returns a stream reference. In a while-condition, depending on the C++ level your compiler implements, operator bool or operator void* will be applied to the reference to indicate if further reading is possible.
Idiom
The standard idiom for reading from a stream is
char c = 0;
while( cin >> c )
process(c);
I do not deviate from it without serious reason.
you input file is
this is fun!{EOF}
two spaces make WordCount increase to 2
and then EOF, exit loop! if you add a new line, you input file is
this is fun!\n{EOF}
I took your program loaded it in to visual studio 2013, changed cin to an fstream object that opened a file called stuff.txt which contains the exact characters "This is fun!/n/r" and the program worked. As previous answers have indicated, be careful because if there's not a /n at the end of the text the program will miss the last word. However, I wasn't able to replicate the application hanging in an infinite loop. The code as written looks correct to me.
cin.get(char) returns a reference to an istream object which then has it's operator bool() called which returns false when any of the error bits are set. There are some better ways to write this code to deal with other error conditions... but this code works for me.
In your case, the correct way to bail out of the loop is:
while (cin.good()) {
char Ch = cin.get();
if (cin.good()) {
// do something with Ch
}
}
That said, there are probably better ways to do what you're trying to do.

Traversing hex input that could have 0xff in it in C++

I am traversing hex input from stdin in my code, and I noticed that I can't get around my code stopping when a 0xff byte is reached. I know that this happens because loop is :
while( (c=getchar()) != EOF)
However, I can't leave this out because otherwise getchar is called after the real End-Of-File and it segfaults. How can I traverse the full input correctly?
(sorry I know that there should be a simple answer to this seemingly common task but I tried searching for some time and found nothing)
You have declared c as a char, but getchar() returns an int. The correct loop construct for C is this:
int c;
while ( (c = getchar()) != EOF ) {
// use c here.
}

what does -1 represent in ASCII?

I'm working on an automatic summarization system in my C++ class and have a question regarding one of the ASCII comparisons I'm doing. Here's the code:
char ch;
string sentence;
pair<char, char> sentenceCheck;
int counter = 0;
while (!ifs2.eof())
{
ch = ifs2.get();
ch = tolower(ch);
if (ch == 13)
ch = ifs2.get();
if (ch != 10 && ch != '?' && ch != '!' && ch != '.')
sentence += ch;
sentenceCheck.first = sentenceCheck.second;
sentenceCheck.second = ch;
cout << sentenceCheck.first << "-" << (int)sentenceCheck.first << " ---- " << sentenceCheck.second << "-" << (int)sentenceCheck.second << endl;
if(sentenceCheck.second == ' ' || sentenceCheck.second == 10 || sentenceCheck.second == -1)
{
if(sentenceCheck.first == '?' || sentenceCheck.first == '!' || sentenceCheck.first == '.')
{
istringstream s(sentence);
while(s >> wordInSentence)
{
sentenceWordMap.insert(pair<string, int>(wordInSentence, 0));
}
//sentenceList.push_back(pair<string, int>(sentence, 0));
sentence.clear();
}
}
}
What is being done here (with the two if statements) is checking whether a new sentence has begun in the text that is to be analyzed and dealt with later. The conditionals work but only because we discovered that we have to check for that -1 as well. Any ideas what that represents?
-1 doesn't represent anything in ASCII. All ASCII codes are in the range [0, 127]. It's not even guaranteed by C++ that -1 is a valid value for a char.
The problem is that you're not checking the return value from ifs2.get(), which returns an int (not a char!) that may be -1 on end of file. The proper way to check for this is
int ch = ifs2.get();
if (!ifs2)
// break the loop
because the EOF value is not guaranteed to be -1 (it's actually std::char_traits<char>::eof()).
(Btw., you shouldn't write ASCII codes as magic numbers; use \n for linefeed, \r for carriage return.)
The while is incorrectly structured: you need to check eof() immediately after get():
for (;;)
{
ch = ifs2.get();
if (ifs2.eof()) break;
ch = tolower(ch);
if (ch == 13)
{
ch = ifs2.get();
if (ifs2.eof()) break;
}
...
}
The -1 is probably the EOF indicator.
Note (as has already been stated) get() returns an int, not a char.
As an ASCII character -1 doesn't represent anything (which is to say -1 is not a valid ASCII value). As the return value from get() it means that the read operation failed - most likely due to the end of file being reached.
Note that the eof() function doesn't return true if the next call to get will fail because of the end of file being reached - it returns true if the previous call to get failed because of the end of file being reached.
It's not ASCII, it's an error returned by istream::get
ch = ifs2.get();
It's probably EOF, i.e. you've run out of input.
The fact that checking for -1 works is an accident, and has nothing to
do with ASCII values (which only use 0 to 127). Your code will fail
if either plain char is unsigned (compile with /J with VC++, I think),
or EOF isn't -1 (rare, but all that's guaranteed is that it is
negative). You're code will also fail if the input happens to be
Latin-1, and it contains a 'ÿ'.
The basic problem in your code is that you're not checking for end of
file correctly. Putting the test at the top of the loop doesn't work;
you need to test for failure (not eof()) after input, before using
the value read. There are several ways of doing this; in your case, the
simplest is probably to use:
if ( !ifs2.get(ch) ) {
// Input failed...
}
Alternatively, you can make ch an int, and do:
ch = ifs2.get();
if ( ch == EOF ) {
// Input failed...
}
This has the advantage that the following call to tolower is no longer
undefined behavior (tolower takes an int, which must be in the range
[0...UCHAR_MAX] or EOF—if plain char is signed, you aren't
guaranteeing this). On the other hand, it doesn't allow chaining, i.e.
you can't write the equivalent of:
while ( ifs2.get( sentenceCheck.first )
&& ifs2.get( sentenceCheck.second ) ) {
// ...
}
(which could be useful in some cases).
FWIW: the technique you're using is something called a sliding window
into a stream, and it's worth pushing it off into a separate class to
handle the logic of keeping the window filled and up to date.
Alternatively, a simple state machine could be used for your problem.
And I'd definitely avoid using magic constants: if you want to check for
a carriage return, compare with '\r'. Similarly, newline is '\n',
and in the outer if, it looks like you want to check for whitespace
(isspace( static_cast<unsigned char>( sentenceCheck.second ) )),
rather than comparing for the values.
I might also add that your code fails to correctly handle sentences that
end with a quote, like This is the "text in your input."; it also
fails for abbreviations like Mr. Jones is here.. But those problems
may be beyond the scope of your assignment. (The abbreviations one is
probably not fully solvable: sometimes "etc." is the end of a
sentence, and sometimes it's not.)

End of File(EOF) of Standard input stream (stdin)

Does stdin have any EOF? For example, if I start reading from stdin using fread or read, then will the following loop end?
while ((c = read(0, buffer, BUFSIZ)) > 0) {
.
.
.
}
If the answer to this question is no, then is there any way to add EOF to stdin?
Speaking about EOF in stdin: when you redirect input from file, e.g.:
program <input.txt
the file already has an EOF, so this is not a problem. In console you can simulate EOF flag. In UNIX systems it is Ctrl+D, in Windows Ctrl+Z. When you type this in the console, program will behave like it has just reached end of input file.
Edit
According to a question asked by OP:
So does it means that stdin don't have EOF and we have to insert them manually using Ctrl+Z or Ctrl+D?
Actually -- yes. One may consider stdin (not redirected, but taken from the console) as infinite file -- no one can tell where does it end. The end of input file, where input ist stdin, must be told literally by Ctrl+D or Ctrl+Z.
I have never programmed C in windows so I can't tell you but in bash, the program will get an EOF when you type end of data (Ctrl+D)
while ((c = read(0, buffer, BUFSIZ)) > 0) {
You don't say the type of c but using that name implies that it's a char. Note that the EOF value for iosteams is an (int) -1. Storing that into an unsigned char will get you a value of 255 which will not match EOF.
The way to test for EOF is to check the return value of fread, and then use feof:
while( fread( ... ) ) { // loop so long as fread does not return zero
// do something
}
if ( feof( stdin ) ) {
// read failed because of EOF
}
else {
// some other error
}
Your solution is tagged C++, so here's some C++.
std::string lols;
while(!(std::cin >> lols).eof()) { // This loop will end when EOF is reached
// Process string
}
First getchar() is really getc(stdin) so getc(FILE) you can read more from that. getchar() gets you last unprocessed character from input stream or stdin pressing enter is '\n'. if the stdin is empty getchar forces a pause to get input.
Say in a program I call getchar() at first the stdin is empty so it pauses for input. If I enter ab'\n' the first getchar() will get 97 the ascii of 'a'. the next time i call getchar() i will get b , then again getchar() will have '\n'.
To prove this write this code.
int choice;
do
{
cout << "Enter input:" ;
choice = getchar();
cout << "Last getchar(): " << choice << ":" << (char) choice ;
if( choice == '0' || choice == EOF)
{
cout << "Exited loop" << endl; // EOF is ctrl+z in windows
break;
}
}while(true);
I do believe stdin is a global so until getchar() or similar function gets called it to clear the stream the characters remain there which can cause bugs later if you use getchar() elsewhere. As people have mentioned you can use gets(char[]) which puts all characters until newline into the character array. The problem with this is you need a char[] larger than input or you will get errors. The nice thing is gets(char[]) does clear stdin so you can make a dumby buffer to clear stdin or process it.
I hope this is informative.