EOF suddenly reaching with getline() in ifstream - c++

I have file "in.txt" which consist of 2 strings:
abcde
12345
I have my code:
#include <iostream>
#include <fstream>
int main() {
std::ifstream fileIn("in.txt", std::ios::in);
char* chPtr = new(char[10]);
char ch;
printf("fileIn.get()==EOF?: %d \n", (fileIn.get() == EOF)); // =0
std::cout << "fileIn.eof() = " << fileIn.eof() << "\n"; // =0
fileIn.getline(chPtr, 3);
std::cout << "chPtr-" << chPtr << "\n"; //output:"bc" (see 1.)
fileIn.get(ch);
std::cout << "ch-" << ch << "\n"; //(see 2.)
printf("fileIn.get()==EOF?: %d \n", (fileIn.get() == EOF)); // =1 (see 3.)
std::cout << "fileIn.eof() = " << fileIn.eof() << "\n"; // =0 (see 4.)
fileIn.close();
delete[] chPtr;
}
Remarks to code:
(1.) 1st symbol 'a' was eaten by get() slightly above; Thus 2 next symbols read here, and 3rd symbol, what i wanted to read, getline() automatically assigns with value '\0' (if I understand correctly).
(2.)And here are is the question - here outputs symbol (with code [-52]). Unfortunately I haven't enough reputation to post images =( (This symbol is like 2 vertical white lines, right line of this pair is with gap at the middle).
(for information: I got this symbol each time, I'm trying to read to char variable an uninitialized element of char-array.)
But why I get it there?? Because there are still unreaded symbols in 1st string & whole 2nd string!
(3.) It turns out that, the cursor suddenly moved to the end of file. But WHY?? I can't understand
(4.) We still have zero here, because (if I understand correctly) there was not attempt of reading data behind the eof-line. The cursor just moved to place behind the last symbol of file, but not out of the file-end-border).

If istream::getline manages to read count-1 characters (count is 3 in your example) before EOF is reached, it will set failbit. See the reference.
This means all further extractions will fail unless you clear the flag, not that "cursor moved to the end". ch never gets initialized.

Related

How can I remove a newline from inside a string in C++?

I am trying to take text input from the user and compare it to a list of values in a text file. The values are this:
That line at the end is the cursor, not a straight line, but it doesn't matter. Anyway, I sort by word and produce the values, then check the values. Semicolon is a separator between words. All the data is basic to get the code working first. The important thing is that all the pieces of data have newlines after them. No matter what I try, I can't get rid of the newlines completely. Looking at the ASCII values shows why, My efforts remove only the new line, but not the carriage return. This is fine most of the time, but when comparing values they won't be the same because the one with the carriage return is treated as longer. Here is the important parts of the code:
int pos = 0;
while (pos != std::string::npos)
{
std::string look = lookContents.substr(pos+1, lookContents.find("\n", pos + 1) - pos);
//look.erase(std::remove(look.begin(), look.end(), '\n'), look.end());
//##
for (int i = 0; i < look.length(); i++)
{
std::cout << (int)(look[i]) << " ";
}
std::cout << std::endl;
std::cout << look << ", " << words[1] << std::endl;
std::cout << look.compare(0,3,words[1]) << std::endl;
std::cout << pos << std::endl;
//##
//std::cout << look << std::endl;
if (look == words[1])
{
std::cout << pos << std::endl;
break;
}
pos = lookContents.find("\n", pos + 1);
}
Everything between the //## are just error checking things. Heres what is outputs when I type look b:2
As you can see, the values have the ASCII 10 and 13 at the end, which is what is used to create newlines. 13 is carriage return and 10 is newline. The last one has its 10 remove earlier in the code so the code doesn't do an extra loop on an empty substring. My efforts to remove the newline, including the commented out erase function, either only remove the 13, or remove both the 10 and 13 but corrupt later data like this:
Also, you can see that using cout to print look and words1 at the same time causes look to just not exist for some reason. Printing it by itself works fine though. I realise I could fix this by just using that compare function in the code to check all but the last characters, but this feels like a temporary fix. Any solutions?
My efforts remove only the new line, but not the carriage return
The newline and carriage control are considered control characters.
To remove all the control characters from the string, you can use std::remove_if along with std::iscntrl:
#include <cctype>
#include <algorithm>
//...
lookContents.erase(std::remove_if(lookContents.begin(), lookContents.end(),
[&](char ch)
{ return std::iscntrl(static_cast<unsigned char>(ch));}),
lookContents.end());
Once you have all the control characters removed, then you can process the string without having to check for them.

