I have a text file of number called InputFile.txt. The file looks like this:
10.5 73.5 109.5 87 45 108 66 117 34.5 13.5 60 97.5 138 63 130.5 4.5 40.5 43.5 60 18
I want to read this file and insert each individual number as an element of the array arr. I know what I have does not attempt to add the elements to the array but I am not sure how I would even approach this. Any advice would be very appreciated.
int main(int argc, char* argv[]) {
float array[20];
ifstream file("InputFile.txt");
}
CodePudding user response:
Here is one way of doing this, although a little bit advanced.
The following uses std::copy
using std::istream_iterator<float>
. Note the usage of vector for flexibility:
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
int main(int argc, char* argv[])
{
std::vector<float> values;
std::ifstream file("InputFile.txt");
// read the input
std::copy(std::istream_iterator<float>(file),
std::istream_iterator<float>(), std::back_inserter(values));
// print out the results of the input read
for (auto f : values)
std::cout << f << "\n";
}
CodePudding user response:
If you need to use your array of floats, you can use a less advanced approach to read the line into a string, create a stringstream from the string and then extract the floats from the stringstream.
Using a POA (plain-old-array), the responsibility is on you to ensure you do not write beyond the bounds of the array. To ensure you don't try and write more elements to the array than it can hold, simply keep a counter which you can use to both index the array and validate against the maximum number of elements the array can hold.
A short example would be:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#define MAXF 20 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
std::ifstream file;
std::string str{};
float array[MAXF] = {0};
if (argc < 1) { /* validate filename provided as argument */
std::cout << "usage: ./prog file with space separated floats\n";
return 1;
}
file.open (argv[1]); /* open file */
if (!file.is_open()) { /* validate file is open for reading */
std::cerr << "error: file open failed.\n";
return 1;
}
while (getline (file, str)) { /* read each line */
std::istringstream iss (str); /* create stringstream */
float f;
size_t nfloats = 0; /* count of no. of floats */
while (nfloats < MAXF && iss >> f) { /* protect bound, get float */
array[nfloats ] = f; /* add float to array */
}
for (size_t i = 0; i < nfloats; i ) { /* output floats from line */
std::cout << array[i] << '\n';
}
}
}
(note: this will read as many lines of floats are are contained in the file, re-using the same array to hold the floats from each line and then printing the floats before reading the next line)
Alternative 2
You can also read the string and manually separate the substrings using alternating calls to .find_first_not_of()
to skip whitespace and save the position of the start of a float value, and then use .find_first_of()
to find and save the position of the next whitespace after the value. (you will need to check against npos
to identify the last value). You would then call stof()
for the conversion and handle any exception on a failed conversion.
Which all emphasizes why using the niceties C provides with the more "advanced method" shown by @PaulMcKenzie can cut down on your code size as well as eliminating the manual checks, indexing and bounds protection you must do.
CodePudding user response:
I have given 2 solutions to this problem. The below program reads double
from input.txt and if there is some invalid entry in the file lets say there is some string
then it will skip that string and read the next value and only if that value is valid(double
) it will put it into the array as you desire.
Solution 1: Using built in arrays
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main()
{
std::string line;
std::ifstream inFile("input.txt");
//in case of using array, size must be fixed and predetermined
double arr[20] = {0.0}; //you can choose size according to your needs
if(inFile)
{
double i = 0;//this variable will be used to add element into the array
int count = 0;
while(getline(inFile, line, '\n'))
{
std::istringstream s(line);
//take input(from s to i) and then checks stream's eof flag status
while(s >> i || !s.eof()) {
//check if either failbit or badbit is set
if(s.fail())
{
//clear the error state to allow further operations on s
s.clear();
std::string temp;
s >> temp;
continue;
}
else
{
arr[count] = i;
count;
//break out of the loop so that we don't go out of bounds
if(count >= 20)
{
break;
}
}
}
}
}
else
{
std::cout<<"file could not be read"<<std::endl;
}
inFile.close();
for(double i: arr)
{
std::cout<<"elem: "<<i<<std::endl;
}
return 0;
}
The output of solution 1 can be checked here.
Solution 2: Using std::vector
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
int main()
{
std::string line;;
std::ifstream inFile("input.txt");
std::vector<double> vec;
if(inFile)
{
double i = 0;//this variable will be used to add element into the vector
while(getline(inFile, line, '\n'))
{
std::istringstream s(line);
//take input(from s to i) and then checks stream's eof flag status
while(s >> i || !s.eof()) {
if(s.fail())
{
//clear the error state to allow further operations on s
s.clear();
std::string temp;
s >> temp;
continue;
}
else
{
vec.push_back(i);
}
}
}
}
else
{
std::cout<<"file could not be read"<<std::endl;
}
inFile.close();
for(double i: vec)
{
std::cout<<"elem: "<<i<<std::endl;
}
return 0;
}
The output of solution 2 can be seen here.
Both of these versions work even if there is an invalid input(like a string) in the input.txt file. As you can see here the input.txt file has strings in between numbers. The program just skips those invalid input and read the next thing. And if that next thing is double, it puts that thing/value into the vector/array.
Important Note
The advantage of using std::vector
over built in array(in this case) is that you don't have know the size of the vector beforehand. So it is preferable because you don't know how many integers are there in the input.txt file. std::vector
can handle this correctly/dynamically. But when using built in arrays you must know/specify the size of the array beforehand. This in turn means you must know beforehand how many integers are there in the input.txt, which is not practical.