Hi guys, I have written some C++ code to do three things:
1. Read data from a delimited file (user specifies type of delimiter used), and return data as a "2D array".
2. Print 2D array to console.
3. Write the 2D array to a tab delimited text file.
I have also had a go at introducing some error handling.
Since I am a bit of a newbie to C++, I just wanted to know if there were any improvements I could make to increase efficiency. Any help would be very appreciated.
// Reads data from a delimited file.
// Data is returned as a 2D array.
// The 2D array is saved to file and printed to console.
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdlib>
using namespace std;
float** ReadTable(const char* FileName_Read, const char delimiter,
int& RowNum, int& ColNum) {
string line;
ifstream in(FileName_Read);
// Determine number of rows and columns in file.
// Program halts if rows are not of same length.
while(getline(in,line,'\n')) {
string entry;
int EntriesPerRow = 0; // Initialize counter.
stringstream ss;
ss << line;
while (getline(ss,entry,delimiter)) {
EntriesPerRow++;
}
if (RowNum == 0) {
// Define number of columns in file as the number
// of entries in the first row.
ColNum = EntriesPerRow;
} else {
if (EntriesPerRow != ColNum) {
cerr << "Row " << RowNum << " is not the same length "
"as row 0." << endl;
exit(0);
}
}
RowNum++;
}
// Declare arrays for storing and accessing
// data from the file.
float** pa2d = new float*[RowNum];
float* parr = new float[RowNum*ColNum];
// Reposition to start of stream buffer.
in.clear();
in.seekg(0, ios::beg);
int k = 0; // Initialize counter
// Read each entry into 1D array.
while(getline(in,line,'\n')) {
// Declarations.
stringstream ss;
ss << line;
string entry;
while (getline(ss,entry,delimiter)) {
// Declarations.
stringstream entry_ss;
float entry_float;
char entry_char;
// Insert data entry into stringstream.
entry_ss << entry;
// Convert data entry to float.
entry_ss >> entry_float;
if (!entry_ss) {
// Check if stream is in error state.
// Halt program if it is.
float r = floor(k/ColNum); float c = k - (r*ColNum);
// (Convert 1D array position to 2D array position.)
cerr << "Bad input: Entry [" << r << "," << c
<< "] put stream into error state." << endl;
exit(0);
} else {
if (entry_ss >> entry_char) {
// The attempt to extract a character is a test
// to see if there is anything left in the stream
// after we extract a float. Program is halted if
// if a non-numeric entry is found.
float r = floor(k/ColNum); float c = k - (r*ColNum);
// (Convert 1D array position to 2D array position.)
cerr << "Bad input: Entry [" << r << "," << c
<< "] is not numeric." << endl;
exit(0);
} else {
// Everything is OK, build array.
parr[k] = entry_float;
}
}
k++;
}
}
in.close();
// Prepare 2D array to be returned.
// Define pointer position at start of each row.
for (int i = 0; i < RowNum; i++) {
pa2d[i] = parr + (i*ColNum);
}
return pa2d;
}
void PrintMatrix(float** matrix, const int RowNum, const int ColNum) {
// Print "matrix" to console.
cout << '\n';
for (int i=0; i < RowNum; i++) {
for(int j=0; j < ColNum; j++) {
cout << (j?"\t":"") << matrix[i][j];
// Don't insert tab before first element of each row.
}
cout << '\n';
}
}
void WriteTable(const char* FileName_Write, float** matrix,
const int RowNum, const int ColNum) {
// Write "matrix" to delimited file.
// Code is very similar to PrintMatrix
ofstream out(FileName_Write);
for (int i=0; i < RowNum; i++) {
for(int j=0; j < ColNum; j++) {
out << (j?"\t":"") << matrix[i][j];
// Don't insert delimiter before first element of each row.
}
out << '\n';
}
out.close();
}
int main() {
// Define filenames.
const char* FileName_Read = "floats.txt";
const char* FileName_Write = "write.txt";
// Initialize row and column counters.
int RowNum = 0; int ColNum = 0;
// Define delimiter.
const char delimiter = '\t';
// Perform reading of data file into 2D array.
float** data = ReadTable(FileName_Read,delimiter,RowNum,ColNum);
// Print contents of 2D array to console.
PrintMatrix(data,RowNum,ColNum);
// Write 2D array to delimited file.
WriteTable(FileName_Write,data,RowNum,ColNum);
return(0);
}