0

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

}
2
Contributors
1
Reply
2
Views
8 Years
Discussion Span
Last Post by d0pedup
0

I didn't read your code but from what i have gathered you want to create a Database like operation.
For varying width operations why don't you go for a solution on similar lines
<row>
<field1>
XXXXXXXXX
</field1>
<field2>
XXXX
</field2>
</row>
<field1>
...

keep in mind this is just a suggestion and i don't know if you have already implemented a solution on similar lines.

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.