Reading a particular input from the txt file - c++

this is from the google practice problem, https://code.google.com/codejam/contest/32014/dashboard#s=p1, and
I'm just having a little bit of problem with reading the input.
The input has the form
3
jam google foo code bar
20 15 40 30 60
foo bar
3 2
code jam
3 2
where the first integer is the number of cases, and each case consists of two lines. The first line contains the list of products, space separated, and second line contains your initial guesses for each product in the list, respectively.
For each case, I want to get the first line as a vector of strings, and second line as a
vector of integers, and the code I came up with is the following: (made modifications using the comment)
ifstream inFile;
inFile.open("B-small-practice.in");
ofstream outFile;
outFile.open("B-small-practice.out");
inFile >> numCase;
inFile.ignore();
for (i = 0; i < numCase; i++) {
vector<string> v1;
vector<int> v2;
getline(inFile, a);
getline(inFile, b);
stringstream aa(a);
stringstream bb(b);
j = 0;
while (aa >> c) {
v1.push_back(c);
if (aa.peek() == ' ')
aa.ignore();
j++;
}
while (bb >> d) {
v2.push_back(d);
if (bb.peek() == ' ')
bb.ignore();
}
}
(all the variables are defined)
However, this code terminates after throwing an error "out of range," and I'm not sure because I thought my code was within the range.
Is there a way of fixing this? Or is there something wrong with my code?

Related

How to use file.eof() while reading in integers from a file?

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.

Resolving anomalous string to float operation on a vector?

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.

Seg Fault Using Copy() and Istream_Iterator to parse string into vector members

