I have a file that goes like this:
98
287 2352
987 4313 3253
235 34325 432 123
Basically I want to reproduce this file. I am trying to import a line at a time, extract the numbers, and push them into vectors. Each vector is pushed into a larger vector.
int main(int argc, char* argv[])
{
int sum = 0, one = 0, two = 1;
std::string line, number;
std::vector<int> vec;
std::vector<std::vector<int>> bigvec;
auto k = vec.begin();
std::ifstream in(argv[1]);
while(in >> line) {
std::istringstream is(line);
while(is >> number) {
vec.push_back(stoi(number));
}
bigvec.push_back(vec);
while(!vec.empty()) {
vec.pop_back();
}
std::cout << std::endl;
}
return 0;
}
My code though, when I print the result, seems to put each number in it's own vector instead of reproducing the file.
So my output is
98
287
2352
etc.
It seems that the line
while(is >> number) {
vec.push_back(stoi(number));
}
pushes one number and then exits the loop.
Where am I going wrong?
while(in >> line) reads next word from the input. Use getline(in, line) if you want to read a whole line.
There are multiple optimizations that you can add to your code. For instance instead of using stoi on the string you've read you can read an integer from the input stream. Also instead of popping the vector's elements one by one you can simply call clear.
Your problem lies here:
while(in >> line)
C++ by defult reads until it encounters interval or new line. In your case it encounters interval before new line. If you want to take the whole line take:
getline(cin, line);
Related
I am writing a program that reads in data from a file. The file contains lines of integers, such as
5 6 2 8 6 7
2 5 3
4 0 9 1 3
The first integer of each line corresponds to how many numbers there are in that line. My goal is to read in each line, store the numbers in a vector, and do some operation on them. Here is what I have done:
int main(){
vector<int> vec;
int amount;
int nums;
ifstream file ("file.txt");
while(!(file.eof())){
file >> amount;
cout << amount << endl;
for (int i = 0; i < amount; i++){
file >> nums;
vec.push_back(nums);
}
printArray(vec);
bubbleSort(vec);
vec.clear();
}
return 0;
}
Unfortunately, the last line always gets read twice. I looked online and saw that the eof() function should not be used to maintain loops. What else could I use in this situation?
Thanks.
operator>> sets the stream's eofbit flag if it tries to read past EOF. You can use that condition to break your loops. But you have to actually perform a read operation BEFORE you can evaluate eof(). See Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong? for more details on that.
Since you are dealing with line-based text, you can use std::getline() to read each line first, and then you can use std::istringstream to parse each line, eg:
int main()
{
vector<int> vec;
ifstream file ("file.txt");
string line;
while (getline(file, line)) {
istringstream iss(line);
int amount, nums;
iss >> amount;
cout << amount << endl;
for (int i = 0; (i < amount) && (iss >> nums); ++i){
vec.push_back(nums);
}
printArray(vec);
bubbleSort(vec);
vec.clear();
}
return 0;
}
Alternatively, you can simply take advantage of the fact that operator>> skips whitespace, including line breaks, eg:
int main()
{
vector<int> vec;
int amount, nums;
ifstream file ("file.txt");
while (file >> amount) {
cout << amount << endl;
for (int i = 0; (i < amount) && (file >> nums); ++i){
vec.push_back(nums);
}
printArray(vec);
bubbleSort(vec);
vec.clear();
}
return 0;
}
Although, this approach would be a little less resilient to errors in the input data, compared to the std:getline() approach. If the actual amount of numbers in a given line does not match the specified amount at the beginning of the line, this approach will get its reading of the file out of sync. Worse, if a given line contains any non-integer values, this approach will fail to read any subsequent data at all.
In the std:getline() approach, if a given line is malformed, the code will simply move on to the next line and continue on like nothing bad happened.
I have a code that takes a .csv file and reads the values and prints it out.
The contents of the .csv file are -
55
100
200
500
500
150
I am using the stof method to cast strings into floats like this -
for (unsigned int i = 0; i < DataStore.size(); i++)
cout << stof(DataStore[i]) << endl;
but in this case I only get the output as
55
instead of -
55
100
200
500
500
150
I am new to C++ so I'm pretty sure there's something trivial that I'm missing - but unable to figure it out.
Minimal Reproducible Code -
string line;
vector<string> DataStore;
{
ifstream file("test.csv");
while (getline(file, line, ','))
{
DataStore.push_back(line);
getline(file, line);
}
}
for (unsigned int i = 0; i < DataStore.size(); i++)
cout << stof(DataStore[i]) << endl;
Contents of test.csv are as follows -
55
100
200
500
500
150
while (getline(file, line, ','))
This reads from the file until the it encounters a comma. There are no commas in your file, so the whole file will be read into line, this line is inserted into DataStore and the loop does not iterate any further, because there is nothing left to be read for the next getline.
Therefore DataStore.size() will be one and in the single iteration the whole file's contents are passed to stof, which will form the parsed number from the beginning until it encounters something not part of a valid number, here the newline. The result will be 55. This is printed and the loop exits.
You seem to want to read line-by-line. This is done by getline without third argument (or third argument equal '\n'). Additionally there is a stray getline, the purpose of which I don't know.
string line;
vector<string> DataStore;
{
ifstream file("test.csv");
while (getline(file, line))
{
DataStore.push_back(line);
}
}
for (unsigned int i = 0; i < DataStore.size(); i++)
cout << stof(DataStore[i]) << endl;
Note that you can directly read the numbers from the file into a std::vector:
ifstream file("test.csv");
vector DataStore(istream_iterator<double>(file), {});
This requires #include<iterator> and before C++17 the vector type needs to be specified: vector<double>
It reads white-space separated numbers until the end of file.
I'm having a bit of a problem with extracting data from a simple .txt file with the getline command.
The txt file is very simple: a column of 400 numbers. I use a vector to store them with the following code:
int i = 0;
string line;
vector <double> vec;
while (getline(input, line))
{
vec.push_back(i);
N++;
input >> vec[i];
i++;
}
It correctly creates a vector of 400 elements but first line of txt file is ignored (I end up with vec[0] = 2nd line of txt file instead of 1st) and 399th element is 399 instead of the 400th line of txt file.
I tried several other ways to extract this data but it was unsuccessful.
Thank you for your help!
EDIT:
I have edited the code according to some of the remarks:
vector <double> vec;
string line;
double num;
while (getline(input, line))
{
input >> num;
vec.push_back(num);
}
Unfortunately, it still skips the first line of my text file.
EDIT 2 --> SOLUTION:
Thanks to all of your remarks, I realized that I was doing something wrong when using both getline and input >> num;
Here is how the problem was solved:
double num;
vector <double> vec;
while (input >> num)
{
vec.push_back(num);
}
You can read the entire file into a vector just by passing std::istream_iterator to std::vector constructor, without loops:
std::vector<int> v{
std::istream_iterator<int>{input},
std::istream_iterator<int>{}
};
E.g.:
#include <iostream>
#include <iterator>
#include <vector>
#include <exception>
template<class T>
std::vector<T> parse_words_into_vector(std::istream& s) {
std::vector<T> result{
std::istream_iterator<T>{s},
std::istream_iterator<T>{}
};
if(!s.eof())
throw std::runtime_error("Failed to parse the entire file.");
return result;
}
int main() {
auto v = parse_words_into_vector<int>(std::cin);
std::cout << v.size() << '\n';
}
You loose the first line due to reading from the file once more - here:
while (getline(input, line))
// ^^^^^^^ Here you read the first line
{
input >> num;
// ^^^^^^^^ Here you will read the second line
You told you want a vector of doubles - like:
std::vector<double> vec;
So you should use std::stod to convert the line read by getline into a double. Like:
while (std::getline(input, line))
{
// Convert the text line (i.e. string) to a floating point number (i.e. double)
double tmp;
try
{
tmp = stod(line);
}
catch(std::invalid_argument)
{
// Illegal input
break;
}
catch(std::out_of_range)
{
// Illegal input
break;
}
vec.push_back(tmp);
}
Don't do input >> num; inside the loop.
If you really want to use input >> num; then you shall not use getline. That is - you can use either but not both.
Change your while loop like below:-
while (getline(input, line))
{
vec.push_back(line);
//N++;
//input >> vec[i];
//i++;
}
Also try with below option
do{
vec.push_back(i);
//N++;
//i++;
}while (input >> vec[i++]);
You are starting by putting 0 in vector in first iteration:
vec.push_back(i);
then after you read first line you read next string, but stream get pointer from file is already in different place, so you override this 0 and skip first value from stream. What is worse that is oddly converted to double:
input >> vec[i];
This way you will get wrong.
Try this:
while (std::getline(file, line)) {
//In c++11
vec.emplace_back(std::stod(line));
//In c++ 98, #include <stdlib.h> needed
//vec.push_back(atof(line.c_str()));
}
This assumes you will always have proper file.
I want to read in scores from a txt file. The scores are going into a struct.
struct playerScore
{
char name[32];
int score, difficulty;
float time;
};
the text file looks like this
Seth 26.255 40 7
as one line, where each item is followed by a tab. (Name\t time\t score\t difficulty\n)
When I begin to read in the text, I don't know how to tell the program when to stop. The scores file could be any number of lines or score entries. This is what I have attempted.
hs.open("scores.txt", ios_base::in);
hs.seekg(0, hs.beg);
if (hs.is_open())
{
int currpos = 0;
while (int(hs.tellg()) != int(hs.end));
{
hs>> inScore.name;
hs >> inScore.time;
hs >> inScore.score;
hs >> inScore.difficulty;
hs.ignore(INT_MAX, '\n');
AllScores.push_back(inScore);
currpos = (int)hs.tellg();
}
}
I'm trying to make a loop that will read in a line of code into a temp struct for the data, then push that struct into a vector of structs. Then update the currpos variable with the current location of the input pointer. However, the loop just gets stuck on the condition and freezes.
There are a multitude of ways to do this, but the following is likely what you're looking for. Declare a free-operator for extracting a single-line definition of a player-score:
std::istream& operator >>(std::istream& inf, playerScore& ps)
{
// read a single line.
std::string line;
if (std::getline(inf, line))
{
// use a string stream to parse line by line.
std::istringstream iss(line);
if (!(iss.getline(ps.name, sizeof(ps.name)/sizeof(*ps.name), '\t') &&
(iss >> ps.time >> ps.score >> ps.difficulty)))
{
// fails to parse a full record. set the top-stream fail-bit.
inf.setstate(std::ios::failbit);
}
}
return inf;
}
With that, your read code can now do this:
std::istream_iterator<playerScore> hs_it(hs), hs_eof;
std::vector<playerScore> scores(hs_it, hs_eof);
I dont think that you can just >> from your file. Do you think it will take everything till \t? :)
You can try to take for example token with strtok()
I guess it can use '\t' to split string and take for each variable via this function needed part of string
In case if it strtok() doesnt work that way i guess you can just copy till '\t' in sub-loop
You can do like this
playerScore s1;
fstream file;
file.open("scores.txt", ios::in | ios::out);
while(!file.eof()) //For end of while loop
{
file.read(s1, sizeof(playerScore));//read data in one structure.
AllScores.push_back(s1);
}
I have a text file that contains the following data.
The first line is this:
5 4 3 2 1
The second line is this:
1 2 3 4 5
I am trying to read data from one line at a time because my first linked-list object is going to use the data from the first line and my second linked-list object is going to use data from the second line. The best I have been able to come up with is the following function:
void polynomial::allocate_poly(std::ifstream& in, const char* file, const char* number)
{
in.open(file);
std::string str;
char b;
int m = 0;
for(int i = 0; !in.eof(); ++i)
{
in >> b;
m = b - '0';
a.insert(m);
}
There is a few problems with this approach. I have tried different binary operators in my for loop such as b == '\n' and none of them seem to trigger when b is a newline character.
Also allocating the numbers from the file this way it looks like
5 5 4 3 2 1 1 2 3 4 5 , so it seems to be copying an extra 5 somewhere, I am not sure if this is the eof bit or not.
I have also attempted to use the getline function but for some reason it seems to only copy the first integer and then dumps the rest of the file. I know certainly I am not using it correctly but all the examples I can find are for typing the file name such as cin.getline and I want to be able to pass my file name as a command line argument when running the program instead.
My question is how can I allocate the numbers on the first row up to the newline char and then pass the ifstream in variable to another object to allocate the second line? Thanks for your help.
You don't say what a is, but never mind: If you want line based parsing, you need to have getline in the outer loop. Also, never use eof, as it doesn't do what you want. Rather use the implicit conversion to bool to check if an operation succeeded.
Here's the typical gig:
#include <sstream>
#include <fstream>
#include <string>
std::string line;
std::ifstream infile("myfile.txt");
while (std::getline(infile, line)) // this does the checking!
{
std::istringstream iss(line);
char c;
while (iss >> c)
{
int value = c - '0';
// process value
}
}
However, this conversion from char to int is cumbersome and fragile. Why not read an integer directly?
int value;
while (iss >> value) { /* ... */ }
Edit: Based on your comment, here's the code to read exactly two lines:
std::string line;
int val;
if (std::getline(infile, line))
{
std::istringstream iss(line);
while (iss >> value) { /* process first line */ }
}
if (std::getline(infile, line))
{
std::istringstream iss(line);
while (iss >> value) { /* process second line */ }
}