Reason for this output of stringstream? - c++

I am trying to learn stringstream and I have the following code:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream os;
os.str("Purohit");
os << "Vipul" << endl;
cout << os.str() << endl;
}
When I compile it and run it, I get the following output:
Vipul
t
Why? Shouldn't this output Purohit Vipul?

This is because str method replaces the content of stringstresm, without placing the buffer pointer for the subsequent writes at the end of the stream. That is why when you output "Vipul\n" it writes over the "Purohit" string that you placed into the stream earlier:
Initial state
0 1 2 3 4 5 6
P u r o h i t
^
After the << write:
0 1 2 3 4 5 6
V i p u l \n t
You could call seekg to set the position before appending the "Vipul" string, but an easier fix would be to use << for both writes.

Related

Why splitting a line separated by spaces with stream in C++ runs infinitely?

Before, when I was writing C++, I often used getch() for validation. However, now I am turning into competitive programming, I cannot use getch(); I had to use cin or getline. Thus, today, I replicated an instance of splitting a string using stringstream:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main() {
string line;
getline(cin, line);
cout << line << endl;
stringstream reader;
reader.clear();
reader.str(line);
vector<long long int> list;
while (true) {
reader.clear();
if (reader.str().size() == 0) {
break;
}
long long int value;
reader >> value;
list.push_back(value);
}
}
Then, I ran the program, typed 1 2 3 4 5 6 7 8 9 and pressed enter. The program successfully displayed line, 1 2 3 4 5 6 7 8 9, but the program just didn't terminate. It never approached the end of the main() function. I tried to print reader.str(), but it just print 1 2 3 4 5 6 7 8 9 continually. I was confused. Why reader >> value didn't run and did not read any value? Why was the program running an infinite loop? How can I fix the issue? I appreciate any solution.
The reading operator >> does not change the underlying string. It uses an inner position of a next char to read.
int main() {
int n;
std::istringstream in; // could also use in("1 2")
in.str("1 2");
in >> n;
std::cout << "after reading the first int from \"1 2\", the int is "
<< n << ", str() = \"" << in.str() << "\"\n";
}
Outputs
after reading the first int from "1 2", the int is 1, str() = "1 2"
The loop may be terminated by replacing reader >> value; with
if (!(reader >> value))
break;
... but the program just didn't terminate.
This means that ...
while (true)
true is never false, or ...
reader.str().size() == 0
is never true.
true, in fact, is never false, and you never change the size of the reader's string object. Why would you expect this loop to break?
Please edit your question to make it more clear what you are trying to accomplish.

std::istream_iterator stops advancing

Why does the following program output
1 2 3 4 4 4
and not
1 2 3 4 5 6
for each of the values provided?
#include <iostream>
#include <iterator>
#include <vector>
#include <string>
#include <sstream>
int main()
{
std::vector<int> numbers;
std::stringstream ss;
ss << " 1 2";
std::istream_iterator<int> start{ss},end;
ss << " 3 4";
numbers.push_back(*start++);
numbers.push_back(*start++);
numbers.push_back(*start++);
ss << " 5 6";
numbers.push_back(*start++);
numbers.push_back(*start++);
numbers.push_back(*start++);
std::cout << "numbers read in:\n";
for (auto number : numbers) {
std::cout << number << " ";
}
std::cout << "\n";
}
Its not iterator doing as you might have thought. It's ss that is invalidated after iterator progressing. Initialiy stringstream constains 1 2 3 4 and is in valid state. But is invalidated by the third iterator dereference, so next operation ss << " 5 6" fails. To fix this, clear flags of stringstream variable:
//...
ss.clear();
ss << " 5 6";
//...
Output:
numbers read in:
1 2 3 4 5 6
Use stream iterators with some caution. When a valid istream_iterator reaches the end of the underlying stream, it becomes equal to the end-of-stream iterator.
And then dereferencing or incrementing it further invokes undefined behavior, in your case you just got a copy of the most recently read object.
Also keep in mind that the first object from the stream is read when the iterator is constructed.

C++ Splitting the input problem