I have some input that looks like this:
CH4
9_site_nonpolar
66
#TEMP #PRES #V #DENSITY
115.0 00.1 10186012.74173 0.00017
145.0 00.1 12709964.99224 0.00014
175.0 00.1 15482213.03440 0.00011
205.0 00.1 18140114.97385 0.00010
...
The number 66 refers to the number of data lines (i.e. those under the #TEMP... line.)
I am trying to take this input, ignore the first two lines, store the third line, ignore the fourth line, and then parse the rest of the lines into a vector of strings. The code below is my attempt, but it segfaults when I attempt to access members of the vector this_line.
I am relatively new to C++ and have been having a difficult time debugging this. I think the problem is with the copy() lines (which I got here;) the two cout statements print to stdout and then the program fails.
The vector all_runs in the code has type vector<vector<run>> where a run is just a struct I am using to hold these variables. The outer vector represents each of the files the program takes as input, while the inner vector is intended to hold information from the data lines (e.g. 115.0 00.1 10186012.74173 0.00017.)
string file_name,
line;
for(int i = 1;i < argc;i++)
{
int j = 0;
file_name = argv[i];
ifstream input(file_name);
input.ignore();
input.ignore();
int num_runs = atof(line.c_str());
input.ignore();
if(input.is_open())
{
while(getline(input,line))
{
vector<string> this_line;
istringstream iss(line);
//copy the numbers of interest from the line into the vector this_line
cout << "hello"<< endl;
copy(
istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(this_line)
);
cout << "hi again" << endl;
auto &ref = (all_runs[i-1])[j];//make current run a ref to clean up the code a bit
ref.temperature = atof(this_line[0].c_str());
ref.pressure_atm = atof(this_line[1].c_str());
ref.simulation_V = atof(this_line[2].c_str());
ref.density = atof(this_line[3].c_str());
if(j == (num_runs - 1))
break;
else
j++;
}
}
input.close();
}
Thank you for your time and any help you may be able to offer!

Read text file by column and show all array of column values

I am trying to do file read by column. Main function is that my file should be show one of columns all values.
I am trying to do it with vectors.
void search(){
const int COLUMNS = 4;
vector< vector <int> > data;
string filename = "bla.txt";
ifstream ifile(filename.c_str());
if (ifile.is_open()) {
int num;
vector <int> numbers_in_line;
while (ifile >> num) {
numbers_in_line.push_back(num);
if (numbers_in_line.size() == COLUMNS) {
data.push_back(numbers_in_line);
numbers_in_line.clear();
}
}
}
else {
cerr << "There was an error opening the input file!\n";
exit(1);
}
//now get the column from the 2d vector:
vector <int> column;
int col = 2;//example: the 2nd column
for (int i = 0; i < data.size(); ++i) {
column.push_back(data[i][col - 1]);
cout << column[i] << endl;
}
ifile.close();
}
my file looks like:
John 1990 1.90 1
Peter 1980 1.88 0
...
This code compiles, but I am not getting any value shown in console. When I try to debug last line it wont get cached, so I guess they do nothing?
while (ifile >> num) {
The loop is never entered because num is an int and the first element of the input line is John, which cannot be interpreted as an int, so ifile is set to an error state and the loop condition is immediately false.
The clean fix is to first read the entire line with std::getline and then tokenise the resulting std::string, for example with an std::istringstream.
Individual std::string tokens resulting from that tokenisation can then be converted to appropriate types with functions like std::stoi.
Do step by step and make sure each step is correct.
Read each line, then print out to make sure you are doing it correctly.
You need to split each line. After this step, you will have John, 1990 etc as strings. My favorite split method
Now convert 2-4th columns into integers.
There are good solutions for each step that you can easily find.

new >> how would i read a file that has 3 columns and each column contains 100 numbers into an array?

int exam1[100];// array that can hold 100 numbers for 1st column
int exam2[100];// array that can hold 100 numbers for 2nd column
int exam3[100];// array that can hold 100 numbers for 3rd column
int main()
{
ifstream infile;
int num;
infile.open("example.txt");// file containing numbers in 3 columns
if(infile.fail()) // checks to see if file opended
{
cout << "error" << endl;
}
while(!infile.eof()) // reads file to end of line
{
for(i=0;i<100;i++); // array numbers less than 100
{
while(infile >> [exam]); // while reading get 1st array or element
???// how will i go read the next number
infile >> num;
}
}
infile.close();
}
int exam1[100];// array that can hold 100 numbers for 1st column
int exam2[100];// array that can hold 100 numbers for 2nd column
int exam3[100];// array that can hold 100 numbers for 3rd column
int main() // int main NOT void main
{
ifstream infile;
int num = 0; // num must start at 0
infile.open("example.txt");// file containing numbers in 3 columns
if(infile.fail()) // checks to see if file opended
{
cout << "error" << endl;
return 1; // no point continuing if the file didn't open...
}
while(!infile.eof()) // reads file to end of *file*, not line
{
infile >> exam1[num]; // read first column number
infile >> exam2[num]; // read second column number
infile >> exam3[num]; // read third column number
++num; // go to the next number
// you can also do it on the same line like this:
// infile >> exam1[num] >> exam2[num] >> exam3[num]; ++num;
}
infile.close();
return 0; // everything went right.
}
I assume you always have 3 numbers per line. If you know the exact number of lines, replace the while with a for from 0 to the number of lines.
Rule # 1 about reading data from a file: don't trust the contents of the file. You never know with absolute certainty what is in the file until you've read it
That said, one correct way to read lines of data from a file, where each line is composed of multiple whitespace-delimited fields would be to use a combination of getline and stringstream:
std::string line;
while (std::getline(infile, line))
{
std::stringstream ss(line);
int a, b, c;
if (ss >> a >> b >> c)
{
// Add a, b, and c to their respective arrays
}
}
In English, we get each line from the file stream using getline, then parse the line into three integers using a stringstream. This allows us to be certain that each line is formatted correctly.
We check to ensure the extraction of the integers succeeded before we add them to the arrays to ensure that the arrays always have only valid data.
There is other error handling that might be desirable:
In the example, if extraction of the integers from the line fails, we just ignore that line; it could be a good idea to add logic to abort the process or report an error.
After we get three integers, we ignore the rest of the line; it might be a good idea to add checks to ensure that there is no more data on the line after the required integers, depending on how strict the file's formatting needs to be.
After we finish reading the file, we should test to be sure eof() is set and not fail() or bad(); if one of those two flags is set, some error occurred when reading the file.