Storing data in char array causing corruption around variable

I am working on a C++ project and I am having an issue.
Below is my code
tempfingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_TYPE_RSA);
char temp[48];
memset(temp, 0, sizeof(temp));
for (i = 0; i < 16; i++)
{
//fingerprintstream << (unsigned char)tempfingerprint[i] << ":";
if (temp[0] == 0)
{
sprintf(temp, "%02X:", (unsigned char)tempfingerprint[i]);
}
else
{
//sprintf(temp, "%s:%02X", temp, (unsigned char)tempfingerprint[i]);
char characters[3];
memset(characters, 0, sizeof(characters));
//If less than 16, then add the colon (:) to the end otherwise don't bother as we're at the end of the fingerprint
sprintf(characters, "%02X:", (unsigned char)tempfingerprint[i]);
strcat(temp, characters);
}
}
//Remove the end colon as its not needed. 48 Will already be null terminated, so the previous will contain the last colon
temp[47] = 0;
return string(temp);
When I run my app, I get the following error from visual studio
Run-Time-Check Failure #2 - Stack around the variable 'temp' was corrupted.
I've ran the same code on Linux through Valgrind and no errors were shown so I'm not sure what the problem is with Windows.
Here's an approach using on what Paul McKenzie's talking about (though he might implement it differently) based on it looks like you were trying to do with the stream
#include <iostream>
#include <sstream>
#include <iomanip> // output format modifiers
using namespace std;
int main()
{
stringstream fingerprintstream;
// set up the stream to print uppercase hex with 0 padding if required
fingerprintstream << hex << uppercase << setfill('0');
// print out the first value without a ':'
fingerprintstream << setw(2) << 0;
for (int i = 1; i < 16; i++) // starting at 1 because first has already been handled.
{
// print out the rest prepending the ':'
fingerprintstream << ":" << setw(2) << i;
}
// print results
std::cout << fingerprintstream.str();
return 0;
}
Output:
00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F
Just realized what I think OP ran up against with the garbage output. When you output a number, << will use the appropriate conversion to get text, but if you output a character << prints the character. So fingerprintstream << (unsigned char)tempfingerprint[i]; takes the binary value at tempfingerprint[i] and, thanks to the cast, tries to render it as a character. Rather than "97", you will get (assuming ASCII) "a". A large amount of what you try to print will give nonsense characters.
Example: If I change
fingerprintstream << ":" << setw(2) << i;
to
fingerprintstream << ":" << setw(2) << (unsigned char)i;
the output becomes
0?:0?:0?:0?:0?:0?:0?:0?:0?:0?:0 :0
:0?:0?:0
:0?:0?
Note the tab and the line feeds.
I need to know the definition of tempfingerprint to be sure, but you can probably solve the garbage output problem by removing the cast.
Based on new information, tempfingerprint is const char *, so tempfingerprint[i] is a char and will be printed as a character.
We want a number, so we have to force the sucker to be an integer.
static_cast<unsigned int>(tempfingerprint[i]&0xFF)
the &0xFF masks out everything but the last byte, eliminating sign extension of negative numbers into huge positive numbers when displayed unsigned.
There are, as far as I see, two issues in the code which lead to exceeding array boundaries:
First, with char temp[48] you reserve exactly 48 characters for storing results; However, when calling strcat(temp, characters) with the 16th value, and characters comprises at least the characters including the colon, then temp will comprise 16*3 digits/colons + one terminating '\0'-character, i.e. 49 characters (not 48). Note that strcat automatically appends a string terminating char.
Second, you define char characters[3] such that you reserve place for two digits and the colon, but not for the terminating '\0'-character. Hence, an sprintf(characters, "%02X:",...) will exceed characterss array bounds, as sprintf also appends the string terminator.
So, if you do not want to rewrite your code in general, changing your definitions to char temp[49] and char characters[4] will solve the problem.

