Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
This code is supposed to read in from a file and store the information. Here's the file:
5
Franks,Tom 2 3 8 3 6 3 5
Gates,Bill 8 8 3 0 8 2 0
Jordan,Michael 9 10 4 7 0 0 0
Bush,George 5 6 5 6 5 6 5
Heinke,Lonnie 7 3 8 7 2 5 7
right now I'm just focused on saving pointers to the names. Here's the code I have so far (Ignore the other functions I haven't gotten to those yet). I have to save the names using employees[row] = new Employee; and fin >> employees[row]->names; and I just don't know how to go about doing that.
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
using namespace std;
struct Employee {
string names;
vector<int> data;
int totalHrs;
};
int fillAndTotal(vector<Employee *>&employees);
void sort(vector<Employee *>&employees, int amount);
void output(vector<Employee *>&employees, int amount);
int main()
{
vector<Employee *>employees;
//vector<string>names;
int amount = 0;
amount = fillAndTotal(employees);
sort(employees, amount);
output(employees, amount);
system("pause");
return 0;
}
int fillAndTotal(vector<Employee *>&employees) {
int const TTL_HRS = 7;
ifstream fin;
fin.open("empdata.txt");
if (fin.fail()) {
cout << "ERROR";
}
int sum = 0;
int numOfNames;
fin >> numOfNames;
string tmpString;
int tempInt = 0;
vector<int>temp(8);
for (int row = 0; row < numOfNames; row++) {
employees[row] = new Employee;
fin >> employees[row]->names;
Firstly, you don't need pointers for this - your Employee structure is perfectly safe to store as-in in a vector.
Secondly, when reading line-orientated data like this, it's very easy to get off-track and let your reads overflow into the next line, or underflow and you not carry out enough reads for the line - what I do is write a function that reads a whole line at a time and returns a stringstream containing just that line, then I do my individual reads on that stringstream.
Thirdly, and finally, it's always useful to write functions that allows you to dump out your data structures so that you can confirm visually that you've populated the structures correctly. Or you can use a debugger.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
struct Employee
{
std::string names;
std::vector<int> data;
int totalHrs;
};
using EmpList = std::vector<Employee>;
int fillAndTotal(EmpList& employees);
std::stringstream readRowData(std::istream& fin);
#ifndef NDEBUG
// Debug - dump to stream.
std::ostream& operator<<(std::ostream& out, const Employee& employee);
std::ostream& operator<<(std::ostream& out, const EmpList& employees);
#endif
int main(int argc, char* argv[])
{
EmpList employees;
auto grandTotal = fillAndTotal(employees);
std::cout << employees;
std::cout << "\nGrand total hours: " << grandTotal << std::endl;
}
int fillAndTotal(EmpList& employees)
{
auto fin = std::ifstream("empdata.txt");
auto rowCount = 0;
auto rowData = readRowData(fin);
rowData >> rowCount;
auto totalHours = 0;
for (auto i = 0; i < rowCount; ++i)
{
rowData = readRowData(fin);
if (!fin.eof())
{
auto employee = Employee{};
rowData >> employee.names;
int hours;
while (rowData >> hours)
{
if (hours != 0)
{
employee.data.push_back(hours);
employee.totalHrs += hours;
totalHours += hours;
}
}
employees.push_back(employee);
}
}
return totalHours;
}
std::stringstream readRowData(std::istream& fin)
{
std::stringstream rowStream;
std::string rowData;
if (getline(fin, rowData))
{
rowStream.str(rowData);
}
return rowStream;
}
#ifndef NDEBUG
std::ostream& operator<<(std::ostream& out, const Employee& employee)
{
out << "Name: " << employee.names << '\n';
out << "Total hours: " << employee.totalHrs << '\n';
out << "Individual hours:";
for (auto const &hours : employee.data)
{
out << ' ' << hours;
}
out << std::endl;
return out;
}
std::ostream& operator<<(std::ostream& out, const EmpList& employees)
{
auto first = true;
for (auto const &employee : employees)
{
if (first)
{
first = false;
}
else
{
out << '\n';
}
out << employee;
}
return out;
}
#endif
Now your output function is already written for you, and you just need to write your sort.
Related
In C++, how to use a two-dimensional dynamic vector to sum up each column for the matrix in the txt file, and print out the content of the txt file and the result of summing up each column?
After searching through the Internet, I got the following code, but it only sums up a single column. The result I want to get is that no matter how many columns there are in the txt file, I can do the sum of each column.
data.txt figure
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
int main() {
ifstream myfile("data.txt");
if (!myfile.is_open()) {
cout << "Unable to open myfile";
system("pause");
exit(0);
}
vector<string> vec;
string temp;
while (getline(myfile, temp))
{
vec.push_back(temp);
}
vector <float> radius;
cout << "Processing time: " << endl;
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it << endl;
istringstream is(*it);
string s;
int pam = 0;
while (is >> s)
{
if (pam == 0)
{
float r = atof(s.c_str());
radius.push_back(r);
}
pam++;
}
}
cout << "matrix: " << endl;
double sum;
sum = 0;
for (auto it = radius.begin(); it != radius.end(); it++)
{
sum += *it;
}
cout << sum << endl;
system("pause");
return 0;
}
I want to sum each column in the txt file, as shown in the image below:
result
The first thing you should do is not concern yourself with where the data is coming from. Instead, you should write a function that takes the data, regardless of where it comes from, and outputs the totals.
The simplest way to represent the input data is to use a std::vector<std::vector<float>>. Thus a function to create the totals would return a std::vector<float> that represents the totals.
Here is an example of such a function:
#include <vector>
#include <numeric>
// Pass in the data
std::vector<float> getTotals(const std::vector<std::vector<float>>& myData)
{
std::vector<float> totals(myData[0].size());
for (size_t i = 0; i < totals.size(); ++i)
{
// call std::accumulate for each column i
totals[i] = std::accumulate(myData.begin(), myData.end(), 0,
[&](int total, auto& v)
{ return total + v[i]; });
}
// return the totals
return totals;
}
The above function uses std::accumulate to total the values in column i, and store the total for that column in totals[i].
Once this function is written, it can then be tested. Here is a full example:
#include <vector>
#include <numeric>
#include <iostream>
std::vector<float> getTotals(const std::vector<std::vector<float>>& myData)
{
std::vector<float> totals(myData[0].size());
for (size_t i = 0; i < totals.size(); ++i)
{
totals[i] = std::accumulate(myData.begin(), myData.end(), 0,
[&](int total, auto& v)
{ return total + v[i]; });
}
return totals;
}
void printTotals(const std::vector<std::vector<float>>& data,
const std::vector<float>& totals)
{
for (auto& v : data)
{
for (auto& v2 : v)
std::cout << v2 << " ";
std::cout << "\n";
}
std::cout << "Total: ";
for (auto& t : totals)
std::cout << t << " ";
}
int main()
{
std::vector<std::vector<float>> test1 = {{1,2,3},{4,5,6},{7,8,9}};
std::vector<std::vector<float>> test2 = {{1,2,3,4},{4,5,6,8},{7,8,9,10}};
std::vector<std::vector<float>> test3 = {{1,2},{-3,4},{7,8},{34,12},{12,17}};
printTotals(test1, getTotals(test1));
std::cout << "\n\n";
printTotals(test2, getTotals(test2));
std::cout << "\n\n";
printTotals(test3, getTotals(test3));
}
Output:
1 2 3
4 5 6
7 8 9
Total: 12 15 18
1 2 3 4
4 5 6 8
7 8 9 10
Total: 12 15 18 22
1 2
-3 4
7 8
34 12
12 17
Total: 51 43
Once you have this, the next step is to create the std::vector<std::vector<float>> from the data in the file. Once that is created, it is just a simple matter of calling the getTotals() function with that data.
The file reading can be as follows:
#include <istream>
#include <sstream>
#include <vector>
#include <string>
//...
std::vector<std::vector<float>> readData(std::istream& is)
{
std::vector<std::vector<float>> data;
std::string oneLine;
float oneData;
while (std::getline(is, oneLine))
{
std::vector<float> vOneData;
std::istringstream strm(oneLine);
while (strm >> oneData)
vOneData.push_back(oneData);
data.push_back(vOneData);
}
return data;
}
The function is called by simply passing in the stream object (in your case, myfile). The returned value will be a std::vector<std::vector<float>> of the values that were read in.
Putting this all together:
#include <vector>
#include <numeric>
#include <iostream>
#include <istream>
#include <string>
#include <sstream>
std::vector<float> getTotals(const std::vector<std::vector<float>>& myData)
{
std::vector<float> totals(myData[0].size());
for (size_t i = 0; i < totals.size(); ++i)
{
totals[i] = std::accumulate(myData.begin(), myData.end(), 0,
[&](int total, auto& v)
{ return total + v[i]; });
}
return totals;
}
void printTotals(const std::vector<std::vector<float>>& data,
const std::vector<float>& totals)
{
for (auto& v : data)
{
for (auto& v2 : v)
std::cout << v2 << " ";
std::cout << "\n";
}
std::cout << "Total: ";
for (auto& t : totals)
std::cout << t << " ";
}
std::vector<std::vector<float>> readData(std::istream& is)
{
std::vector<std::vector<float>> data;
std::string oneLine;
float oneData;
while (std::getline(is, oneLine))
{
std::vector<float> vOneData;
std::istringstream strm(oneLine);
while (strm >> oneData)
vOneData.push_back(oneData);
data.push_back(vOneData);
}
return data;
}
int main()
{
std::string fileData = "2 3 4 1 5 2\n6 1 2 6 1 8\n8 7 3 9 6 4";
std::istringstream fileDataStream(fileData);
auto dataFromFile = readData(fileDataStream);
printTotals(dataFromFile, getTotals(dataFromFile));
}
Output:
2 3 4 1 5 2
6 1 2 6 1 8
8 7 3 9 6 4
Total: 16 11 9 16 12 14
Note that I didn't use a file stream, but a stringstream to illustrate it doesn't matter how the data is created.
Below code is the normal way to get the input from a text and store it in an array in a structure.
Wanted to ask how can i use pointer to store all these data into the array of structure ? Like p1->Years (this is without array, but how can i apply this to way of writing in below code)
Any better suggestion to use pointer to take in the input?
int years = 4;
struct maju_company {
int Year;
float quarter1, quarter2, quarter3, quarter4, total_sales, average_sales;
};
int main() {
string line;
maju_company p1[years];
fstream yeecinnfile("MajuSales.txt");
if(yeecinnfile.is_open()) {
//ignoring the first four line of code and store the rest of the code
string line1,line2,line3,line4;
getline(yeecinnfile,line1);
getline(yeecinnfile,line2);
getline(yeecinnfile,line3);
getline(yeecinnfile,line4);
while(!yeecinnfile.eof()) {
for(int i =0; i<years; i++) {
yeecinnfile>>p1[i].Year>>p1[i].quarter1>>p1[i].quarter2>>p1[i].quarter3>>p1[i].quarter4;
}
}
for(int i =0; i<years; i++) {
cout<<p1[i].Year<<setw(10)<<p1[i].quarter1<<setw(10)<<p1[i].quarter2<<setw(10)<<p1[i].quarter3<<setw(10)<<p1[i].quarter4<<endl;
}
cout<<endl;
}
}
I see nothing wrong with the way you do this.
However, you could create a pointer to each record inside the loop
maju_company* p = &p1[i];
and then use p-> instead of p1[i]., but I really don't see this as an improvement.
If the reading loop looks too complicated, I would rather move the code to a separate function, perhaps
void read_record(maju_company& company);
or maybe
maju_company read_record();
and then only have to handle a single company inside the function (so no indexing and no ponters there).
I think you wouldn't need pointers at all for your example.
Use a std::vector to hold all your data and then there are other
things from C++ I think you should learn to use, example here :
(if you have questions let me know)
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
// dont use : using namespace std;
struct maju_company_data
{
int year;
float quarter1, quarter2, quarter3, quarter4, total_sales, average_sales;
};
// describe how to stream data to an output stream (like std::cout)
std::ostream& operator<<(std::ostream& os, const maju_company_data& data)
{
os << "-----------------------------------------------------\n";
os << "Company data for year : " << data.year << "\n";
os << "Quarter 1 : " << data.quarter1 << "\n";
os << "Quarter 2 : " << data.quarter1 << "\n";
os << "Quarter 3 : " << data.quarter1 << "\n";
os << "Quarter 4 : " << data.quarter1 << "\n";
os << "\n";
return os;
}
int main()
{
// no need to manage pointers yourself use a vector
std::vector<maju_company_data> company_yearly_data; // give variables a meaningful name
std::ifstream ifile("MajuSales.txt"); // ifstream your using file as input
std::string line1, line2, line3, line4;
// ignore first line
ifile >> line1;
while (ifile >> line1 >> line2 >> line3 >> line4) // probably you need to read a few more lines here
{
maju_company_data data;
// convert read strings to numbers
data.year = std::stoi(line1);
data.quarter1 = std::stof(line2);
data.quarter2 = std::stof(line3);
data.quarter3 = std::stof(line4);
//..
//data.quarter4 = std::stof(line5);
//data.total_sales = std::stof(line6);
company_yearly_data.push_back(data);
};
// this is a range based for loop
// it is prefered since you cant go out of bounds
// const auto& means that data will be an unmodifiable
// reference to each of the structs stored in the vector
for (const auto& data : company_yearly_data)
{
std::cout << data; // since we overloaded << this loop will be nice and clean
}
return 0;
}
A C++ approach to this to overload the istream operator>> and ostream operator<< for your specific type. E.g.
#include <algorithm>
#include <array>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
static constexpr auto years{4};
struct maju_company {
int Year{};
float quarter1{}, quarter2{}, quarter3{}, quarter4{};
float total_sales{}, average_sales{}; // ALWAYS init your floats.
};
auto& operator>>(std::istream& is, maju_company& mc) {
is >> mc.Year
>> mc.quarter1 >> mc.quarter2 >> mc.quarter3 >> mc.quarter4
>> mc.total_sales >> mc.average_sales;
return is;
}
auto& operator<<(std::ostream& os, maju_company const& mc) {
os << mc.Year
<< std::setw(10) << mc.quarter1
<< std::setw(10) << mc.quarter2
<< std::setw(10) << mc.quarter3
<< std::setw(10) << mc.quarter4;
return os;
}
You can then go on to use the type using the std library, e.g.
int main() {
auto p1{std::array<maju_company, years>{}};
{
auto fs{std::fstream("MajuSales.txt")};
if (!fs.is_open()) return -1;
{
// throw away 4 lines
auto dummy{std::string{}};
for (auto i{0}; i < 4; ++i) getline(fs, dummy);
}
std::copy_n(std::istream_iterator<maju_company>{fs},
years,
begin(p1));
}
std::copy(cbegin(p1), cend(p1),
std::ostream_iterator<maju_company>{std::cout, "\n"});
}
User inputs ints and strings and program stores them into two separate lists in C++.
I get an error on if (isNum(input)) - invalid arguments; could not convert input from char to string.
#include <list>
#include <iostream>
using namespace std;
bool isNum(string s)
{
for (int i = 0; i < s.length(); i++)
if (isdigit(s[i]) == false)
return false;
return true;
}
int main(int argv, char* argc[])
{
int i;
string str;
list<int> l;
list<string> s;
char input;
do {
cin >> input;
if (isNum(input))
{
i = input;
l.push_front(i);
}
else
{
str = input;
s.push_back(str);
}
l.push_back(i);
s.push_back(str);
} while (i != 0);
l.sort();
list<int>::const_iterator iter;
for (iter = l.begin(); iter != l.end(); iter++)
cout << (*iter) << endl;
}
That's not that easy ... But I'd let the stream do the work of deciding if it's an int or a string:
#include <list>
#include <string>
#include <iostream>
int main() // no parameters required for our program
{
std::list<std::string> strings;
std::list<int> numbers;
int num;
do {
std::string str;
if (std::cin >> num) { // try to read an integer if that fails, num will be 0
numbers.push_front(num);
}
else if (std::cin.clear(), std::cin >> str) { // reset the streams flags because
strings.push_front(str); // we only get here if trying to
num = 42; // no, don't exit // extract an integer failed.
}
} while (std::cin && num != 0); // as long as the stream is good and num not 0
strings.sort();
std::cout << "\nStrings:\n";
for (auto const &s : strings)
std::cout << s << '\n';
std::cout.put('\n');
numbers.sort();
std::cout << "Numbers:\n";
for (auto const &n : numbers)
std::cout << n << '\n';
std::cout.put('\n');
}
Sample Output:
foo
5
bar
3
aleph
2
aga
1
0
Strings:
aga
aleph
bar
foo
Numbers:
0
1
2
3
5
Just a few things about your code:
Avoid using namespace std; because it spills out the entire namespace std into the global namespace.
Declare your variables as close to where they're needed.
Use range-based for-loops where possible. Easier to write, easier to read.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have to calculate the wage for each employee. How would I write a function to do this?
And how would I sort the employees according to their wage?
The data file looks like this: I think I have to convert int to string or the other way around. I know that The function for calculating wage is wrong. Thanks.
A.Smith 20001 25 40
T.Philip 20002 20 35
S.Long 20003 15 50
G.Santos 20004 30 30
F.Farkas 20005 22 55
and this is my code that I am trying to write:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <stdlib.h>
using namespace std;
struct Record
{
string name;
int id;
double rate;
int hrWorked;
double wage;
};
void read_file(string[], int);
void calculate_wage(Record& payroll);
int main()
{
int e = 5;
Record payroll[5];
string s[5];
cout << "Your entered file is: " << endl;
read_file(s, e);
calculate_wage(payroll);
system("pause");
return 0;
}
void read_file(string s[], int e)
{
ifstream myFile;
myFile.open("Project 3.dat");
string str;
int i = 0;
if (myFile.is_open())
{
while (getline(myFile, str))
{
s[i++] = str;
cout << str << endl;
}
myFile.close();
}
else
{
cout << "No Data Found!" << endl;
}
}
void calculate_wage (Record& payroll) // i know this part isnt right but im not sure what to do for this
{
char emplresult[256]; // need to convert int to string
payroll.wage = atoi(emplresult);
payroll.rate = atoi(emplresult);
payroll.hrWorked = atoi(emplresult);
for (int i = 0; i < 5; i++)
{
payroll[i].wage = payroll[i].rate * payroll[i].hrWorked;
}
}
use std algorithms, it will make your code readable and maintainable. For example you can sort your objects with std::sort:
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
struct Record
{
Record(std::string name, double wage) : name(name), wage(wage) {};
std::string name;
int id;
double rate;
int hrWorked;
double wage;
};
int main() {
using Records = std::vector<Record>;
Records records;
records.push_back(Record("Pedro",20));
records.push_back(Record("Andres",10));
records.push_back(Record("Santiago",15));
std::sort(records.begin(),records.end(),
[](auto& lhs, auto& rhs) {
return lhs.wage < rhs.wage;
});
for (const auto& r : records) {
std::cout << "Name: " << r.name << " wage: " << r.wage << "\n";
}
}
which outputs the sorted records:
Name: Andres wage: 10
Name: Santiago wage: 15
Name: Pedro wage: 20
I hope this gives you inspiration for your code!
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am using a for loop to grab the values in a txt file.
I want to average the numbers together. So I am doing this,
int size = 0;
double sum = 0;
for (int i = 0; i < size; ++i)
{
sum += data[i].getQuantity();
}
double avg = ((double)sum)/size; //or cast sum to double before division
std::cout << avg << '\n';
return 0;
When I cout avg I get 80nan. I assume I need to do atod But I can't seem to implement this correctly.
What am I missing here to find the average of the values stored inside getQuantity
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
struct Input
{
friend std::istream& operator >>(std::istream& inp, Input& item);
friend std::ostream& operator <<(std::ostream& outp, Input const& item);
std::string group;
float total_pay;
unsigned int quantity;
Input() : group(), total_pay(), quantity()
{
}
Input(std::string groupIn, float total_payIn, unsigned int quantityIn) :
group(std::move(groupIn)),
total_pay(total_payIn),
quantity(quantityIn)
{
}
std::string const& getGroup() const { return group; }
float getTotalPay() const { return total_pay; }
unsigned int getQuantity() const { return quantity; }
};
std::istream& operator >>(std::istream& inp, Input& item)
{
return (inp >> item.group >> item.total_pay >> item.quantity);
}
std::ostream& operator <<(std::ostream& outp, Input const& item)
{
outp
<< item.getGroup() << ' '
<< item.getTotalPay() << ' '
<< item.getQuantity();
return outp;
}
int main()
{
std::ifstream infile("input.txt");
if (!infile)
{
std::cerr << "Failed to open input file" << '\n';
exit(EXIT_FAILURE);
}
std::vector<Input> data;
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
Input inp;
if (iss >> inp) // calls our extaction operator >>
data.push_back(inp);
else
std::cerr << "Invalid input line: " << line << '\n';
}
std::copy(data.begin(), data.end(),
std::ostream_iterator<Input>(std::cout,"\n"));
std::cout << data[2].getQuantity();
int size = 0;
double sum = 0;
for (int i = 0; i < size; ++i)
{
sum += data[i].getQuantity();
}
double avg = ((double)sum)/size;
std::cout << avg << '\n';
return 0;
}
Change
int size = 0;
to
size_t size = data.size();
So you set correct value to the size, loop correct number of times and then divide by correct number instead of 0.
You are dividing by 0 in this program, this will always result in an ERROR
in a program because dividing by 0 is simply not possible.