Some background information, for a homework assignment I had to write a polish notation calculator using binary trees, for this to work I had to parse command line input so that it would properly build the binary tree and then go over it to give a valid answer to the mathematical expression that was entered.
For the parsing I used a std::stringstream so that I would easily be able to convert the std::string I was handed into a valid float (or integer, double). The issue I ran across was the following code, which has the error showcased and how I solved the issue. I was hoping that somebody where would be able to tell me if I was doing something wrong and .clear() is not correct, or if this is a bug in the standard library in the way it handles this particular input (only happens for + and -).
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string mystring("+");
int num;
char op;
std::stringstream iss(mystring);
iss >> num;
// Seems it is not a number
if (iss.fail()) {
// This part does not work as you would expect it to
// We clear the error state of the stringstream
iss.clear();
std::cout << "iss fail bit: " << iss.fail() << std::endl;
iss.get(op);
std::cout << "op is: " << op << " iss is: " << iss.str() << std::endl;
std::cout << "iss fail bit: " << iss.fail() << std::endl;
// This however works as you would expect it to
std::stringstream oss(iss.str());
std::cout << "oss fail bit: " << oss.fail() << std::endl;
oss.get(op);
std::cout << "op is: " << op << " oss is: " << oss.str() << std::endl;
std::cout << "oss fail bit: " << oss.fail() << std::endl;
} else {
// We got a number
}
}
Sample output from the program:
iss fail bit: 0
op is: iss is: +
iss fail bit: 1
oss fail bit: 0
op is: + oss is: +
oss fail bit: 0
Maybe you guys will see something I missed, or if this is indeed a bug higher up beyond my program, in which case pointers as to where to report this would be greatly appreciated.
When you say:
iss.clear();
std::cout << "iss fail bit: " << iss.fail() << std::endl;
iss.get(op);
you are trying to read something that has already been read. You need to reset the streams read pointer:
iss.clear();
iss.seekg(0); // start again
std::cout << "iss fail bit: " << iss.fail() << std::endl;
iss.get(op);
Related
I have a very simple program
#include <iostream>
#include <fstream>
void CHECK(std::iostream& s)
{
std::cout << "good(): " << s.good()
<< " fail(): " << s.fail()
<< " bad(): " << s.bad()
<< " eof(): " << s.eof() << std::endl;
}
int main(int argc, const char * argv[])
{
std::fstream ofs("test.txt", std::ios::out | std::ios::trunc);
std::cout << "opened" << std::endl;
CHECK(ofs);
ofs << "Hello, World!\n";
CHECK(ofs);
ofs.close();
std::cout << "closed" << std::endl;
CHECK(ofs);
ofs << "Hello, World!\n";
std::cout << "after operation" << std::endl;
CHECK(ofs);
return 0;
}
With libc++ I get the following last line:
good(): 1 fail(): 0 bad(): 0 eof(): 0
Expected (or with libstdc++):
good(): 0 fail(): 1 bad(): 1 eof(): 0
I have tested on OSX with Xcode 9.4.1 (or on Linux), but always the same. Can anybody explain me the situation here? Also the file content was not updated, because already closed. Why is the stream still good after closing and further operation?
What I suspect is happening is that the operations are stuffing the data into the rdbuf associated with the stream. That succeeds, as long as there is room in the buffer. Eventually, the buffer gets full, and the stream attempts to write to the file (which is closed) and that fails.
You can test that by making the last bit a loop:
ofs.close();
std::cout << "closed" << std::endl;
CHECK(ofs);
for (int i = 0; i < 500; ++i)
{
ofs << "Hello, World!\n";
std::cout << i << " ";
CHECK(ofs);
}
std::cout << "after operation" << std::endl;
On my machine, it fails after about 300 - and forever after that.
Is this correct behavior? (or even standards-compliant?)
I don't know.
[ Later: If I change libc++ do set the buffer size to 0 upon close, then the first write fails - so that suggests that my analysis is correct. However, I still haven't found anything in the standard about what this 'should' do. ]
I'm still relatively new-ish to CPP but I can't find any source that has my issue. My IDE is MSVC 2017 Preview and my desired outcome is to add two hex addresses together, then read the address' value. I'm not sure why but it's not playing nicely with adding hex numbers. I'll give you my current example:
int number;
ReadProcessMemory(pHandle, (void*)(0x37c90000 + 0xE29FE8), &number, sizeof(number), 0);
std::cout << number << " for " << std::hex << (0x37c90000 + 0xE29FE8) << std::endl;
ReadProcessMemory(pHandle, (void*)(0x38ab9fe8), &number, sizeof(number), 0);
std::cout << number << " for " << std::hex << (0x38ab9fe8) << std::endl;
std::cout << "a = " << (0x37c90000 + 0xE29FE8) << std::endl;
std::cout << "b = " << (0x38ab9fe8) << std::endl;
My predicted outcome of this code would be that both ReadProcessMemory should get the same exact same value, but instead only the second ReadProcessMemory (with the already added hex value) returns properly.
Furthermore, cout-ing A and B report the exact same address. If that's the case, why is ReadProcessMemory throwing a tantrum and reporting a negative number on the first ReadProcessMemory?
Here's my outcome with the code above:
-331287296 for 38ab9fe8
ec40f500 for 38ab9fe8
a = 38ab9fe8
b = 38ab9fe8
Apologies but I truly can't figure out why they're different in any way.
No that seems about right. 0xec40f500 is the unsigned hexadecimal representation of the decimal signed value -331287296. Please learn about two's complement representation of negative numbers.
The problem is, I believe, the std::hex manipulator, which is sticky. If you in the second case use std::dec both numbers will be displayed as decimal:
// Second output
std::cout << std::dec << number << " for " << std::hex << (0x38ab9fe8) << std::endl;
// ^^^^^^^^
// Display *all* following numbers as decimal
Or use std::hex in the first output:
// First output
std::cout << std::hex << number << " for " << (0x37c90000 + 0xE29FE8) << std::endl;
// ^^^^^^^^
// Display *all* following numbers as hexadecimal
Of course, if you intend for number to be unsigned, you need to explicitly say so when defining the variable. Perhaps it would be easier for you to see the connection between 0xec40f500 and the unsigned decimal value 3963680000?
I begin with c++ and i'm just doing a mini Game, and i would like to open my file.txt which contains:
Hello
Test
Random
Mysterious
Nice
Good
Uber
Facebook
etc...
and inside my code i put myself a word inside my variable :
RandName
So how i could open a file.txt, take a random word inside my file and insert into my game. I think i have to use ofstream but i don't really know how to use it.
Code:
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
using namespace std;
string Shake(string str){
string melange;
int i(0);
while (str.size() != 0){
i = rand() % str.size();
melange += str[i];
str.erase(i, 1);
}
return melange;
}
int main(){
std::cout << "Welcome to secret word : ";
string RandName("Random");
string Reponse("");
string RandNameShake("");
int cpt(0);
int lose(10);
int Replay(0);
srand(time(0));
std::cin >> Reponse;
while (RandName != Reponse && lose != 0) {
RandNameShake = Shake(RandName);
std::cout << "Wrong word ! " << '\n';
std::cout << endl << "The secret word is : " << RandNameShake << endl;
std::cout << "HIT : " << lose << '\n';
std::cout << endl << "Try again : ";
std::cin >> Reponse;
cpt++;
lose--;
}
if (lose == 0 ) {
std::cout << endl << "Sorry you don't find the word ... " << '\n';
std::cout << endl << "The word was : " << RandName <<'\n';
std::cout << endl << "An other game ? 1/Yes 2/No" << '\n';
std::cin >> Replay;
}
else
std::cout << endl << "Good Game yu find the word in " << cpt << " hits" << endl;
std::cout << endl << "An other game ? 1/Yes 2/No" << '\n';
std::cin >> Replay;
if (Replay == 1) {
main();
}
else if (Replay == 2) {
std::cout << "All right see you soon :) !" << '\n';
return 0;
}
else
std::cout << "Don't understand i close the program" << '\n';
return 0;
return 0;
}
This sounds awfully lot like homework assignment, so I will leave the code for you and limit the answer to general directions.
I think i have to use ofstream
Try again. ofstream as the name suggests is for output, and what you need in this case is input.
Onto getting a random word - an inefficient native solution would involve counting the number of lines/words, picking one at random and skipping ahead till you reach it. That however involves a lot of unnecessary operations that can be avoided.
Another solution, inefficient in a different way would involve reading all of the words into a container and picking at random an index from the word container. That solution might however turn out to be more efficient if you are gonna do a lot of random word picking.
For a single word it would be better to pick a position in the file at random and seek ahead until you find the next new line, and read a line from that position. If you reach the end without finding one, that means the position happened to be in the last line, so you need to go back until you find the first new line, that will represent the last line in the file and read that.
In either case, you will end up with a word picked at random with minimum amount of overhead.
I have a c++ program which writes changing numbers to screen, something in the vein of the following snippet:
stringstream ss, ssd; ss << 0; int decs=0; ssd << decs;
cout << "Number ";
for(int i=1;i<=1000;i++) {
cout << ss.str() << " Decades: " << decs; cout.flush();
int l=ss.str().length()+12+ssd.str().length();
for(int j=0;j<l;j++) cout << "\b";
this_thread::sleep_for (chrono::milliseconds(100));
ss.str(""); ss << i;
if(i%10==0) {
decs++; ssd.str(""); ssd << decs;
}
}
This works fine, but sometimes (not always) I would like to send the output to a file instead of the terminal, using e.g. ./prog > out.txt. Here the backspace character \b doesn't delete character but outputs some symbol (googling tells me this is not surprising).
One option would be to e.g. only output the data at the end of the calculation when printing to a file. But this would entail different code for terminal/file, switching with an input parameter for example. Is there a way I can do this without having separate code for terminal/file output?
I am using cygwin on Windows 7.
Try to write whole string every time and to write just '\r' without '\n'
stringstream ss, ssd; ss << 0; int decs=0; ssd << decs;
for(int i=1;i<=1000;i++) {
cout << "Number " << ss.str() << " Decades: " << decs; cout.flush();
//int l=ss.str().length()+12+ssd.str().length();
//for(int j=0;j<l;j++) cout << "\b";
cout << '\r';
this_thread::sleep_for (chrono::milliseconds(100));
ss.str(""); ss << i;
if(i%10==0) {
decs++; ssd.str(""); ssd << decs;
}
}
In this case you'll have the full output in the file.
A possible workaround may be to use std::cerr for intermediate result (and so for '\b'),
and std::cout for final result.
I would like to know if and why seekg(0) is not supposed to clear the eofbit of a stream.
I am in a point where I have already read all the stream, thus EOF has been reached (but no failbit is set yet) and want to go back with seekg() to a valid position and read some chars again. In this case seekg(0) seems "to work" with the eofbit set, but as soon as I try to read from the stream, the failbit is set. Is this logic, correct or is my implementation bad? Am I supposed to recognize this case and clear the eofbit manually (if the failbit is not set)?
EDIT:
The following program provided by a reader gives different results in my implementation ( mingw32-c++.exe (TDM-2 mingw32) 4.4.1 ):
#include <sstream>
#include <iostream>
#include <string>
int main() {
std::istringstream foo("AAA");
std::string a;
foo >> a;
std::cout << foo.eof() << " " << foo.fail() << std::endl; // 1 0
foo.seekg(0);
std::cout << foo.eof() << " " << foo.fail() << std::endl; // 0 0
foo >> a;
std::cout << foo.eof() << " " << foo.fail() << std::endl; // 1 0
foo >> a;
std::cout << foo.eof() << " " << foo.fail() << std::endl; // 1 1
}
The comments above are from the user who tried that program in his implementation. I obtain these results:
1 0
1 0
1 1
1 1
According to the new standard clear() is supposed to reset the eofbit (§ 27.7.2.3):
basic_istream<charT,traits>& seekg(pos_type pos);
Effects: Behaves as an unformatted input function ..., except that the function first clears eofbit ...
But in the old standard (§ 27.6.1.3) there is no mention of clearing the eofbit!
And a simple test:
#include <sstream>
#include <iostream>
#include <string>
int main() {
std::istringstream foo("AAA");
std::string a;
foo >> a;
std::cout << foo.eof() << " " << foo.fail() << std::endl; // 1 0
foo.seekg(0);
std::cout << foo.eof() << " " << foo.fail() << std::endl; // 0 0
foo >> a;
std::cout << foo.eof() << " " << foo.fail() << std::endl; // 1 0
foo >> a;
std::cout << foo.eof() << " " << foo.fail() << std::endl; // 1 1
}
Why not just manually clear() the stream then go back once the eofbit has been set? EOF has been reached, why should seekg clear it automatically? Doing that would seem to cause more problems.