C++ 2d read-in array troubles - c++

I need help with reading in a text file that has string integers for the first row and for the first column. I need to have everything print out in a table format. The program I have reads in a edited text file that only has the floats, and works fine. The program is meant to read in the text file, find the average and totals for each row and column, and print it all out in a table, but I'm unsure how to go about this. The table is supposed to print like so:
Department-Name Electric Copier Phone Miscellaneous sumOfRows totalOfRows
Bookkeeping 434.92 233.76 322.25 1442.98
Sales 610.55 233.21 144.75 1232.20
Service 343.21 224.76 128.90 987.00
Customer Relations 278.23 98.43 177.34 899.32
Marketing 522.32 109.78 233.45 1232.45
Media 132.98 221.43 119.56 1090.30
Human-Resources 109.56 342.87 298 1154
sumOfColumns
totalofColumns
I was told that I could input two string arrays, one for the first row and one for the first column, but I'm unsure how I could print it out in a table format.
Here is the file:
Department-Name Electric Copier Phone Miscellaneous
Bookkeeping 434.92 233.76 322.25 1442.98
Sales 610.55 233.21 144.75 1232.20
Service 343.21 224.76 128.90 987.00
Customer Relations 278.23 98.43 177.34 899.32
Marketing 522.32 109.78 233.45 1232.45
Media 132.98 221.43 119.56 1090.30
Human-Resources 109.56 342.87 298 1154
Here is my code:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
using namespace std;
const int ROWSPACE = 7;
const int COLUMNSPACE = 4;
float rowAverage[ROWSPACE] = {0};
float colAverage[COLUMNSPACE] = {0};
float rowTotal[ROWSPACE] = {0};
float colTotal[COLUMNSPACE] = {0};
float getAverage(float averageArray[][COLUMNSPACE], int size, float rowAverage[], float colAverage[]);
float calcTotal(float sumArray[][COLUMNSPACE], int sz, float rowTotal[], float colTotal[]);
void getData(float expense[][COLUMNSPACE], int ROWSPACE);
void printTable();
int _tmain(int argc, _TCHAR* argv[])
{
printTable();//Prints the data.
system("pause");
return 0;
}
float getAverage(float averageArray[][COLUMNSPACE], int size, float rowAverage[], float colAverage[])//Finds the sums of the rows and columns.
{
int i,j;
float sum = 0, average;
cout<<"These are the row averages: \n";
for(i = 0; i<size; i++)
{
for(j=0; j<COLUMNSPACE; j++)
{
sum+=averageArray[i][j];//Finds the overall average
rowAverage[i] += averageArray[i][j]; //Finds each row's average
colAverage[j] += averageArray[i][j]; //Finds each column's average.
}
rowAverage[i] /= COLUMNSPACE;
cout<<rowAverage[i]<<"\t"; //prints the row averages
}
cout<<endl;
cout<<"These are the column averages: \n";
for(j=0; j<COLUMNSPACE; j++)
{
colAverage[j] /= size;
cout<<colAverage[j]<<"\t"; //prints the column averages
}
average=sum/(size * COLUMNSPACE);
return average;
}
float calcTotal(float sumArray[][COLUMNSPACE], int sz, float rowTotal[], float colTotal[])
{
int i,j;
float sum = 0, total;
cout<<"These are the row totals: \n";
for(i = 0; i<sz; i++)
{
for(j=0; j<COLUMNSPACE; j++)
{
sum+=sumArray[i][j]; //Finds the overall total
rowTotal[i] += sumArray[i][j]; //Finds the row totals
colTotal[j] += sumArray[i][j]; //Finds the column totals
}
cout<<rowTotal[i]<<"\t"; //prints out row totals
}
cout<<"\nThese are the column totals: \n";
for(j=0; j<COLUMNSPACE; j++) {
cout<<colTotal[j]<<"\t"; //Prints out column totals
}
total=sum;
return total;
}
void getData(float expense[][COLUMNSPACE], int ROWSPACE)
{
ifstream expenseFile;
ofstream outFile;
int i, j;
expenseFile.open("Expense1.txt"); //reads in the file (I have Expense1 as the floats only, and Expense with the strings and the floats)
outFile.open("newFile.txt"); //creates thew new file
outFile<<"The expenses are: \n";
for(i = 0; i<ROWSPACE; i++) //creates the array from the file
{
for(j = 0; j<COLUMNSPACE; j++)
{
expenseFile>>expense[i][j];
cout<<expense[i][j]<<"\t";
outFile<<expense[i][j]<<"\t";
}
cout << endl; //closes the expense file
outFile << endl; //closes the new file
}
}
void printTable() //prints out the data
{
float average;
float total;
float expenseArray[ROWSPACE][COLUMNSPACE];
cout<<"Electric Copier Phone Miscellaneous\n";
getData(expenseArray,ROWSPACE);
cout<<endl;
average=getAverage(expenseArray,ROWSPACE,rowAverage, colAverage);
cout<<endl;
total= calcTotal(expenseArray, ROWSPACE, rowTotal, colTotal);
cout<<endl;
}
Any suggestions?

