Unexpected repetition while extracting integers from string in c++ using stringstream - c++

I am trying to read a file which consist of lines that are made of space separated integers. I want to store each line as a separate vector of integers.
so I tried reading input line by line and extracting integers from it using
stringstream
The code I have used for extraction is as follows -
#include <bits/stdc++.h>
using namespace std;
int main()
{
freopen("input.txt","r",stdin);
string line;
while(getline(cin, line)) {
int temp;
stringstream line_stream(line); // conversion of string to integer.
while(line_stream) {
line_stream >> temp;
cout << temp<< " ";
}
cout << endl;
}
return 0;
}
Above code works but it repeats the last element.For example, input file -
1 2 34
5 66
output:
1 2 34 34
5 66 66
How can I fix this?

Because of this:
while(line_stream) {
line_stream >> temp;
cout << temp<< " ";
}
which fails for the same reason that while (!line_stream.eof()) would fail.
When you have read the last integer, you haven't reached the end of the stream yet - that will happen on the next read.
And the next read is the unchecked line_stream >> temp;, which will fail and leave temp untouched.
The proper form for such a loop is
while (line_stream >> temp)
{
cout << temp<< " ";
}

Related

Reading coordinate file with ifstream while ignoring headers and writing to array

There's a series of coordinates I'm trying to write to an array so I can perform calculations on, but I haven't been able to read the file correctly since I can't ignore the headers, and when I do remove the headers it also doesn't seem to correctly write the values to the array.
The coordinate file is a txt as below.
Coordinates of 4 points
x y z
-0.06325 0.0359793 0.0420873
-0.06275 0.0360343 0.0425949
-0.0645 0.0365101 0.0404362
-0.064 0.0366195 0.0414512
Any help with the code is much appreciated. I've tried using .ignore to skip the two header lines but they don't seem to work as expected.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
int main() {
int i = 1;
int count = 1;
char separator;
const int MAX = 10000;
int x[MAX];
int y[MAX];
int z[MAX];
int dist[MAX];
char in_file[16]; // File name string of 16 characters long
char out_file[16];
ifstream in_stream;
ofstream out_stream;
out_stream << setiosflags(ios::left); // Use IO Manipulators to set output to align left
cout << "This program reads a series of values from a given file, saves them into an array and performs calculations." << endl << endl;
// User data input
cout << "Enter the input in_file name: \n";
cin >> in_file;
cout << endl;
in_stream.open(in_file, ios::_Nocreate);
cout << "Enter the output file name: \n";
cin >> out_file;
cout << endl;
out_stream.open(out_file);
// While loop in case in_file does not exist / cannot be opened
while (in_stream.fail()) {
cout << "Error opening '" << in_file << "'\n";
cout << "Enter the input in_file name: ";
cin >> in_file;
in_stream.clear();
in_stream.open(in_file, ios::_Nocreate);
}
while (in_stream.good) {
in_stream.ignore(256, '\n');
in_stream.ignore(256, '\n');
in_stream >> x[i] >> separator >>y[i] >> separator >> z[i];
i++;
count = count + 1;
}
cout << x[1] << y[1] << z[1];
in_stream.close();
out_stream.close();
return 0;
}
Within your reading of the file, you are using in_stream.ignore(256, '\n'); correctly, but you want to use it outside the while loop. When you have it inside the while loop, every time it runs, you will ignore the first two lines, then read the third. Your output would actually read in only a third of what you expect. To fix this, just move those 2 lines outside the while loop.
in_stream.ignore(256, '\n');
in_stream.ignore(256, '\n');
while (in_stream.good)
{
in_stream >> x[i] >> separator >>y[i] >> separator >> z[i];
i++;
count = count + 1;
}
This should fix your problem, but you should generally use a vector instead of an array. Vectors automatically manage memory and check for bounds instead of you having to do that.
Also, good practice is to read values out of the stream as the while condition instead of in_stream.good:
while(stream >> var)
{
//Your code here
}
Here is a good resource on why that is.

How to simulate user input to std::cin for a mcve? [duplicate]

