bigner
bigner

Reputation: 1

read text file contain matrix C++

I need to simple program on C++ which can take two matrices from text file and also it take the number of row and column of each one like this:

this is ex for which is text file contain

3 5
1 -2 3 4 5
1 2 -3 4 5
-1 2 3 4 5
5 4
-1 2 3 4
1 -2 3 4
1 2 -3 4
1 2 3 -4
-1 -2 -3 -4

the first line of each matrix contain it`s number of row and column

and this is the prog which i tried to do it

#include <cstdio>
#include <cstring>
#include <fstream>
#define Height 3
#define Width  5
// I assume that each input line in the file can contain at most width * 3 characters.
// Three extra characters for NL, CR, 0.
// Change this if you expect the file to contain longer lines.
#define BUFFER_WIDTH (Width * 3 + 3)
unsigned char Map[Height][Width];
char line[BUFFER_WIDTH];
// Remove CR, NL at the end of the line.
void clean_line(char *line)
{
 int len = strlen(line);
  while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
{
 line[len - 1] = '\0';
 len--;
  }
}
int main ()
{
FILE *fp = fopen("input1.txt","r");
int row = 0;
while (!feof(fp) && row < Height)
  {
  fgets(line, BUFFER_WIDTH, fp);
  clean_line(line);
  int len = strlen(line);
  int rowLen = len > Width ? Width : len;
for (int col = 0; col < rowLen; col++)
{
  Map[row][col] = line[col];
  printf("%d  ",Map[row][col]);
 }
printf("\n");
row++;
 }
fclose(fp);
 return 0;
}

Upvotes: 0

Views: 2559

Answers (4)

Andrew Tomazos
Andrew Tomazos

Reputation: 68598

#include <iostream>
#include <vector>
using namespace std;

vector<vector<int>> read_matrix(istream& in)
{
    int rows, cols;
    in >> rows >> cols;

    vector<vector<int>> matrix(rows, vector<int>(cols));

    for (auto& row : matrix)
        for (auto& cell : row)
            in >> cell;

    return matrix;
}

int main()
{
    fstream in("input.txt");
    vector<vector<int>> mat1 = read_matrix(in);
    vector<vector<int>> mat2 = read_matrix(in);
}

Upvotes: 0

Paul Hiemstra
Paul Hiemstra

Reputation: 60924

I recently wrote a rather simple CSV reader class, this does a lot of the things you are looking for. I also posted this code on the stack exchange Code Review. This also includes some comments on the code. I use boost::MultiArray to store the results in a 2d array, and I use boost::split to split the text in the file into numbers.

Here is the code:

A header file:

 #include <iostream>
 #include <sstream>
 #include <string>
 #include <stdexcept>

 class BadConversion : public std::runtime_error {
 public:
   BadConversion(std::string const& s)
     : std::runtime_error(s)
     { }
 };

 class BadIndex : public std::runtime_error {
 public:
   BadIndex(std::string const& s)
     : std::runtime_error(s)
     { }
 };

 inline double convertToDouble(std::string const& s)
 {
   std::istringstream i(s);
   double x;
   if (!(i >> x))
     throw BadConversion("convertToDouble(\"" + s + "\")");
   return x;
 }

and the c++ code, which include some example uses:

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/multi_array.hpp>
#include "csv-test.h"
#include <cassert>

template <class T> class csv_reader {
  boost::multi_array<T, 2> content2d ;
  std::vector<std::string> split_line ;        
  std::string line;
  std::string sep ;
  int ncol ;                         
  int nrow ;  
public :
  csv_reader(std::string, std::string) ;  // constructor
  ~csv_reader();          // desctructor
  void cout_content() ;    // print the contents
  T operator() (unsigned row, unsigned column) ;
} ;

// Constructor
template <class T> csv_reader<T>::csv_reader(std::string path, std::string sep = ",")
{
  // Initializing variables
  ncol = 0 ; // Initialize the number of colums to 0
  nrow = 1 ; // Initialize the number of rows to 1
  content2d = boost::multi_array<T, 2> (boost::extents[0][0]) ;
  std::ifstream  data(path.c_str()) ;

  // read the csv data
  while(getline(data, line))
  {   
    boost::split(split_line, line, boost::is_any_of(sep) ) ;
    if(ncol == 0) 
    {
      ncol = split_line.size() ;
    }
    else assert(ncol == split_line.size()) ;
    content2d.resize(boost::extents[nrow][ncol]) ;
    for(int i = 0; i < split_line.size(); i++) 
    {
      content2d[nrow - 1][i] = convertToDouble(split_line[i]) ;
    }
    nrow++ ;
  }
}

// Destructor
template <class T> csv_reader<T>::~csv_reader() { }

template <class T> void csv_reader<T>::cout_content()
{
  for(int row = 0; row < (nrow - 1); row++) 
  {
      for(int col = 0; col < ncol ; col++) 
      {
        std::cout << content2d[row][col] << " ";
      }
      std::cout << "\n" ;
  }
}

// Allow access to the contents
template <class T> T csv_reader<T>::operator() (unsigned row, unsigned column)
{ 
  if (row >= nrow || column >= ncol)
     throw BadIndex("boost::MultiArray subscript out of bounds");
  return(content2d[row][column]) ;
}

int main()
{
  // An integer csv reader
  csv_reader<int> csv_obj_int("test.csv") ;
  csv_obj_int.cout_content() ;

  // A double csv reader
  csv_reader<double> csv_obj_double("test.csv") ;
  csv_obj_double.cout_content() ;

  // It also supports direct access to the content using operator()
  std::cout << csv_obj_double(1,1) << "\n" ;
  std::cout << csv_obj_double(1,1) * 5 << "\n" ;

  // This statement fails with a subscript out of bounds error
  // std::cout << csv_obj_double(10,10) * 5 << "\n" ;

  // Testing a different seperator
  csv_reader<double> csv_obj_double_sep2("test_semicol.csv", ";") ;
  csv_obj_double_sep2.cout_content() ;
}

Upvotes: 0

YAKOVM
YAKOVM

Reputation: 10153

#include <iostream>

void matUpdate(int***mat,int& row,int& col,int**matData,int& rowData,int& colData) {
    *mat = matData;
    row = rowData;
    col = colData;
}
int read(int***mat1,int***mat2,int& row1,int& col1,int& row2,int& col2)
{
    FILE* fp = fopen("mat.txt","r");
    if (fp == NULL) {
        return -1;
    }
    int row,col,matNum = 0;
    while(matNum < 2) {
        if (fscanf(fp,"%d %d",&row,&col) != 2 || row < 0 || col < 0) {
            return -1;
        }
        int i,j;
        int** mat = new int*[row];

        for (i = 0; i < row;++i) {
            mat[i] = new int[col];
        }
        for (i = 0;i < row;++i) {
            for (j = 0;j < col;++j) {
                fscanf(fp,"%d",&mat[i][j]);
            }
        }
        if (matNum) {
            matUpdate(mat2,row2,col2,mat,row,col);
        }
        else {
            matUpdate(mat1,row1,col1,mat,row,col);
        }
        matNum++;
    }
    return fp;
}
int main()
{
    int **mat1 = NULL,**mat2 = NULL;
    int row1,col1,row2,col2;
    FILE* fp = read(&mat1,&mat2,row1,col1,row2,col2);
    if (fp != - 1) {
    //work with matrics
    //delete memory allocated for matrics
    fclose(fp);
    }
    else {
      //error
    }

}

Upvotes: 1

Sebastian Hoffmann
Sebastian Hoffmann

Reputation: 11482

You need to parse the file at whole and then to split it by some delimeter(in this case newlines and blanks). This process is called tokenization. Many libraries like boost or poco support such operations.

class StringTokenizer

boost::split

Upvotes: 1

Related Questions