Use an array of structures, not a 2D array.
One reason is all elements of an array must have the same data type so you can't mix strings and floats without playing shifty games with casting or unions. But with a class or structure... You can really have fun!
struct datastruct
{
string DepartmentName;
float Electric;
float Copier;
float Phone;
float Miscellaneous;
};
If allowed, prefer std::vector
std::vector<datastruct> list;
If bound by odd requirements and you have to use an array
datastruct list[ROWSPACE];
Now you can read the file in line by line. The following is adapted from Read file line by line
std::string line;
std::getline(infile, line); // discard first line. It is only header information
while (std::getline(infile, line))
{
std::istringstream iss(line);
datastruct temp;
if (!(iss >> temp.DepartmentName
>> temp.Electric
>> temp.Copier
...))
{
// handle error
}
// store temp in vector or array
list.push_back(temp);
// or
list[index] = temp;
}
If using an array add an exit condition to the while loop to prevent overrunning the end of the array
When you have a good grasp on C++ you can also overload >> for the structure and write something more like
datastruct temp;
while (infile >> temp))
{
// store temp in vector or array
}
But I'm not going to cover that trick here.
Passing it around is much easier because you now have a one dimensional vector or array.
float getAverage(vector<datastruct> & list,
vector<float> &rowAverage,
datastruct & colAverage)
or
float getAverage(datastruct list[],
int size,
float rowAverage[],
datastruct & colAverage)
To make computing the row and column average easy we modify datastruct
struct datastruct
{
string DepartmentName;
float Electric;
float Copier;
float Phone;
float Miscellaneous;
float getAverage()
{
return (Electric + Copier + phone + Miscellaneous) / 4;
}
datastruct & operator+=(const datastruct & rhs)
{
Electric += rhs.Electric;
Copier+= rhs.Copier;
Phone+= rhs.Phone;
Miscellaneous+= rhs.Miscellaneous;
return *this;
}
datastruct & operator/=(float divisor)
{
Electric /= divisor;
Copier/= divisor;
Phone/= divisor;
Miscellaneous/= divisor;
return *this;
}
};
and call it like
for (auto & row: list)
{
rowAverage.push_back(row.getAverage());
colAverage += row;
}
colAverage /= size;
or
for(i = 0; i<size; i++)
{
rowAverage[i] = list[i].getAverage();
colAverage += list[i];
}
colAverage /= size;
Here colAverge is used to sum up all the items in the list with the overloaded += operator and is then divided by the size with the/= operator.
Note that colAverage needs to be zeroed before it can be used to sum. You may want to add a method or a constructor to do that for you.
Calculating the totals is similar.

Related

Getting variables values from a .txt file in C++

I am writing a CFD solver in C++ but I am in the very beginning. Now I am coding a solver for the linear convection. The math is ok, working well, but I need to write also a code for reading variables from a .txt file.
My code is:
//Code for solving the convection linear equation from Navier-Stokes
#include <iostream>
using namespace std;
int main()
{
float endtime=0.3; //simulation time
float dx=0.025; //element size
float xmax=2; //domain size
float c=1; //wave velocity
float C=0.3; //Courant-Friedrich-Lewy number
float dt=C*dx/c; //defining timestep by the Courant equantion
int nx=xmax/dx + 1; //defining number of elements
int nt=endtime/dt; //defining number of time points
float u[nx] = { }; //defining an initial velocity array.
float un[nx] = { };
for(int i = 4; i <= 9; i++) //defining contour conditions
{
u[i] = 2;
}
for(int n=1; n<=nt; n++)
{
std::copy(u, u + nx, un);
for(int i=1; i<=nx; i++)
{
u[i] = un[i] - c*(dt/dx)*(un[i]-un[i-1]);
}
}
for (int i = 0; i <= nx; i++)
{
cout << u[i] << endl;
}
return 0;
}
I need to take these variables values from a .txt, like the end time, element size, etc. Then, I have a .txt called "parameters", which is exactly written like that:
endtime=0.3
dx=0.025
xmax=2
c=1
C=0.3
What's the most effiecient way to get these variables values from this .txt and use it in the code?
Using only standard features:
#include <iostream>
#include <tuple>
using namespace std;
tuple<bool, string, string> read_one_value(istream& in)
{
string name;
if(getline(in, name, '='))
{
string value;
if(getline(in, value))
{
return make_tuple(true, name, value);
}
}
return make_tuple(false, "", "");
}
int main()
{
for(auto val = read_one_value(cin); get<0>(val); val = read_one_value(cin))
{
std::cout << get<1>(val) << " -> " << get<2>(val) << '\n';
}
return 0;
}
This leaves converting from the value string objects to the needed type as an exercise for the reader, and assumes your format of name=value is consistent.

