Home > Blockchain >  How do I read in a text file separated by spaces into an array in c ?
How do I read in a text file separated by spaces into an array in c ?

Time:10-21

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.

  •  Tags:  
  • c
  • Related