How to fix C++ char converting?

I have a these functions which written in C++ :
#include ...
char read_somthing()
{
int n = 0, spot = 0;
char buf = '\0';
char response[13];
memset(response, '\0', sizeof response);
do {
n = read( fd, &buf, 1 );
sprintf( &response[spot], "%c", buf );
spot += n;
} while( buf != '\r' && n > 0);
cout << "Response: " << response << endl;
return buf;
}
void main()
{
cout << read_somthing();
char response = read_somthing();
cout << response;
}
The problem is, First cout works and prints the true value, but the second one is returning empty line , i think it has something to do with second line in main function, How can i fix it ?
PS : I comment out the cout << read_somthing(); but nothing appear in output.
Your read_somthing is reading a character in input and returning a copy of that. The second time you call read_somthing, the input stream has been moved ahead of 1 character, and if the input is of 1 character, then reading another one will yield no results.
This is similar to the initialisation and assignment.
in c it is allowed but in c++ it will give different results
The first one relies on initialization while the second one - on assignment. In C++ these operations are over loadable and therefore can potentially lead to different results.
You are returning buf variable, which is single character. When do {} while() loop exits there's chance buf contains \r (or junk when read failed), which will not be shown on console output.
You probably want to return data gathered in response. To mitigate problems with data allocation etc. just use std::string - change return type of read_something and last line to return response;

Program throwing exception