Reading arbitrary array of any size

The following code works fine when reading two .txt files containing two 5X5 array.
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <vector>
#include <sstream>
using namespace std;
int main()
{
string myFile, mysecondFile, mystring;
string DIR;
string extension;
int total = 0;
int number_of_lines = 0;
string line;
extension = ".txt";
DIR = "H:\\Year2\\EE273\\EE273\\Week6\\";
cout << "Enter the name of the file: \t";
cin >> myFile;
cout << "Enter the name of the second file: \t";
cin >> mysecondFile;
myFile = DIR + myFile + extension;
mysecondFile = DIR + mysecondFile + extension;
ifstream inFile;
ifstream inFile2;
int i=5;
int j=5;
int i2=5;
int j2=5;
int i3=5;
int j3=5;
int k;
int l;
int Array[5][5];
int Array2[5][5];
int Array3[5][5];
string attempt1,attempt2;
int row = 0;
int col = 0;
int row2 = 0;
int col2 = 0;//i = row
//y = column
inFile.open(myFile.c_str());
if (!inFile) {
cout <<"Error opening file"<<myFile<<endl;
return -1;
}
while (!inFile.eof())
{
getline(inFile, attempt1);
stringstream iss( attempt1 );
string result;
col = 0;
while (getline( iss, result, ','))
{
//cout << result << endl;
Array[row][col] = atoi(result.c_str());
//j = j + 1;
col = col + 1;
}
row = row + 1;
}
inFile.close();
inFile2.open(mysecondFile.c_str());
if (!inFile2) {
cout <<"Error opening file"<<mysecondFile<<endl;
return -1;
}
while (!inFile2.eof())
{
getline(inFile2, attempt2);
stringstream iss( attempt2 );
string result2;
col2 = 0;
while (getline( iss, result2, ','))
{
//cout << result2 << endl;
Array2[row2][col2] = atoi(result2.c_str());
col2 = col2 + 1;
}
row2 = row2 + 1;
}
inFile2.close();
/*for (int i=0;i<5;i++){
for (int j=0; j<5; j++){
cout<<Array[i][j]<<endl;}}
for (int i2=0;i2<5;i2++){
for (int j2=0; j2<5; j2++){
cout<<Array2[i2][j2]<<endl;
}}
Here I am carrying out the multiplication between the two matrices and writing the resulting values to a third matrix.
int Total=0;
i=0;
j2=0;
j=0;
j3=0;
for (i3=0; i3<5; i3++) {
while(j3<5){
while (j<5){
for (i2=0;i2<5;i2++){
Total += Array[i][j]*Array2[i2][j2];
j++;
Array3[i3][j3]=Total;
}}
j=0;
j2++;
j3++;
Total=0;
}
i++;
j=0;
j2=0;
j3=0;
Total=0;
}
My question is: what is the easiest way to modify the code so that it can read two .txt files containing an array of any size and then carry out the multiplication successfully?
EDIT I have to do this using arrays only, I can't use vectors unfortunately.
Am I correct in thinking the new operator is involved?
The "easiest" way would be to do something naive, like reading the file once fully to get the number of rows/cols, then reading the file again to actually store the values in the matrix:
unsigned int rows = 0;
unsigned int cols = 0;
std::string line;
while (std::getline(inFile, line)) {
rows++;
std::stringstream ss(line);
std::string col;
while (std::getline(ss, col, ',')) {
cols++;
}
}
// Now allocate the rows*cols matrix
int** matrix = new int*[rows];
for (int i = 0; i < rows; i++) {
matrix[i] = new int[cols];
}
// and read your values into the matrix ...
// matrix[m][n] = xxx
It's pretty inefficient to read a file twice; and there are other ways to obtain the size beforehand. For example you could have a convention in your input file to include the matrix width/height before the data:
[infile.txt]
3,3
1,2,3
4,5,6
7,8,9
Now you can read the first line of the file, and you'll know that the rest of this file contains a 3x3 matrix. Allocate your matrix with new (similar to above example), then continue to read the rest of the file into it.
Remember to clean up your dynamically allocated matrices with delete[]. There should be 1 call to delete for every call to new.
for (int i = 0; i < rows; i++) {
delete[] matrix[i];
}
delete[] matrix;
Use std::vector instead of raw arrays. E.g. you can push_back an item on a vector. And more crucially, you can create it with a size known only at run-time, e.g. from information in a file.
The easiest approach requires the file to contain the size of the matrix as its first entries. With that, you can fallback to using C (C++ does not tolerate matrices of dynamic size) and do the following:
Read the dimension of the matrix into variables width and heigh.
Allocate the matrix using
int (*dynamicMatrix)[width] = malloc(height*sizeof(*dynamicMatrix));
Reuse your code to fill the matrix.
If you can't fall back to C, and can't use std::vector<>, the only thing left to you is to use a double pointer:
int**dynamicMatrix = new int*[height];
for(size_t i = width; i--; ) dynamicMatrix[i] = new int[width];
Again, this is easiest if you can define the first two numbers in a file to contain the width and height of the matrix in the file. If you can't code these two numbers into your file, you have to grow your dynamic arrays as you go:
size_t lines = 0, allocatedLines = 8;
int** dynamicMatrix = new int*[allocatedLines];
while(/* can read a line */) {
if(lines == allocatedLines) {
int** temp = new int*[allocatedLines *= 2];
for(size_t i = lines; i--; ) temp[i] = dynamicMatrix[i];
delete[] dynamicMatrix;
dynamicMatrix = temp;
}
//add one line
size_t curLineLength = 0, allocatedLineLength = 8;
dynamicMatrix[lines++] = new int[allocatedLineLength];
//fill the line
...
}
A similar block for reallocating a line would need to go into the loop where you read the elements of a single line. This is tedious; but the only way to get better is to use stuff that you are not allowed to use.
Btw: even the reallocating stuff is easier in C, since it provides the realloc() function:
size_t lines = 0, allocatedLines = 8;
int** dynamicMatrix = malloc(allocatedLines * sizeof(*dynamicMatrix));
while(/* can read a line */) {
if(lines == allocatedLines) {
//realloc takes care of copying the data to a new location (if that is necessary):
allocatedLines *= 2;
dynamicMatrix = realloc(dynamicMatrix, allocatedLines * sizeof(*dynamicMatrix));
}
//add one line
size_t curLineLength = 0, allocatedLineLength = 8;
dynamicMatrix[lines++] = malloc(allocatedLineLength * sizeof(**dynamicMatrix));
//fill the line
...
}
Since there is no equivalent to realloc() to work with new/delete, you are required to either use std::vector<> in C++, or to do the copying yourself as above.