I am being given input in the form of:
(8,7,15)
(0,0,1) (0,3,2) (0,6,3)
(1,0,4) (1,1,5)
(2,1,6) (2,2,7) (2,5,8)
(3,0,9) (3,3,10) (3,4,11) (3,5,12)
(4,1,13) (4,4,14)
(7,6,15)
where I have to remember the amount of triples there are. I wrote a quick testing program to try read the input from cin and then split string up to get the numbers out of the input. The program doesn't seem to read all the lines, it stops after (1,1,5) and prints out a random 7 afterwards
I created this quick testing function for one of the functions I am trying to create for my assignment:
int main ()
{
string line;
char * parse;
while (getline(cin, line)) {
char * writable = new char[line.size() + 1];
copy (line.begin(), line.end(), writable);
parse = strtok (writable," (,)");
while (parse != NULL)
{
cout << parse << endl;
parse = strtok (NULL," (,)");
cout << parse << endl;
parse = strtok (NULL," (,)");
cout << parse << endl;
parse = strtok (NULL," (,)");
}
}
return 0;
}
Can someone help me fix my code or give me a working sample?
You can use this simple function:
istream& read3(int& a, int& b, int& c, istream& stream = cin) {
stream.ignore(INT_MAX, '(');
stream >> a;
stream.ignore(INT_MAX, ',');
stream >> b;
stream.ignore(INT_MAX, ',');
stream >> c;
stream.ignore(INT_MAX, ')');
return stream;
}
It expects the stream to start at a (, so it skips any characters and stops after the first ( it sees. It reads in an int into a which is passed by reference (so the outside a is affected by this) and then reads up to and skips the first comma it sees. Wash, rinse, repeat. Then after reading the third int in, it skips the closing ), so it is ready to do it again.
It also returns an istream& which has operator bool overloaded to return false when the stream is at its end, which is what breaks the while loop in the example.
You use it like this:
// don't forget the appropriate headers...
#include <iostream>
#include <sstream>
#include <string>
int a, b, c;
while (read3(a, b, c)) {
cout << a << ' ' << b << ' ' << c << endl;
}
That prints:
8 7 15
0 0 1
0 3 2
0 6 3
1 0 4
1 1 5
2 1 6
2 2 7
2 5 8
3 0 9
3 3 10
3 4 11
3 5 12
4 1 13
4 4 14
7 6 15
When you give it your input.
Because this is an assignment, I leave it to you to add error handling, etc.
I've written a blog 9 days back exactly to parse such inputs:
Playing around with Boost.Spirit - Parsing integer triplets
And you can see the output here for your input : http://ideone.com/qr4DA

This is not the output i asked for

#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
ofstream w("d:/tester.txt");
int f = 1;
int s = 2;
int t = 3;
string x = "hello";
w << f << endl << s << endl << t << endl << x ;
w.close();
ifstream r("d:/tester.txt");
r >> x;
cout << x << endl ;
s = s + 10 ;
r.close();
/* ofstream wa("d:/tester.txt");
wa << s;
wa.close();*/
}
I always get the output equal to 1 .
Why is this so ? When i asked for the string hello 1 gets displayed .
In fact, it is the output you ask for: you are reading the first string token from the file. And that happens to be the number “1” you wrote on the first line into the file.
The streaming operators don’t magically parse your file for the most suitable token; they are simply reading the next available token. And even if they did, “1” would be a perfectly valid choice for a string.
You store consecutively 1 2 3 in your file, then you fetch the first value from the file. Are you surprised that the value is 1? If you want the other values, you must call the stream in functions more than once.
The first line of tester.txt is f which is 1.
x is a string, so when you read from tester.txt using r>>x you get the first line, which is "1"
When you open a stream, you open it in a top-bottom fashion, this meaning that the stream is positioned in the beginning of the first line.
You wrote:
w << f << endl << s << endl << t << endl << x ;
So line the lines are:
f
s
t
x
And f = 1, so you are getting what you should be getting.
Isn't that what you would expect, or am I missing something?
You put the values "1" "2" "3" "hello" in the stream, in that order.
Then, you stream from that into a string. String spec says that all characters will be copied until the first valid whitespace. It will see "1" as a char, and then stop at the newline. Hence, you will get a string, the string "1";

Problem with istream::tellg()?

I'm reading data.txt:
//////////////////////////////////////////////////
data.txt:
//////////////////////////////////////////////////
MissionImpossible3
3
TomCruise
MaggieQ
JeffChase
Here's code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ifstream fin("data.txt");
string FilmName, ActorName;
getline(fin,FilmName,'\n');
cout << FilmName << endl;
// cout << fin.tellg() << endl; //if I add this line to
// get current reading position of data.txt, the program just
// can't work as if tellg() triggered some error. So I removed
// all tellg(). What's the reason for this and what shall I do
// if I want to get current reading position?
int a;
fin >> a;
cout << a << endl;
// cout << fin.tellg() << endl;
getline(fin,ActorName,'\n');
// cout << fin.tellg() << endl;
for(int i=0;i<a;i++)
{
getline(fin,ActorName,'\n');
cout << ActorName << endl;
// cout << fin.tellg() << endl;
}
getchar();
}
Unexpected output is:
MissionImpossible3240-1-1
I'm using Dev-c++ and Windows XP. I'll appreciate it if you guys give it a try and paste your results and environment. Maybe there is some problem with my system or compiler.
Another version of input/output:
data.txt:
MissionImpossible3
3
TomCruise
MaggieQ
JeffChase
WarOfTheWorlds
2
TomCruise
DakotaFanning
SharkTale
3
JackBlack
RobertDeNiro
WillSmith
HideAndSeek
2
DakotaFanning
RobertDeNiro
TheAdventureOfPlutoNash
2
WillSmith
EddieMurphy
ShowTime
2
RobertDeNiro
EddieMurphy
output:
MissionImpossible3
49
0
-1
-1
It says it consumed 24 characters after the first line, then failed to get a number. However, MissionImpossible3 only has 18 characters.
I suspect you have a line encoding incompatiblity. Your file is saved with \n endings, while Windows iostreams expects \r\n. The 3 in the input gets thrown away as the system expects a \n. Then the next input is non-numeric and it enters an error state.
Try copy-pasting the input data to a new file in Notepad.
Try opening the file in binary mode:
ifstream fin("data.txt", ios::binary);
Creating the ifstream with std::ios::binary fixed the tellg so it returned the correct position in the file in my code as well (Win 7 64-bit).
As L.Lawliets asks - Why??!
I compiled and ran your code with the tellg lines re-enabled, and it seemed to work fine. The output I got was:
MissionImpossible3
20
3
21
23
TomCruise
34
MaggieQ
43
JeffChase
52
What exact result do you get when you try to run it? [Yes, this is really more of a comment than an answer, but it won't fit in a comment.]