Считать таблицу чисел в массивы, когда количество строк и столбцов определено во время выполнения - PullRequest
1 голос
/ 19 января 2012

Я хотел бы спросить вас о вводе данных.У меня есть текстовый файл в следующем формате:

7 2

XY

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

Первая строка содержит количество строк и столбцов для чтения. Вторая строка - заголовки.Начиная с третьей строки, это только данные.Я хотел бы прочитать мои данные в 2D-массив (mat [] []), а заголовки - в массив строк (title []), на которые можно было бы легко сослаться позже.Я зашел так далеко, написав сценарий.Он может считывать номера массивов в массив, но не двумерные.Я пытался объявить указатель на матрицу, которая передается функции, но я не смог этого сделать.Я также пробовал getline (), но я не знаю, как разделить заголовки \ t, разделенные на отдельные строки.

#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();
}

Может ли кто-нибудь мне помочь?


Спасибо запомощь до сих пор.Я посмотрю на применение векторов в эти выходные, но я должен прочитать об этом.Я быстро изменил свой скрипт, так что теперь он делает то, что хотел: возвращает указатель на массив «mat» со значениями.У меня есть функция под названием «showMatrix», которая выводит ее на экран.Если я вызываю showMatrix в функции 'readFile', она работает нормально.С другой стороны, если я вызываю его вне основного сценария, он возвращает совершенно неправильные значения.

У меня такое ощущение, что здесь что-то не так.Не могли бы вы помочь, чтобы указать на это?

#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;
    }
}

Ответы [ 4 ]

4 голосов
/ 19 января 2012

Обратите внимание на следующее:

while (!infile.eof()){

Почти всегда неправильно.Если чтение файла не удается по любой другой причине, кроме eof, вы вводите бесконечный цикл.

Кроме того, способ организации кода также будет означать, что вы попытаетесь инициализировать данные дважды (хотя это не удастся навторой проход и ничего не делать (кроме повторного выполнения цикла)), поскольку флаг eof не устанавливается до тех пор, пока вы не прочитаете за пределами EOF, и поскольку вы знаете, сколько данных для чтения за первый проход не будет прочитано за пределами EOF,читать все вплоть до (но не в прошлом).

Чтение в 1D массив

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*/}
}

Чтение в 2D массив почти так же просто:

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;
    }

}
0 голосов
/ 19 января 2012

В C и C ++ указатели (C и C ++) и ссылки (только на C ++) на массивы объявляются с несколько неясным синтаксисом, например:

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);
}

Вы не можете объявить указатель или ссылку на массив, который не имеет постоянного размера во время компиляции. Чтобы передавать данные переменного размера, вам нужно использовать указатель на первый элемент в массиве и передавать размер данных, чтобы ваш код мог безопасно использовать массив без исчерпания границ, например:

void f(float* data, int length);

Однако это накладывает на программиста бремя тщательного написания безопасного и правильного кода. Поскольку вы используете C ++, а не C, настоятельно рекомендуется использовать std::vector! vector - это последовательный контейнерный объект, который ведет себя так же, как массив, когда вам нужно индексировать его. Это динамически изменяемый размер, и он будет обрабатывать детали размещения и освобождения для вас.

0 голосов
/ 19 января 2012

Как сказано выше, вы не можете динамически распределять многомерный массив, потому что все, кроме одного измерения, должны быть известны во время компиляции.Хотя вы можете использовать std::vector<std::vector<float> >, лучше создать тип Matrix.Вот (очень упрощенный) пример:

class Matrix
{
public:
  Matrix (int _m, int _n) : m(_m), n(_n), t(m * n) {}
  float& operator() (int i, int j) { return t[i * n + j]; }
  int size_x () { return m; }
  int size_y () { return n; }

private:
  int m;
  int n;
  std::vector<float> t;
};

std::ostream &operator<<(std::ostream &os, Matrix mat)
{
  for (int i = 0; i < mat.size_x(); i++) {
    for (int j = 0; j < mat.size_y(); j++) {
      os << mat(i,j) << ' ';
    }
    os << '\n';
  }
  return os;
}

Конечно, вы должны использовать существующую библиотеку, такую ​​как uBLAS .

0 голосов
/ 19 января 2012

Чтобы выделить двумерный массив внутри вашей функции, используйте:

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

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

Тогда вы можете изменить infile >> mat[i*n+j]; на:

infile >> mat[i][j];

Наконец, убедитесь, что вы реализовали чтение заголовка; сейчас пусто:

//Read title
...