I've been trying to read some information in from a .txt file in C++ but it's not all working like I expect. Here is some example code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char words[255];
int value = 0;
ifstream input_stream("test.txt");
input_stream >> value;
input_stream.getline(words, 256);
cout << value << endl;
cout << words << endl;
}
And test.txt contains:
1234
WordOne WordTwo
What I expect is for the code to print the two lines contained in the text file, but instead I just get:
1234
I've been reading about getline and istream but can't seem to find any solutions so any help would be appreciated.
Thanks
The newline character remains in the input stream after the read of the integer:
// Always check result to ensure variables correctly assigned a value.
if (input_stream >> value)
{
}
Then, the call to getline() reads the newline character and stops, producing an empty string. To correct, consume the newline character before calling getline() (options include using getline() or ignore()).
Note there is a version std::getline() that accepts a std::string as its argument to avoid using a fixed sized array of char, which is used incorrectly in the posted code.
ifstream's getline method gathers input until one of two options is hit. Either a terminating character or the size passed in is reached. In your case, the newline terminator is encountered before the size is reached.
Use another getline to retrieve the second line of text.
Reference
The problem you are seeing is that the first newline after 1234 is not consumed by input_stream>>(int); so the next getline only reads to the end of that file.
This is a very constructed scenario, commonly found in schoolwork. The more common scenario when reading a textfile is to consider the entire file as linebased text.
In this case the more convenient
string line;
while( std::getline( input_stream, line ) ){
}
is appropriate, and way less error prone.
The textfile would commonly have a predefined format. Perhaps name = value lines, and are parsed as such after the line is read from the file.
Here is a somewhat corrected version of your original code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char words[256]; // was 255
int value = 0;
ifstream input_stream("test.txt");
input_stream >> value;
input_stream.ignore(); // skip '\n'
input_stream.getline(words, 256);
cout << value << endl;
cout << words << endl;
}
Also, I would advise you to use a string instead of a char[] and use the other getline function.
Related
I am learning C++. I want to take multiple line string as input but I can't. I am using getline() for it but it is taking only one line input. When I press enter for writing next line it stoped taking input and print the first line.
I want to give input like the example below
Hello, I am Satyajit Roy.
I want to make a program.
I love to travel.
But it takes only the first line input.
My code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
getline(cin, s);
cout << s << endl;
return 0;
}
Please help me to know how can I do that.
Thank you.
Either you write a loop to read individual lines and concatenate them to a single string, thats what this answer suggests. If you are fine with designating a specific character to signal the end of the input, you can use the getline overload that takes a delimiter as parameter:
#include <iostream>
#include <string>
int main() {
std::string s;
std::getline(std::cin,s,'x');
std::cout << s;
}
The user would have to type an x to end input, so this input
Hello, I am Satyajit Roy.
I want to make a program.
I love to travel.
x
would result in this output:
Hello, I am Satyajit Roy.
I want to make a program.
I love to travel.
Of course this won't work when the string to be entered contains x, which renders the approach rather useless.
However, instead of using a "real" character as delimiter you can use the EOF character (EOF = end of file) like this:
std::getline(std::cin, s, static_cast<char>(EOF));
Then input is terminated by whatever your terminal interprets as EOF, eg Ctrl-d in linux.
Thanks to #darcamo for enlightening me on the EOF part.
You can only read one line at a time with std::getline if you don’t provide your own delimiter. If you want to accumulate multiple lines, one at a time, you need a place to put the result. Define a second string. Read a line at a time into s with std::getline, and then append s to the result string. Like this:
std::string result;
std::string s;
while (std::getline(std::cin, s))
result += s;
You can take several lines using the code below if you know how many lines you will input.
int line=3, t;
string s, bigString;
for(int i=0 ; i<line ; i++)
{
getline(cin,s); // This is to input the sentence
bigString += s + "\n";
}
cout << bigString;
If you don't know how many lines you will input (Input from file until end of file) then you can check this.
string s;
vector<string> all;
while(getline(cin,s))
{
all.push_back(s);// This is to input the sentence
}
for(auto i:all)
{
cout << i << endl;
}
Imagine I want to copy-paste some text in stdin and I want to read it entirely in cpp (including whitespace). How can I do it? If I use cin, it reads tokens delimited by whitespace. If I do:
string text
string s;
while(cin>>s){
text += s;
}
Then it gets indistinguishable whether it was space(" ") or newline("\n") between tokens.
Question is, how can I read the whole string.
If you want something that is quick to code, use std::istream::getc.
std::string text;
char c;
while ( std::cin.getc(c) )
{
text.push_back(c);
}
If you expect the content of stdin to be large, this will be a performance problem. You should consider using std::istream::read for such use cases.
To make the result of the provided while loop approach distinguishable, I had to read it with readline() like this:
string text
string s;
while(readline(cin,s)){
text += s + "\n";
}
This way, it's guaranteed that readline will read the whole line (with spaces) and the given tokens will be only delimited by "\n" (which can be added manually).
From cplusplusreference.com:
As an object of class istream, characters can be retrieved either as
formatted data using the extraction operator (operator>>) or as
unformatted data, using member functions such as read.
cin - C++ Reference
I get:
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
using std::endl;
int main()
{
char c;
string text;
while (!cin.read(&c, 1).eof())
s += c;
cout << "string was " << s << endl;
}
On Windows, end it with a <Ctrl-Z> on a line by itself, followed by <Enter>. I tested it, and it does indeed include the end of line characters.
So I was taking input some integers and then taking input some sentences.
This code works fine:
#include<bits/stdc++.h>
using namespace std;
main(){
int c,b,n,i;string s;
cin>>n>>b>>c;
for(i=0;i<n;i++){
cin>>ws;
getline(cin,s,'\n');
cout<<s;
}
}
Example:
3 3 3
This is weird
This is weirdDefinitely makes
Definitely makesNo sense
No sense
However, when I try to omit the cin>>ws inside the forloop, it doesn't work properly, eg this code segment,
#include<bits/stdc++.h>
using namespace std;
main(){
int c,b,n,i;string s;
cin>>n>>b>>c;
for(i=0;i<n;i++){
getline(cin,s,'\n');
cout<<s;
}
}
Example:
3 3 3
This is weird
This is weirdDefinitely makes
Definitely makes
..and terminates there instead of taking all three inputs.
Why is that? cin>>ws extracts all whitespace from the input but isn't getline() doing that too? So why does it not work properly when I omit cin>>ws in the forloop?
std::getline() extract characters until it extracted the first delimiter character (by default '\n'). The delimiter is not stored in the result but it is extracted. It does not extract whitespace in general or multiple delimiter characters.
As an aside: always check whether input works after trying to read a value.
In the example printed, the issue is is that after formatted input, i.e., using the >> operator, whitespaces are not extracted. That is, the first calls to std::getline() extracts the empty string terminated by the initial newline. It generally is necessary to extract trailing whitespace when switching between formatted and unformatted I/O. That is, You'd want code like
if (cin>>n>>b>>c >> std::ws) {
for(i=0;i<n;i++){
if (getline(cin,s,'\n')) {
cout << "i=" << i << ":'" << s << "'\n";
}
}
}
I can't recommend input operations without adding check for success. The output is changed to make it more easily visible what is going on: try the code with/without this particular std::endl to see what is happening.
When you use cin >> it doesn't remove any whitespace after the input. This means the newline that terminated the first 3 inputs is still in the buffer, waiting to be read by the first getline. Since there's nothing before the newline, the first getline delivered an empty string. Your output should have included a newline so you could have seen the empty line, then it would have made sense.
Originally the code you posted showed a cin >> ws just before the for loop which would have eliminated this problem.
The default delimiter for getline() is '\n', so there is no need to include that in the getline call, though, it should not change the functionality.
See for example Same as getline(input, str, input.widen('\n')), that is, the default delimiter is the endline character.
The change in formatting from the integer input to the getline() input leaves some whitespace (endl) after the integer as explained by #DietmarKühl.
You can change the getline() call to eliminate the delimiter to
getline(cin,s);
which will cause getline() to use '\n' as the default delimiter.
I have modified the 'n' variable to count and removed the other integers to make the code a little simpler to read:
#include <iostream>
int main()
{
int i; // index
int count; // number of strings to accept
std::string str;
std::cout << "Input the number of strings you would like me to process: " << std::endl;
std::cin >> count;
if (std::cin >> count >> std::ws) {
for (i = 0; i < count; i++) {
if (getline(std::cin, str)) {
std::cout << "i=" << i << ":'" << str << "'\n";
}
}
}
}
Cin doesn't extract all white spaces, it just gets the first word until the first white space. It is like having a getline with a space delimiter(not quite but close to).
Getline takes the whole line and has the default '\n' delimiter like mentioned above.
Ex:
string a = "Stack Overflow is awesome";
can give you Stack and getline will give you everything at that line
I'm trying to write a program that returns the number of characters in a string. As I was writing my program, I've noticed that there's a bug in the string class.
Say my program is this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string input;
cout << "Input string: ";
cin >> input
cout << "Number of characters: " << input.size() << endl;
return 0;
}
If my input is Test String, I should see the number 11 as the output.
However, the output I get is this:
Number of characters: 4
It seems like the size() method does not work when there is space in the string.
My question is, is there another way to get the number of characters in a string? I tried length() method but the result was the same.
That's because your
cin >> input;
only reads up to the first whitespace character.
If you want to get the a whole line, use the following code:
std::string s;
std::getline(std::cin, s);
This is not a bug, and more particularly, actually has nothing to do with the string class.
It has to do with the istream class (cin). cin's operator>> performs "formatted input," which is to say, input delimited by whitespace. After you hit enter, you read out "Test" into a string, leaving "String" in the input buffer. "Test" is, in fact, four characters long.
Consider using std::getline or istream::getline to read entire lines of input with more control. Be sure to read the documentation for these methods carefully, as they have different behavior with respect to what is left in the input stream which can then cause results you may not expect if mixed together with oeprator>> usage.
This is a result of the meaning of cin >> input, which stops reading when any whitespace is found. If you want to keep reading until the end of a line, try getline.
After taking input correctly, you can get the length of the string or char pointer(char*)(including whitespaces) by using strlen(string_name), this will return the length.
i have a little problem on writing the string into a file,
How can i write the string into the file and able to view it as ascii text?
because i am able to do that when i set the default value for str but not when i enter a str data
Thanks.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
fstream out("G://Test.txt");
if(!out) {
cout << "Cannot open output file.\n";
return 1;
}
char str[200];
cout << "Enter Customers data seperate by tab\n";
cin >> str;
cin.ignore();
out.write(str, strlen(str));
out.seekp(0 ,ios::end);
out.close();
return 0;
}
Please use std::string:
#include <string>
std::string str;
std::getline(cin, str);
cout << str;
I'm not sure what the exact problem in your case was, but >> only reads up to the first separator (which is whitespace); getline will read the entire line.
Just note that >> operator will read 1 word.
std::string word;
std::cin >> word; // reads one space seporated word.
// Ignores any initial space. Then read
// into 'word' all character upto (but not including)
// the first space character (the space is gone.
// Note. Space => White Space (' ', '\t', '\v' etc...)
You're working at the wrong level of abstraction. Also, there is no need to seekp to the end of the file before closing the file.
You want to read a string and write a string. As Pavel Minaev has said, this is directly supported via std::string and std::fstream:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ofstream out("G:\\Test.txt");
if(!out) {
std::cout << "Cannot open output file.\n";
return 1;
}
std::cout << "Enter Customer's data seperated by tab\n";
std::string buffer;
std::getline(std::cin, buffer);
out << buffer;
return 0;
}
If you want to write C, use C. Otherwise, take advantage of the language you're using.
I can't believe no one found the problem. The problem was that you were using strlen on a string that wasn't terminated with a null character. strlen will keep iterating until it finds a zero-byte, and an incorrect string length might be returned (or the program might crash - it's Undefined Behavior, who knows?).
The answer is to zero-initialize your string:
char str[200] = {0};
Supplying your own string as the value of str works because those in-memory strings are null-terminated.