why this code
char magicData [] = { 0x00i8, 0xfdi8, 0xffi8, 0xfci8, 0x00i8,
0xf3i8, 0xf4i8, 0xf5i8, 0x00i8};
std::string s;
std::istringstream ss(magicData, sizeof(magicData));
while(std::getline(ss, s))
{
std::cout << s << std::endl;
}
don't produce any output? (using stringstream instead of istringstream doesn't help).
As result i expect 2 line of string (without 0x00 at end).
How to solve it?
std::istringstream doesn't have a constructor that takes an array. You're actually calling the constructor that takes a C-style string and an openmode. All you need for this to work is:
std::istringstream ss(std::string(magic, magic + sizeof(magic)));
Related
What I want to do is get user input from the terminal and use this input in other functions in my program. Since my functions only take input streams as arguments I want to convert the input string into an input stream.
int main(int argc, char** argv)
{
std::vector<std::string> args(argv, argv + argc);
if(args.size() == 1){ //if no arguments are passed in the console
std::string from_console;
std::istringstream is;
std::vector<std::string> input;
while(!getline(std::cin,from_console).eof()){
input.emplace_back(from_console);
}
for(std::string str : input){
std::cout << "\n" << str;
}
}
Another questions that arose when I was trying this code, was that when I ended the console input with a bunch of characters and not with a new line(pressing enter then ctrl+d) the line was ignored and didn't get printed out.
Example:
When I typed the following:
aaa bbb
ccc ctrl+d
I got only the first line(aaa bbb) and not ccc printed out.
But:
aaa bbb
ccc
ctrl+d
prints out ccc as well, but it does ignore the new line. So why is this happening?
Is there a way to turn input string to input stream in c++?
Yes, it is possible. This is what std::istringstream is for. Example:
std::string input = some_input;
std::istringstream istream(input); // this is an input stream
The std::istringstream class has a constructor that takes a std::string as an argument, which uses a copy of the string passed as the initial content of the stream.
So, rather than use a std::vector to store all your input lines from the console, just keep adding those to a single (different) std::string object, remembering to add the newlines after each, then construct your std::istringstream from that.
Here is a trivial example that shows how you can use std::getline (which, like your functions, takes an input stream as its first argument) equally well on std::cin and a std::istringstream object created like that:
#include <iostream>
#include <sstream>
int main()
{
std::string buffer; // Create an empty buffer to start with
std::string input;
// Fill buffer with input ...
do {
getline(std::cin, input);
buffer += input;
buffer += '\n';
} while (!input.empty()); // ... until we enter a blank line
// Create stringstream from buffer ...
std::istringstream iss{ buffer };
// Feed input back:
do {
getline(iss, input);
std::cout << input << "\n";
} while (!input.empty());
return 0;
}
When the eof is in the same line as the last line of content, getline(std::cin,from_console) will reach it and .eof() will return true, thus the last line is read into string from_console but not push into the vector.
There are two ways:
Modify your code by pushing the last line into the vector manually:
while(!getline(std::cin,from_console).eof()){
input.emplace_back(from_console);
}
input.emplace_back(from_console); // add one line
for(std::string str : input){
iterator can be an elegant way:
#include <iterator>
// ...
if (args.size() == 1) { // if no arguments are passed in the console
copy(std::istream_iterator<std::string>(std::cin), {},
std::ostream_iterator<std::string>(std::cout, "\n"));
}
I have a text file with a series two strings delimited by a colon on each line.
I'm using getline to grab the entire line then string stream to split the two strings and put them onto a vector. The code works fine on the first pass it grabs the strings perfectly. Then after that on the 2nd pass of the while loop and so forth it doesn't grab the new input. The string stream seems to leave the original first values for some reason.
if (infile.is_open()) {
std::stringstream ss;
std::string current_line;
std::string tempProxy;
std::string tempPort;
while (std::getline(infile, current_line)) {
ss << current_line;
std::getline(ss, tempProxy, ':');
std::getline(ss, tempPort);
std::cout << tempProxy << " and " << tempPort << std::endl;
}
Any idea why it doesn't want to grab the strings from current_line on any pass except the first iteration?
You're reusing ss but not resetting it correctly. When you extract the second word from the first line, the stream is exhausted and put in an 'EOF' state. When streams are in this or any other 'error' state they don't do anything. You have to clear the error before you can continue to use them.
If you were to check for errors returned by operator<< and getline in the loop (or if you were to cause ss to throw exceptions on errors*) you would find they are indicating that they are not successful past the first iteration. It's a good general practice to always check for errors, and especially so when you're debugging.
You can clear the error by changing your loop:
while (std::getline(infile, current_line)) {
ss.clear(); // clears the error, not the contents
ss << current_line;
However doing this means that ss will accumulate all the lines in its internal buffer. The code will produce your expected output unless the file is large and you run out of memory or something like that.
You can see the accumulating internal buffer with the following:
while (std::getline(infile, current_line)) {
ss.clear();
ss << current_line;
std::cout << "ss internal buffer: " << ss.str();
Instead of using the formatted input to add ss you are probably better off using the .str() member to set it, which will replace the previous data instead of adding to it.
while (std::getline(infile, current_line)) {
ss.clear();
ss.str(current_line);
Alternatively you can construct a new stringstream in each iteration of the loop. This does ensure that no error states or data are carried over from previous iterations. It may also be slower, but you'll have to profile that for yourself.
while (std::getline(infile, current_line)) {
std::stringstream ss(current_line);
* Exceptions are nice because you don't need to remember to check them... except in cases like this where they're not enabled by default. Also I've noticed some C++ implementations have bugs in their iostreams exception code because people don't use it much.
I think you're looking for something like:
if (infile.is_open()) {
std::stringstream ss;
std::string current_line;
std::string tempProxy;
std::string tempPort;
while (std::getline(infile, current_line)) {
std::stringstream to_split;
to_split.str(current_line);
std::getline(to_split, tempProxy, ':');
std::getline(to_split, tempPort);
std::cout << tempProxy << " and " << tempPort << std::endl;
}
Why does this program print out blank?
string str;
stringstream ss(str);
ss << "A string";
cout << str; // just blank
stringstream is not going to modify the argument you pass to its constructor.
Instead, you can get the current buffer from the stringstream by calling its str member function:
cout << ss.str();
Next time, consider reading the documentation.
As my learning, I am trying to use c++ ifstream and its operator>> to read data from a text file using code below. The text file outdummy.txt has following contents:
just dummy
Hello ofstream
555
My questions is how to read char data present in the file into a char array or string. How to do this using the ifstream::operator>> in code below.
#include <iostream>
#include <fstream>
int main()
{
int a;
string s;
char buf[100];
ifstream in("outdummy.txt",ios_base::in);
in.operator>>(a); //How to read integer? How to read the string data.??
cout << a;
in.close();
getchar();
return 0;
}
If you want to use formatted input, you have to know in advance what data to expect and read it into variables of the according data type. For example, if you know that the number is always the fifth token, as in your example, you could do this:
std::string s1, s2, s3, s4;
int n;
std::ifstream in("outdummy.txt");
if (in >> s1 >> s2 >> s3 >> s4 >> n)
{
std::cout << "We read the number " << n << std::endl;
}
On the other hand, if you know that the number is always on the third line, by itself:
std::string line;
std::getline(in, line); // have line 1
std::getline(in, line); // have line 2
std::getline(in, line); // have line 3
std::istringstream iss(line);
if (iss >> n)
{
std::cout << "We read the number " << n << std::endl;
}
As you can see, to read a token as a string, you just stream it into a std::string. It's important to remember that the formatted input operator works token by token, and tokens are separated by whitespace (spaces, tabs, newlines). The usual fundamental choice to make is whether you process a file entirely in tokens (first version), or line by line (second version). For line-by-line processing, you use getline first to read one line into a string, and then use a string stream to tokenize the string.
A word about validation: You cannot know whether a formatted extraction will actually succeed, because that depends on the input data. Therefore, you should always check whether an input operation succeeded, and abort parsing if it doesn't, because in case of a failure your variables won't contain the correct data, but you have no way of knowing that later. So always say it like this:
if (in >> v) { /* ... */ } // v is some suitable variable
else { /* could not read into v */ }
if (std::getline(in, line)) { /* process line */ }
else { /* error, no line! */ }
The latter construction is usually used in a while loop, to read an entire file line by line:
while (std::getline(in, line)) { /* process line */ }
ifstream has ios_base::in by default. You don't need to specify it.
operator>> can be invoked directly as an operator: in >> a.
Reading strings is the same: in >> s, but the caveat is that it is whitespace-delimited, so it will read "just" by itself, without "dummy".
If you want to read complete lines, use std::getline(in, s).
Since you have elected to use C-strings, you can use the getline method of your ifstream object (not std::getline() which works with std::strings), which will allow you to specify the C-string and a maximum size for the buffer.
Based on what you had, and adding an additional buffer for the second line:
char buf[100];
char buf2[100];
in.getline(buf,sizeof(buf));
in.getline(buf2,sizeof(buf2));
in >> a;
However, as the other poster has proposed, try using the std::string and its methods, it will make your life easier.
You can read file contents and use a Finite State Machine for parsing.
Example:
void Parse(const char* buffer, size_t length);
size_t GetBufferSize();
size_t bufferSize = GetBufferSize();
char* buffer = new char[bufferSize];
std::ifstream in("input.txt");
while(in.getline(buffer, bufferSize)) {
Parse(buffer, in.gcount());
}
Alternatively, you can use a tool like Flex to write your parser.
I'm using a third party code which has its own implementation for std::ostream operator<<, to handle the third party's type.
I'm using stringstream for this output - like:
string ToString(const thrdPartyType& structure)
{
stringstream outputStream;
outputStream<<structure;
return outputStream.str();
}
...
string str = ToString(structure);
...
This structure contains pointer members, which are set to NULL. When using the operator<< and the assignment of str() into a string, I see (via gdb - print str) that there are many leading '\000' characters, then the string data I need.
How can I trim those NULLs in order to get only the real, not empty data?
P.S. The exact code works fine in Windows VC++...
Thank you.
Are you looking for a workoround like this?
string ToString(const thrdPartyType& structure)
{
stringstream outputStream;
outputStream << structure;
stringstream workaround;
while(! outputStream.eof ) {
char t;
outputStream >> t;
if(t != '\0')
workaround << t;
}
return workaround .str();
}
If you have boost available, something like the following will replace all instances of null in a string with another value.
boost::replace_all(str,boost::as_array(""),"NULL");
For example
char buf[10] = "hello";
string str(buf,buf+10);
boost::replace_all(str,boost::as_array(""),"NULL");
cout << str << endl;
Produces the following output
helloNULLNULLNULLNULLNULL