Reading from a data file to 2D array. No output. C++

I am new to programming and c++. I am working on an assignment which requires me to read data from a data file and store it into a 2D array. Every line in the text file is in the following format(data type is int)
XXXX XX XX XX XX ...(and so on)
The four digit number is actually student ID and is to be stored in a separate 1D array. I have done this part and I don't have any issues. Now the rest 2 digit numbers are to be stored in a 2D array with 4 columns and X rows, where X is the number of lines in the data file.
I have written the following code to try to read into the file. It gives no error and compiles correctly but when I try to print the 2D array, using cout, I don't get anything. Nothing. Please look at the following code and try to help me.
I am new to stackoverflow and programming so please forgive me if the code is not formatted correctly or is not as per the tradition.
//___CODE____
#include<iostream>
#include<iomanip>
#include<fstream>
#include<cstdlib>
#include<string>
using namespace std;
//Global
const int SIZE = 1000;
int const col = 4;
string fileName;
//Function Prototypes
int readId(int id[], int size);
int readScores(int scores[][col], int size);
//Main
int main()
{
int examScores[SIZE][col];
int id[SIZE] = {};
cout<<endl;
readId(id, SIZE);
readScores(examScores, SIZE);
}
//Declarations
int readId(int id[], int size)
{
ifstream inputFile;
int count = 0;
int total = 0; //Size of id [] OR no. of students.
int temp = 0;
//Takes the name of the data file from the user.
//NOTE: The filename should include its extension.
cout<<"Enter the name of the data file (including the extension):";
cin>>fileName;
inputFile.open(fileName.c_str());
if(inputFile.is_open())
{
while(inputFile >> temp)
{
if(count % 5 == 0)
{
id[total] = temp;
total++;
}
++count;
}
}
else
cout<<"Data file not found!"<<endl; // If this is executed make sure the data file
//is located in the same directory as this program.
//To print the content of array. Check.
for(int i=0; i < total; i++)
cout<<id[i]<<endl;
return total;
}
int readScores(int scores[][col], int size)
{
ifstream inputFile;
int count = 0;
int c = 0; //Counter for column.
int total = 0; //No. of students.
int temp = 0;
inputFile.open(fileName.c_str());
if(inputFile.is_open())
{
while(inputFile >> temp)
{
if(count % 5 != 0)
{
if (c < col)
{
scores[total][c] = temp;
}
else
total++;
c = 0;
scores[total][c] = temp;
}
++count;
c++;
}
}
else
cout<<"Data file not found!"<<endl; // If this is executed make sure the data file
//is located in the same directory as this program.
//To print the contents of 2D array. Check.
for (int r = 0; r < total; r++)
{
for (c = 0; c < col; c++)
{
cout<<setw(8)<<scores[r][col];
}
cout<<endl;
}
return total;
}
Your else-Statement is wrong, there are some brackets missing (now you always reset c to zero)

