I get confused with the "istream& getline (istream& is, string& str)"function, and according to http://www.cplusplus.com/reference/string/string/getline/, the following program:
#include <iostream>
#include <sstream>
int main()
{
std::istringstream s("this is a test");
std::string line = "line ";
getline( s, line );
std::cout << line << std::endl;
s.str("test again");
getline( s, line );
std::cout << s.str() << std::endl;
std::cout << line << std::endl;
return 0;
}
I expect the output to be:
line this is a test
test again
test again
but when I test it on Visual Studio, the output is :
this is a test
test again
this is a test
Could anyone explain the frustrating function for me ?
Clear the error flags between the calls to getline:
int main()
{
std::istringstream s("this is a test");
std::string line = "line ";
getline( s, line );
std::cout << line << std::endl;
s.str("test again");
s.clear() // <<<--------------- to clear error flags
getline( s, line );
std::cout << s.str() << std::endl;
std::cout << line << std::endl;
return 0;
}
The first getline sets eofbit on the stream. The second one then fails and line stays intact.
With the fix, you'll get:
this is a test
test again
test again
because getline doesn't add to the string, it replaces the content.
Whatever value line has prior to the call will not matter, as from the documentation for std::getline:
Calls str.erase()
Your second logical error is due to reusing a stream once you've reached its end.
Related
I have a vector of strings in C++, named lines.
This line
std::cout << "First line: >" << lines[0] << "<" << std::endl;
prints ">irst line: >string_here" instead of "First line: >string_here<".
Why does cout start printing at the start of the current line after the string, and how can I resolve it? I also tried to flush after every cout but result was the same.
This is a full code that ilustrates my problem, BEFORE it was solved:
#include <iostream>
#include <vector>
#include <string.h>
std::vector<std::string> parse(char *buffer, const char *delimiter) {
std::string buff(buffer);
size_t pos = 0;
std::string part;
std::vector<std::string> parts;
while ((pos = buff.find(delimiter)) != std::string::npos) {
part = buff.substr(0, pos);
parts.push_back(part);
buff.erase(0, pos + 1);
}
parts.push_back(buff);
return parts;
}
int main() {
char *s;
s = strdup("Many lines\r\nOf text");
std::cout << s << std::endl; // this should print the string how it is
std::vector<std::string> lines;
lines = parse(s, "\n"); // parsing the string, after "\n" delimiter
// that was the problem, I should have parsed after "\r\n"
std::cout << "First line: >"<< lines[0] << "<" << std::endl; // output
}
It's impossible to be sure without the full content of lines[0], but my (educated) guess would be that lines[0] ends with \r, the carriage return character, so everything printed after lines[0] is printed a the beginning of the line.
I seems std::cout does not work consistently in printing multiple things, as shown in the following two examples. I thought it might related to buffer flush but it made no difference even if I add a number of std::flush in the test example.
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
void test(const std::string& f1);
int main(void) {
std::string a = "a";
std::cout << a << a << a << std::endl;
// Then I got aaa on the screen, which is as expected.
test("inputfile");
// The input file contains one character: "a"
// after running the test I got only one "a" on the screen
// even though the string is repeated three times in the cout statement, as in the previous case
return 0;
}
void test(const std::string& f1){
std::ifstream ifile;
ifile.open(f1);
for(std::string line; std::getline(ifile, line); ) {
std::cout << line << line << line << std::endl;
}
ifile.close();
}
I expected to see
aaa
aaa
on the screen, but the actual output was
aaa
a
I use this to compile
g++ -g -std=c++11 -o test test.cpp
The version of g++ is 5.2.0.
I have a feeling the comment by Mark Ransom points out the problem. You can verify that hypothesis by opening your file in binary mode and printing the integer values that encode the characters.
void test(const std::string& f1){
std::ifstream ifile;
ifile.open(f1, std::ifstream::binary);
int ch;
while ( (ch = ifile.get()) != EOF )
{
// Print the integer value that encodes the character
std::cout << std::setw(2) << std::setfill('0') << std::hex << ch << std::endl;
}
ifile.close();
}
If the output is
61
0d
0a
and your platform is not Windows, then the output your are getting would make sense.
The line read from the file contains the characters 'a' (0x61) and '\r' (0x0d).
The carriage return character ('\r') causes the line to be written on top of the previous output.
i am writing this very simple program that ouputes hello world using files. keep in mind i want the hello and world to be on separate lines.
here is the following code:
int main()
{
std::ofstream someFile("file.dat");
someFile << "" << std::endl;
std::fstream someOtherFile("file.dat",ios::in | ios::out);
std::string content;
someOtherFile << "hello" << std::endl;
someOtherFile << "world" << std::endl;
someOtherFile.seekg(0, ios::beg);
std::getline(someOtherFile, content);
std::cout << content << std::endl;
return 0;
}
however, whenever i run the following program, it only prints "hello".
any help will be greatly appreciated, and PLEASE give an example using fstream, not ofstream or ifstream (I am trying to learn how fstream works, however am finding a little trouble).
my compiler is the latest VS.
getine function only read one line per one time, so you should call getline until the end of file. The code be below can help you.
#include <iostream>
#include <fstream>`
#include <string>
using namespace std;
int main()
{
std::ofstream someFile("file.dat");
someFile << "" << std::endl;
std::fstream someOtherFile("file.dat",ios::in | ios::out);
std::string content;
someOtherFile << "hello" << std::endl;
someOtherFile << "world" << std::endl;
someOtherFile.seekg(0, ios::beg);
while(std::getline(someOtherFile, content))
{
std::cout << content << std::endl;
}
return 0;
}
You have 2 lines of code:
someOtherFile << "hello" << std::endl;
someOtherFile << "world" << std::endl;
They put 2 lines of strings into file.dat:
// file.dat
hello
world
The function "getline()" gets only 1 line from the file. And the "seekg" function sets the read position to the first line of the file: which contains "hello".
If you want to read to the end of the file: then replace:
std::getline(someOtherFile, content);
std::cout << content << std::endl;
with:
while (!someOtherFile.eof())
{
std::getline(someOtherFile, content);
std::cout << content << std::endl;
}
Or use a counter variable if you just want specific lines.
By the way, I am just assuming that you meant to put the variable "content" where "name" is.
std::getline only get one line of text from the specific file. As http://www.cplusplus.com/reference/string/string/getline/?kw=getline says:
istream& getline (istream& is, string& str);
Extracts characters from is and stores them into str until the delimitation character delim is found (or the newline character, '\n', for (2)).
Add another getline(..) and cout statement after the first set of getline and cout. you will get the world as output.
someOtherFile << "hello" << std::endl;
someOtherFile << "world" << std::endl;
someOtherFile.seekg(0, ios::beg);
std::getline(someOtherFile, content);
std::cout << content << std::endl;
std::getline(someOtherFile, content);
std::cout << content << std::endl;
getline gets only one line in a file. To get next line, you need to call again.
#include<fstream>
#include<iostream>
using namespace std;
int main()
{
std::ofstream someFile("file.dat");
someFile << "" << std::endl;
someFile.close();
std::fstream someOtherFile("file.dat",ios::in | ios::out);
std::string content;
someOtherFile << "hello ";
someOtherFile << "world" << std::endl;
someOtherFile.close();
someOtherFile.seekg(0, ios::beg);
std::getline(someFile1, content);
std::cout << content << std::endl;
someFile1.close();
return 0;
}
This will print your desired answer
Using the following code to extract a string from a std::istream :
#include <sstream>
#include <iostream>
void parse(std::istream & is, std::string & out)
{
is >> out;
}
int main(int argc, char** argv)
{
if (argc>1)
{
std::istringstream is(argv[1]);
std::string out("__INIT__");
std::cout << "good:" << is.good() << " fail:"<< is.fail() << " eof:"<< is.eof() << " in_avail:"<< is.rdbuf()->in_avail() << " value:" << out << std::endl;
parse(is, out);
std::cout << "good:" << is.good() << " fail:"<< is.fail() << " eof:"<< is.eof() << " in_avail:"<< is.rdbuf()->in_avail() << " value:" << out << std::endl;
}
}
With a non-empty string the output looks like :
$./a.out "TEST"
good:1 fail:0 eof:0 in_avail:4 value:__INIT__
good:0 fail:0 eof:1 in_avail:0 value:TEST
With an empty string the output looks like :
$./a.out ""
good:1 fail:0 eof:0 in_avail:0 value:__INIT__
good:0 fail:1 eof:1 in_avail:0 value:__INIT__
Instead of this, I would expect :
good:1 fail:0 eof:0 in_avail:0 value:__INIT__
good:0 fail:0 eof:1 in_avail:0 value:
The operator>> does not extract an empty string. The result is the same with an empty string or and no data.
Any suggestion to handle this situation will be appreciated.
If you're using your parse function exclusively for extraction, you can simply make it out to be a check for an empty buffer. If there is, simply clear the string:
void parse(std::istream& is, std::string& out)
{
if (is.eof() || is.peek() == std::char_traits<char>::eof())
{
out.clear();
return;
}
is >> out;
}
There is no difference between an empty value and no value.
That's just your assumption, and it's not really true.
If you attempt to extract a string, it is expected that there are characters to extract. Before characters are available, it is impossible to perform any extraction, let alone one that results in extraction to a particular object.
This is entirely expected behaviour.
I guess your confusion stems from your prior check for argc > 1, but although the shell pretended ./myProgram "" had some argument, as far as your stream is concerned there is nothing in that argument.
If you wish to make your own handling for it, simply stick an if condition on is.fail() after the read.
#include <sstream>
#include <iostream>
int main(int argc, char** argv)
{
if (argc>1)
{
std::istringstream is(argv[1]);
std::string out;
is >> out;
if (is.fail()) {
std::cout << "Well, you gave me an argument, but it was empty, biatch!\n";
}
}
}
Don't bother checking is.eof(); it'll be set when you reached the end of input whether it contained any characters or not.
in the following small program I want to read the inputString with whitespace:
#include <string>
#include <sstream>
#include <iostream>
int main( int argc , char ** argv ) {
std::string inputString(" ITEM ");
std::istringstream inputStream( inputString );
//Template:
T value;
inputStream.unsetf(std::ios::skipws);
inputStream >> value;
std::cout << "Value: [" << value << "]" << std::endl;
std::cout << "StringPos: " << inputStream.tellg() << std::endl;
std::cout << "State: " << inputStream.good() << std::endl;
}
This produces the output:
Value: []
StringPos: -1
State: 0
If I remove the the unsetf() call I instead get:
Value: [ITEM]
StringPos: 4
State: 1
I.e. as expected when whitespace is ignored. So - obviously I do something wrong with the "Don't skip whitespace" setting. Any tips?
Edit: After adding the template-like "T value" the example does not compile any longer; but it is important that the
inputStream >> value;
works. The following meta code should work as well:
if is_string(T)
value = inputString; // String values are assigned directly
else
inputStream >> value; // Other types.
Joakim
Use:
std::string line;
if(std::getline(inputStream, line)) {
// line contains one line from the input stream
} else {
// inputStream is empty, EOF or in error state
}