0

I have a file, which looks like this:

0 0 1 4 6 17 43 20 21 7 0 1 6
0 2 1 9 14 16 79 283 35
1 0 1 2 2 0 0 0 0 0 0 1 4 0 3 5 7 9 11 4 1 30
1 1 0 1 5

And more lines which are of different length. I would like to read first line into an array, do something with this array and then read next line into array again (so a loop) and work with this array too. In summary - at one time I would like to have an array of values from one line.

Is it possible to do it with array, not vector?

Code like this works for me, but I have a problem with adding reading next line here

int size = 13;
int arr[SIZE];

string inFileName = "file.txt";
ifstream inFile;
inFile.open(inFileName.c_str());

if (inFile.is_open())  
{
    for (int i = 0; i < size; i++) 
    {
        inFile>>arr[i];
        cout<<arr[i] << " ";
    }
    inFile.close(); 
}

size is not a problem for me, I can read it from another file, for each line.

Thanks in advance!

beechy
  • 101
  • 8
  • If you could know sizes of every line, you can find the max number of sizes, then new an array of that size. – ABacker Nov 25 '21 at 18:25
  • 1
    If you know some thing like "there are at most N numbers on each line", then you can reuse an array of size N (and store the number of elements on the current line in some other variable). However, if there is no such upper-bound, then arrays won't help you. – Fullfungo Nov 25 '21 at 18:28
  • Use two arrays. Array one contains all of the value in one 1D blob. Array two contains the start location of each row. The start of the next row implies the end of the previous row, so you need one extra value in array to to store the end of the array. – user4581301 Nov 25 '21 at 18:34
  • Indeed, thank you! But how can I 1) read line into array and then 2) read next line into array? Reading line after line into array is my problem here. – beechy Nov 25 '21 at 18:34
  • To read a stream line by line I usually start with something like [Option 2 in this answer](https://stackoverflow.com/a/7868998/4581301). Obviously you need something more complicated than `iss >> a >> b`, like a loop that keeps reading until it runs out of values to read `while (iss >> val) { store val }`. Definitely steal the structure from Anoop's answer below. – user4581301 Nov 25 '21 at 18:51

2 Answers2

1

Is it possible to do it with array, not vector?

Yes it is possible to do it with array but for that you must know the the exact number of elements in each line and also how many lines are there in the file. A better alternative would be to use std::vector<>.

From your description it seems that you want to process the array/vector after reading the file. For this you can use a 2D std::vector as shown below.

Also your program has two variables one named size and other named SIZE. For specifying the size of the array you have used SIZE instead of size. But from your code we can't infer the type of SIZE but only the type of size. In case you meant to use a single size variable instead of 2 different ones with one in capital and other in small letters, your program will not be a standard C++ program because in C++ the size of any array must be a compile time constant. So take for instance:

int SIZE = 13;
int arr[SIZE];//INCORRECT because variable SIZE is not a constant expression

The correct way to write the above would be:

const int SIZE = 13;
int arr[SIZE];//CORRECT

But if want to use array you must know how many rows(lines) and columns(elements) will be there in the input file, which is not suitable.

You can use a std::vector for storing information(like integers values in this case) in 2D manner. After reading all the values from the file you can process the vector according to your needs. The advantage of using std::vector is that you don't have to know the number of rows and columns beforehand in your input file. So you don't have to allocate memory beforehand for rows and columns. You can add the values dynamically. The below program read data(int values) from input.txt and store those in a 2D vector.

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include<fstream>
int main() {
    std::string line;
    int word;

    
    std::ifstream inFile("input.txt");
    
    //create/use a std::vector instead of builit in array 
    std::vector<std::vector<int>> vec;
    
    if(inFile)
    {
        while(getline(inFile, line, '\n'))        
        {
            //create a temporary vector that will contain all the columns
            std::vector<int> tempVec;
            
            
            std::istringstream ss(line);
            
            //read word by word(or int by int) 
            while(ss >> word)
            {
                //std::cout<<"word:"<<word<<std::endl;
                //add the word to the temporary vector 
                tempVec.push_back(word);
            
            }      
            
            //now all the words from the current line has been added to the temporary vector 
            vec.emplace_back(tempVec);
        }    
    }
    
    else 
    {
        std::cout<<"file cannot be opened"<<std::endl;
    }
    
    inFile.close();
    //now you can do the whatever processing you want on the vector

    //lets check out the elements of the 2D vector so the we can confirm if it contains all the right elements(rows and columns)
    for(std::vector<int> &newvec: vec)
    {
        for(const int &elem: newvec)
        {
            std::cout<<elem<<" ";
        }
        std::cout<<std::endl;
    }
    
    
    
    return 0;
}

The output of the above program can be seen here. The input file through which int values are read is also given at the above mentioned link.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • `int arr[SIZE];//INCORRECT because variable SIZE is not a constant expression` How do you know this? `SIZE` isn't declared anywhere in the given code. – user4581301 Nov 25 '21 at 18:40
  • 1
    While using `vector` is the best way to do this, the asker has specifically asked for how to do this without `vector`. And the answer to that is "Write your own `vector`." – user4581301 Nov 25 '21 at 18:41
  • @user4581301 Yes I mistyped `int size = 13;` while i actually want to type `int SIZE = 13;`. Also i **assume** by `size` and `SIZE` the OP meant the same thing and he/she also wanted to write `int SIZE = 13;` instead of `int size = 13;` in his/her code. But that is just an assumption and must be verified by the OP. Next, i provided/showed a possible way of doing it. The OP is free to use it or discard it. Note that with possible usage i also gave some explanation about why array(built in) is not suitable for this purpose. – Jason Nov 25 '21 at 18:46
  • Using getline and then and then a stringstream is not the most efficient way to do things as you read in the line and then go through it again (in your programs memory, not in the file) when creating the vector. Unfortunately doing it in the most efficient way probably means creating a custom iterator. – floomby Nov 25 '21 at 18:58
  • Agreed. The `stringstream` approach is not runtime efficient, but it's really simple to write, hard to screw up, and easy on the maintainers. Start with stupidly easy and stay there unless profiling shows it's a significant problem. – user4581301 Nov 25 '21 at 20:54
0

TLDR:

You could, but you have to know at least a maximum number of elements in each line, and then you create a buffer that would potentially have unused space in it.

PS:

You then could put it inside a vector at once if you fear the repeated emplace_back function.

But you shouldn't fear emplace_back function that much, since std::vector does a smart thing:

It at some point decides, that it will reserve twice as much space it already uses. This approach will minimize the number of reallocations so that on avarage the time it spends doing emplace_back is O(1) (constant speed)

Disclaimer:

There are cases you can screw up the efficiency of a vector (probably not with ints tho), but in most times it can be mitigated. Many cpp conference talks and many blog posts and so on were made on that topic.