If we have this code snippet:
int a;
cout << "please enter a value: ";
cin >> a;
And in the terminal, the input request would look like this
please enter a value: _
How can I programatically simulate a user's typing in it.
Here's a sample how to manipulate cin's input buffer using the rdbuf() function, to retrieve fake input from a std::istringstream
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
istringstream iss("1 a 1 b 4 a 4 b 9");
cin.rdbuf(iss.rdbuf()); // This line actually sets cin's input buffer
// to the same one as used in iss (namely the
// string data that was used to initialize it)
int num = 0;
char c;
while(cin >> num >> c || !cin.eof()) {
if(cin.fail()) {
cin.clear();
string dummy;
cin >> dummy;
continue;
}
cout << num << ", " << c << endl;
}
return 0;
}
See it working
Another option (closer to what Joachim Pileborg said in his comment IMHO), is to put your reading code into a separate function e.g.
int readIntFromStream(std::istream& input) {
int result = 0;
input >> result;
return result;
}
This enables you to have different calls for testing and production, like
// Testing code
std::istringstream iss("42");
int value = readIntFromStream(iss);
// Production code
int value = readIntFromStream(std::cin);
Hey why don't you write your input in a plain text file and redirect it to cin ???
It's the simplest method.
Open Command Prompt.
Suppose your text file which will used as input is in.txt and your program is prog.exe.
Keep the text file and the program in same folder. cd to your folder. Then type:
prog.exe < in.txt
Remember, your text file will be treated exactly as it is. Shoudld't be a problem if you know cin only catches upto next whitespace character, while string input functions (e.g. cin.getline) only catch upto next newline character.
//Sample prog.cpp
#include <iostream>
using namespace std;
int main()
{
int num;
do
{
cin >> num;
cout << (num + 1) << endl;
}
while (num != 0);
return 0;
}
//Sample in.txt
2
51
77
0
//Sample output
3
52
78
1
Sorry if you are on other platform, I don't know about them.

What is a good way to read in and separate information from this text file?

Let's say I have a text file:
83 71 69 97Joines, William B.
100 85 88 85Henry, Jackson Q.
And I want to store each number in an array of ints, and each full-name into an array of strings (a full name would be Joines, William B for example).
What would be the best way, because I debated whether using while (inputFile >> line) or while (getline(inputFile, line)) would be better. I don't know if it would be easier to read them one word at a time or read them one line at a time. My main problem will be splitting the 97Joines, William B. to 97 and Joines, William B. which I don't understand how to do in C++.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
int counter = 0;
int scores[40];
string names[10];
string filename, line;
ifstream inputFile;
cout << "Please enter the location of the file:\n";
cin >> filename;
inputFile.open(filename);
while (inputFile >> line) {
// if line is numeric values only, do scores[counter] = line;
// if it is alphabet characters only, do names[counter] = line;
//if it is both, find a way to split it // <----- need help figuring out how to do this!
}
inputFile.close();
}
You need to #include <cstdlib> for strtol I am sure there are better ways to do this but this is the only way I know and this is only for 97joines, and 85Henry,
string word; // to get joines,
string str; // for 97
string numword;
inputFile >> numword;
for(int k = 0; k < numword.length(); k++)
{
if(isdigit(numword[k]))
{
str = str + numword[k];
}
else
{
word = word + numword[k];
}
}
int num = strtol(str.c_str(), NULL, 0);
You can, given the file structure you have shown, read it like this:
int a, b, c, d;
std::string name;
for (int i = 0; i < 2; ++i)
{
// read the numbers
inputFile >> a >> b >> c >> d;
// read the name
std::getline(inputFile, name);
// do stuff with the data... we just print it now
std::cout << a << " " << b << " " << c << " " << d << " " << name << std::endl;
}
Since the numbers are space separated it is easy to just use the stream operator. Furthermore, since the name is the last part we can just use std::getline which will read the rest of the line and store it in the variable name.
You can try it here, using std::cin.

C ++ , getting error in vector , after reading text file line by line