I am writing a program that allows the user to enter a sentence which then gets stored in a string and then the program will remove any full stops in the sentence and then create a list of each individual word in the string before outputting that list to the console.
the program is working perfectly as long as there is only 1 full stop in the sentence but if there are any more than that it throws this exception:
Unhandled exception at at 0x7696B727 in Project6.exe: Microsoft C++ exception: std::out_of_range at memory location 0x0022F8B8.
and then if I continue to run it it throws:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
any suggestions? (and before anyone asks, i know you usually only have 1 full stop in a sentence but i need to do it with more than 1 as part of testing.
here is the code:
#include <iostream>
#include <string>
using namespace std
string sSentence; // sets up a string variable called sSentence
int i = 0;
void RemoveFullStop()
{
while(sSentence.find (".") != string::npos) // the program runs this loop until it cannot find any more full stops in the string
{
i = sSentence.find("." , i); // find the next full stop in the string and get the character count of the space and place it in the variable i
sSentence.replace(i,1,""); // remove the full stop
}
}
void ListWords()
{
while(sSentence.find (" ") != string::npos) // the program runs this loop until it cannot find any more spaces in the string
{
i = sSentence.find(" " , i); // find the next space in the string and get the character count of the space and place it in the variable i
// cout << i << endl; // output the contents of iWordSpace to the console (used for debugging - no longer used)
sSentence.replace(i,1,"\n");
// cout << sSentence << endl; // output the contents of iWordSpace to the console (used for debugging - no longer used)
}
}
int main()
{
getline(cin, sSentence); // get user input and store it in sSentence (using the getline function so the .find operation works correctly)
RemoveFullStop(); // calls the RemoveFullStop void function that removes all full stops from the string
ListWords(); // calls the ListWords void function that splits the string into a list of words
cout << endl; // formatting line
cout << "The words that were in the sentence were:" << endl;
cout << endl; // formatting line
cout << sSentence << endl;
cout << endl; // formatting line
system("pause");
return 0;
}
The problem is that you keep re-using i, in both RemoveFullStop and ListWords.
i only ever increases, and so eventually it can get past the end of the string.
You really shouldn't need a global i variable at all, to do this task.
The reason this happens is that when sSentence.find(" " , i) in ListWords runs, i's value is not 0 because it was already defined in RemoveFullStop(). To fix this, first remove int i = 0;, then add it to RemoveFullStop() and ListWords()
Also, while this is just a style thing and won't effect your codes ability to run, I wouldn't call this variable i as i,j,k usually imply counters. Call this variable something more appropriately descriptive.
Here is the relevant code as it should be.
using namespace std
string sSentence;
void RemoveFullStop()
{
int charPlace = 0;
while(sSentence.find (".") != string::npos)
{
charPlace = sSentence.find("." , charPlace);
sSentence.replace(charPlace,1,"");
}
}
void ListWords()
{
int charPlace = 0;
while(sSentence.find (" ") != string::npos)
{
charPlace = sSentence.find(" " , charPlace);
sSentence.replace(charPlace,1,"\n");
}
}

unexpected behavior when read a character from istringstream

I have a question on the stream behavior, see the following example. What I was expecting is the ss_char and ss_int will be eof state, but just the ss_int will be eof state.
My question is, why isn't ss_char eof state?
Can't I use the operator>>, only the istringstream::get() function, but then why read the value successfully?
Output:
char value: a
int value: 42
ss_char eof: false // why false?
ss_int eof: true
Sorry for my poor English. I’m working on improving my English.
#include <iostream>
#include <sstream>
int main(int /*argc*/, char const * /*argv*/[])
{
char c;
int num;
std::istringstream ss_int("42");
std::istringstream ss_char("a");
if (ss_char >> c)
{
std::cout << "char value: " << c << std::endl;
}
else
{
std::cout << "cannot read char" << std::endl;
}
if (ss_int >> num)
{
std::cout << "int value: " << num << std::endl;
}
else
{
std::cout << "cannot read int" << std::endl;
}
std::cout << std::endl;
std::cout << "ss_char eof: " << std::boolalpha << ss_char.eof() << std::endl; // why false
std::cout << "ss_int eof: " << std::boolalpha << ss_int.eof() << std::endl;
return 0;
}
CppReference says: "This function only reports the stream state as set by the most recent I/O operation, it does not examine the associated data source. For example, if the most recent I/O was a get(), which returned the last byte of a file, eof() returns false. The next get() fails to read anything and sets the eofbit. Only then eof() returns true."
oefbit will turn true when a read operation attempts to read beyond end of file, but not when it reads exactly to the end of file without trying to go further. When you read the char, it knows it should read a single byte, so this read operation is ok, the read position advance 1 byte, goes to the end, but let say the the stream still haven't noticed that it is indeed the end, it will if you try to read something else. When you read an integer, it tries to read beyond 42 because the length of the integer is not clear, it could have been 42901, so it has to read until it sees an space, and end of line, or eventually the end of the file/stream if there's nothing else to read.
And the result of the operator >> is the stream itself. When it is converted to void* (or bool, depends on c++11 or previous) it works as !fail(), so it tells you if the read or write operation was ok, regardless of whether it reached the end of file (next read operation will fail if it is now at the end).
The EOF condition doesn't actually occur until you try to read past the end of the stream.
In the char case you read exactly one character, the only one available. You don't try to read past the end because there is no need to.
Extracting an int on the other hand attempts to consume as many digits as possible. It reads the 4 and the 2, and then it tries to read again to see if there is another digit to consume, it does attempt to read past the end in this case. It notices that the input came to an end and so finishes the conversion of 42.
when extracting chars, it will pull a single character at a time and skip white spaces on consecutive calls.
when extracting int, the parser attempts to pull as many characters out to form the number. this causes the integer extraction to hit the eof in your test case.