Read table of numbers into arrays when number of rows and columns determined at runtime

血红的双手。 提交于 2019-12-06 12:20:29

问题


I would like to ask you about data input. I have a text file in the following format:

7 2

X Y

1 0
2 0.048922
3 0.0978829
4 0.146908
5 0.196019
6 0.245239
7 0.294584

The first line contains the number of rows and columns to be read in. The second line are headers. From the third line onwards it's only data. I would like to read my data into a 2D array (mat[][]) and the headers into an array of strings (title[]), which could be easily referenced later. I came this far writing the script. It can read the array numbers into the array, but not a 2D one. I was trying to declare a pointer for the matrix which is passed to the function but I couldn't do it. I also tried getline() but I do not know how to separate the headers \t delimited into separate strings.

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
using namespace std;

void readFile(char[]);

int main(){

    char fileName[] = "results.txt";

    readFile(fileName);
    return 0;
}


// Read file to matrix
void readFile(char fileName[]){

    int m, n;

    // Create streamobject
    ifstream infile;
    infile.open(fileName);

    // Exit if file opening failed
    if (!infile.is_open()){
        cerr<<"Opening failed"<<endl;
        exit(1);
    }

    // Get size of the matrix
    infile >> m >> n;

    // Pre-allocate memory
    string title;
    float *mat=new float[m*n];

    // Read title

    // Start reading data
    while (!infile.eof()){
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                infile >> mat[i*n+j];
            }
        }
    }

    infile.close();
}

Could anyone help me out?


Thank you for the help so far. I will have a look at applying vectors this weekend, but I have to read up on it. I have quickly changed my script so now it does what I wanted: return a pointer to an array "mat" with the values. I have a function called 'showMatrix', which prints it to the screen. If I call showMatrix within the function 'readFile' it works fine. If on the other hand I call it outside from the main script then it returns completely wrong values.

I have a feeling there is something wrong here. Could you please help to point it out?

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
using namespace std;

void readFile(char[],float *mat,int &m,int &n);
void showMatrix(float *mat,int m,int n);


/*******************************************************************
 Script
 *******************************************************************/
int main(){

    char fileName[] = "results.txt";
    int m, n;
    float *mat;

    // Read data from file
    readFile(fileName,mat,m,n);
    showMatrix(mat,m,n);

    return 0;
}

// Read file to matrix
void readFile(char fileName[],float *mat,int &m,int &n){


    // Create streamobject
    ifstream infile;
    infile.open(fileName);

    // Exit if file opening failed
    if (!infile.is_open()){
        cerr<<"Opening failed"<<endl;
        exit(1);
    }

    // Get size of the matrix
    infile >> m >> n;

    // Pre-allocate memory
    mat=new float[m*n];

    // Read title
    std::string X;
    std::string Y;
    infile >> X >> Y;

    // Reading data
    while (!infile.eof()){
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                infile >> mat[i*n+j];
            }
        }
    }
//    showMatrix(mat,m,n);
    infile.close();
}

// Print matrix to screen
void showMatrix(float *x,int m, int n){
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            cout << x[i*n+j] << "\t";
        }
        cout << endl;
    }
}

回答1:


Note doing this:

while (!infile.eof()){

Is nearly always wrong. If the file reading fails for any other reason than eof then you enter an infinite loop.

Also the way you code is organized this will also mean that you try and initialize your data twice (though it will fail on the second pass an not do anything (apart from re-do the loop)) as the eof flag is not set until you read past the EOF and since you know how much data to read your first pass will not read past the EOF, you will read all the way up-to (but not past).

Reading into a 1D array

int main()
{
    std::ifstream file("plop");

    int n;
    int m;
    std::string ColHeadX;
    std::string ColHeadY;
    // You forgot to read the Col Header out.
    // Just read them into strings.
    file >> n >> m >> ColHeadX >> ColHeadY;

    // Don't do manual memory management.
    // Use a vector it will do the work for you.
    std::vector<double>   data(n*m); // initialized with (n*m) elemensts

    // Always put the read in the loop test
    //      This bit:  file >> data[loop]
    // If this read fails you want the loop to exit immediately.
    // By putting the read here the result of the read will be
    // tested to see if it worked.
    for(int loop=0;loop < (n*m) && (file >> data[loop]); ++loop) { /*Empty*/}
}

Reading into a 2D array is nearly as simple:

int main()
{
    std::ifstream file("plop");

    int n;
    int m;
    std::string ColHeadX;
    std::string ColHeadY;
    // You forgot to read the Col Header out.
    // Just read them into strings.
    file >> n >> m >> ColHeadX >> ColHeadY;

    // Don't do manual memory management.
    // A vector of vectors gives you a 2D array.
    // The initialize(r) is slightly more complex but given the example above
    // I think you should be able to see the outer vector is initialized with
    // n copies of a vector with m elements. 
    std::vector<std::vector<double> >   data(n,std::vector<double>(m));


    // Again I would advise putting the read in the loop condition
    // The easiest way here is then to calculate the x/y coordinates in the body as you go.
    for(int loop=0, x=0, y=0;loop < (n*m) && (file >> data[x][y]);)
    {
       ++loop
       x = loop % n;
       y = loop / n;
    }

}



回答2:


To allocate the two-dimensional array inside your function, use:

float **mat = new float*[m];

for(int i=0; i<m; i++){
    mat[i] = new float[n];
}

Then you can change infile >> mat[i*n+j]; to:

infile >> mat[i][j];

Finally, make sure you implement reading the title; right now it's empty:

//Read title



回答3:


In C and C++, pointers (C and C++) and references (C++ only) to arrays are declared with a somewhat obscure syntax, like this:

void fp(float (*array)[10]);
void fr(float (&array)[10]);
void f2d(float (&array)[10][10]);


void main()
{
    float a[10];
    fp(&a);
    fr(a);

    float b[10][10];
    f2d(b);
}

You cannot declare a pointer or reference to an array that is not of compile-time constant size. To pass variable-sized data you need to use a pointer to the first element in the array and pass in the size of the data, so your code can safely use the array with out running out of bounds, like this:

void f(float* data, int length);

However, this places a burden on the programmer to carefully write safe and correct code. Since you're using C++ and not C, using std::vector is highly recommended! vector is a sequential container object that behaves just like an array when you need to index into it. It is dynamically resizable, and will handle the details of allocation and deallocation for you.



来源:https://stackoverflow.com/questions/8918084/read-table-of-numbers-into-arrays-when-number-of-rows-and-columns-determined-at

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!