Here's what I want to do,
While reading the text file line by line and splitting each line, I want to it to check if the ID (first one) is equal to the ID I want. If it equals then put the rest of the line into a vector except the ID.
Text file(example):
11111 Mark 100 40 30
11112 Helen 90 50 20
11113 John 20 20 80
11114 Paul 50 40 10
11115 Hank 10 10 20
Here is my code so far, but for some reason I am getting a "vector subscript out of range" error.
#include...
using namespace std;
vector <string> Grades;
void getgrades(string x) {
string gtemp;
ifstream myfile;
myfile.open("Test.txt");
while (getline(myfile, gtemp)) {
stringstream ss(gtemp);
string ToBe;
while (getline(ss, ToBe, ' ')) {
Grades.push_back(ToBe);
}
if (Grades[0] != x) {
Grades.clear();
}
else {
Grades.erase(Grades.begin());
}
}
}
int main() {
string x;
cout << "Enter the ID: ";
cin >> x;
getgrades(x);
cout << "Name:" << Grades[0] << endl;
cout << "Grades: " << Grades[1] << " " << Grades[2] << " "<< Grades[3] <<endl;
return 0;
}
p.s: I am using VS2015.
When you have found the correct line, you don't exit the outer while.
So the outer while loop continues and as the next line will not match the ID, your vector will get cleared. So you will necessarily be out of boudns when you try to access any elements.
To correct just complete your code as follows:
...
else {
Grades.erase(Grades.begin());
break; //<============ exit the outer while
}
One suggestion though: you can never be sure that the user enters a valid ID. You should in any case verify how many elements you have in the vector before trying to access them (as s.o. suggested in the comments).
Your logic is wrong.
F.e. you entered ID = 11111, then after first 'while (getline(myfile, gtemp))' loop you will have this in your 'Grades' vector:
Grades[0] = Mark
Grades[1] = 100
Grades[2] = 40
Grades[3] = 30
after this the next 'while (getline(myfile, gtemp))' will clear your Grades vector, because Grades[0] = Mark, and it's not equal to x anymore
You keep reading after finding the id, and clear the vector on the next id, leaving it empty.
You can break immediately when you've found x and gathered its grades.
You also don't need to collect grades for everyone and clear them, you can skip the lines you're not interested in (and globals are bad, mmkay?):
vector<string> getgrades(string x) {
vector<string> grades;
string line;
ifstream myfile("Test.txt");
while (getline(myfile, line)) {
stringstream ss(line);
string id;
if (ss >> id && id == x)
{
string grade;
while (ss >> grade) {
grades.push_back(grade);
}
break;
}
}
return grades;
}
You should return after erase, otherwise you will get garbage value.

Why is the C++ StringStream skipping the first number from an input file, but showing the rest?

Okay, so I have an input file input.txtthat contains a CSV sequence: 1,1,1,2,2,3,3,4,4
and I am trying to separate it at the commas using a stringstream; however I'm getting a little problem here. For some reason the first number from the sequence is not even getting read by the stream. To show this, I created a some debugging code to see what is happening and I found out that the first number is being stored inside csvLine and every other number is being read and coverted just fine. I don't understand why just the first number is being omitted. Below is an example pic showing exactly what I mean. num should have the same exact values and Line, but it's not. It has all the values except the first one, which is being stored inside csvLine. Why is this happening?!
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main(int argc, const char * argv[]) {
ifstream file;
string line;
string csvLine; //comma seperated value line
int num = 0;
file.open(argv[1]);
if(file.is_open()) {
while(getline(file, line)) { //get the whole line and use string stream to break at commas
cout << "\nLine: " << line << endl;
//using stringstream to seperate at commas
stringstream ss(line);
while(getline(ss, csvLine, ',')) {
cout << "csvLine: " << csvLine << " " << endl;
//using stringstream to convert to int
ss >> num;
cout << "num: " << num << " " << endl;
}
}
}
return 0;
}
The problem arises since you're using getline and then extracting integer from your stringstream
You should only use getline
while(getline(ss, csvLine, ','))
{
cout << "csvLine: " << csvLine << " " << endl;
num = std::stoi( csvLine ) ;
}
When you read getline(ss, csvLine, ',') the first time it reads the number followed by the the ','. For the next numbers it just reads the comma as the number was already extracted using ss >> num. That is, the simplest fix is to only read everything up to and including the comma after the loop was executed. Since the value of string extracting the comma isn't used it makes sense to use ignore() instead of std::getline():
for (; ss >> num; ss.ignore(std::numeric_limits<std::streamsize>::max(), ',')) {
// do something with the number
}
Restructuring the loop this way has the added benefit that it is checked whether reading the number was successful.