Alphabetical string arrays sorting

I have posted previously and got some very helpful responses. I need to read in people's info (such as ID, age, etc.) from a text file into different arrays.
Records are like this
2012317109 Jamie Carles Smith Male 65 (different bits of info are separated by TAB, lines ending with newline)
However, regarding the ID numbers, I am told to use extraction operator (<<) to get the ID number as an integer and not as a string.
Then I must sort these records by alphabetical string order and then put these in an output file. 
So far, I have the following. How should I proceed? I am not to use maps or vectors, I need to use arrays.
#include <iostream>
#include <fstream>
using namespace std;
void selection_sort( double x[], int length)
{
int i, j, k;
double t;
for (i=0; i<length-1; ++i) {
k = i; //find next smallest elm, x[k]
for (j=i+1; j< length; ++j)
if (x[k] > x[j]) k = j;
//swap x[i] with x[k]
t = x[i]; x[i] = x[k]; x[k] = t;
}
}
int main () {
ifstream fin;
ofstream fout;
fin.open("input.txt");
fout.open("output.txt");
if (fin.fail()) {
cout << "Fail to open inout.txt" << endl;
exit(1);
}
struct row{string ID, name, rest;};
int x;
fout << x << endl;
row *rows=new row[x];
for (int i=0; i<x; ++i) {
getline (fin, rows[i].ID, '\t'); // ID
getline (fin, rows[i].name, '\t'); // name
getline (fin, rows[i].rest );
}
selection_sort (row[], x);
//complier error this line: expected primary expression before [ token.
}
The easiest approach is probably to use std::sort (from the header <algorithm>), and define an
bool operator<(row const& lhs, row const& rhs)
{
// delegates to operator< for std::string
return lhs.name < rhs.name;
}
and then call the STL algorithm
// uses the above defined operator< for row objects
std::sort(rows, rows + x);
and then write the sorted output.

Pass an array through a function

I'm trying to pass a simple array through a function to compute the mean.
int main()
{
int n = 0; // the number of grades in the array
double *a; // the array of grades
cout << "Enter number of scores: ";
cin >> n;
a = new double[n]; // the array of grades set
// to the size of the user input
cout << "Enter scores separated by blanks: ";
for(int i=0; i<n; i++)
{
cin >> a[i];
}
computeMean(a, n);
}
double computeMean (double values[ ], int n)
{
double sum;
double mean = 0;
mean += (*values/n);
return mean;
}
Right now the code is only taking the mean of the last number that was inputted.
There's no loop in your function. It should be something like:
double sum = 0;
for (int i = 0; i != n; ++i)
sum += values[i];
return sum / n;
I'm surprised your current version only takes the last number, it should only take the first number, since *values is the same as values[0].
A better solution uses idiomatic C++:
return std::accumulate(values, values + n, 0.0) / n;
std::accumulate should do the trick.
#include <numeric>
double computeMean (double values[ ], int n) {
return std::accumulate( values, values + n, 0. ) / n;
}
Is this a homework question?
You nead to step through all of the values in your array. You're currently outputting the first number in the array divided by the number of items.