This assignment has all of the functionality of assignment 3, but will be rewrit
ID: 3867745 • Letter: T
Question
This assignment has all of the functionality of assignment 3, but
will be rewritten to use dynamic c-strings and dynamic structs.
Dynamic memory can leak, so use Valgrind to check your code for
leaks (see below). In addition to the methods listed in project 3, you will create one more method to calculate the total calories burned for all exercises in the database. So, this assignment will have the same user- controlled loop as assignment 3 plus the total option. The menu items are: search for an exercise by name, list all exercises stored in memory, add a new exercise, print the total calories burned for all exercises in memory, or quit. Just like assignment 3, your program will write the data back to the same file as the input file at program termination, using the writeData() method. Don’t forget to make a backup copy of assignment 3 before modifying the source code for assignment 4.
--------------------------------------------------------------------------------
Here are Project 3 files below
-----------------------------------------------------------------------------
// common.cpp
#include "common.h"
// Return true if any char in cs satisfies condition.
// condition has type 'int (*condition)(int)' to match <cstring> convention.
bool any(const char cs[], int (*condition)(int)) {
for (int i = 0; cs[i]; i++)
if (condition(cs[i]))
return true;
return false;
}
// The q prefix indicates a function that queries the user.
// Ask the user a question. Dump the response into answer.
void qCString(const char question[], char answer[], const int ss) {
cout << question << ' ';
cin.getline(answer, ss);
}
// Bother the user until they enter a string containing graphical characters.
void qGCString(const char question[], char answer[], const int ss) {
qCString(question, answer, ss);
while (!any(answer, isgraph))
qCString("Try again:", answer, ss);
}
// Bother the user until they enter a valid integer. Return the integer.
int qInt(const char question[]) {
int resp;
bool fail;
cout << question << ' ';
while (true) {
cin >> resp;
fail = cin.fail();
cin.clear();
cin.ignore(strSize, ' ');
if (!fail)
break;
cout << "Try again: ";
}
return resp;
}
// Bother the user until they enter a positive integer. Return the integer.
int qPInt(const char question[]) {
int response = qInt(question);
while (response <= 0)
response = qInt("Try again:");
return response;
}
// Get a character from user. Consumes entire line.
char qChar(const char question[]) {
cout << question << ' ';
const char resp = cin.peek();
cin.ignore(strSize, ' ');
return resp;
}
// Return whether cs contains c.
bool contains(const char cs[], const char c) {
for (int i = 0; cs[i]; i++)
if (cs[i] == c)
return true;
return false;
}
// Bother user until they select an allowed character.
char qSel(const char question[], const char allowed[]) {
char resp = qChar(question);
while (!contains(allowed, resp))
resp = qChar("Try again:");
return resp;
}
// Bother the user until they enter y or n. Return true for y, false for n.
bool qYN(const char question[]) { return qSel(question, "yn") == 'y'; }
// Bother the user for a path to a real file. Return the open file.
void qFH(const char question[], ifstream& fh) {
char filename[strSize];
qCString(question, filename);
fh.open(filename);
while (!fh.is_open()) {
qCString("Try again:", filename);
fh.open(filename);
}
}
// Bother the user for a path to a real file. Set fn to filename.
void qFN(const char question[], char fn[], const int ss) {
ifstream fh;
qCString(question, fn);
fh.open(fn);
while (!fh.is_open()) {
qCString("Try again:", fn, ss);
fh.open(fn);
}
}
-------------------------------------------------------------------
// common.h
#ifndef _COMMON_H_
#define _COMMON_H_
#include <cstring>
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
const int strSize = 256;
const int arraySize = 128;
// Return true if any char in cs satisfies condition.
// condition has type 'int (*condition)(int)' to match <cstring> convention.
bool any(const char cs[], int (*condition)(int));
// The q prefix indicates a function that queries the user.
// Ask the user a question. Dump the response into answer.
void qCString(const char question[], char answer[],
const int ss = strSize);
// Bother the user until they enter a string containing graphical characters.
void qGCString(const char question[], char answer[],
const int ss = strSize);
// Bother the user until they enter a valid integer. Return the integer.
int qInt(const char question[]);
// Bother the user until they enter a positive integer. Return the integer.
int qPInt(const char question[]);
// Get a character from user. Consumes entire line.
char qChar(const char question[]);
// Return whether cs contains c.
bool contains(const char cs[], const char c);
// Bother user until they select an allowed character.
char qSel(const char question[], const char allowed[]);
// Bother the user until they enter y or n. Return true for y, false for n.
bool qYN(const char question[]);
// Bother the user for a path to a real file. Return the open file.
void qFH(const char question[], ifstream& fh);
// Bother the user for a path to a real file. Set fn to filename.
void qFN(const char question[], char fn[], const int ss = strSize);
#endif
--------------------------------------------------------------------
// exercise.cpp
Elliptical,06/10/17,40,400,135,great workout
Treadmill,06/12/17,20,150,120,doggin it
Stationary Bike,06/15/17,30,200,130,felt good
Elliptical,06/20/17,45,350,140,great-worked out with Mike
1,1,1,1,1,1
------------------------------------------------------------------------------
// exerciseJournal.cpp
#include "exerciseJournal.h"
// Populate an activity from a line in a csv.
bool parseActivity(exerciseData &ed, ifstream &fh) {
fh.getline(ed.name, strSize, ',');
fh.getline(ed.date, strSize, ',');
fh.getline(ed.note, strSize, ',');
fh >> ed.time;
fh.ignore();
fh >> ed.calories;
fh.ignore();
fh >> ed.maxHeartRate;
fh.ignore();
}
template <class A, class B, class C, class D, class E, class F>
void showRow(A name, B date, C time, D calories, E maxHeartRate, F note) {
cout << left
<< setw(17) << name
<< setw(10) << date
<< setw(6) << time
<< setw(10) << calories
<< setw(15) << maxHeartRate
<< setw(12) << note
<< ' ';
}
// Populate an activity from user input.
void queryActivty(exerciseData &ed) {
qGCString("What exercise activity did you do?", ed.name);
qGCString("What was the date (mm/dd/yy):", ed.date);
ed.time = qPInt("How many minutes?");
ed.calories = qPInt("How many calories did you burn?");
ed.maxHeartRate = qPInt("What was you max heart rate?");
qGCString("Do you have any notes to add?", ed.note);
}
// Ask the user which file to load. Set fileName.
void exerciseJournal::queryFilename() {
qFN("What is the name of the exercise data text file to load?", fileName);
}
// Load all the data from a csv. Return number of loaded elements.
int exerciseJournal::loadData() {
countAndIndex = 0;
ifstream fh(fileName);
while (true) {
parseActivity(eds[countAndIndex], fh);
if (!fh)
break;
countAndIndex++;
if (countAndIndex >= arraySize)
break;
}
return countAndIndex;
}
void exerciseJournal::writeData() {
ofstream of(fileName);
if (of.is_open())
for (int i = 0; i < countAndIndex; i++)
of << eds[i].name << ','
<< eds[i].date << ','
<< eds[i].time << ','
<< eds[i].calories << ','
<< eds[i].maxHeartRate << ','
<< eds[i].note << ' ';
else
cerr << "Could not open " << fileName << " for writing. ";
of.close();
}
// Ask user to enter an exercise. Increment count if user chooses to save.
void exerciseJournal::add() {
if (countAndIndex >= arraySize) {
cout << "You need to stop exercising. ";
} else {
queryActivty(eds[countAndIndex]);
if (qYN("Record the activity time and calories (y/n)?")) {
countAndIndex++;
cout << "Your activity info has been recorded. ";
}
}
}
// Search for specific exercise name. Print all matches.
bool exerciseJournal::search() {
char name[strSize];
qGCString("What activity would you like to search for?", name);
cout << "Here are the activities matching " << name << ": ";
showRow("Name", "Date", "Time", "Calories", "Max Heartrate", "Note");
for (int i = 0; i < countAndIndex; i++)
if (strcmp(name, eds[i].name) == 0)
showRow(eds[i].name, eds[i].date, eds[i].time,
eds[i].calories, eds[i].maxHeartRate, eds[i].note);
}
// Pretty print all the exercises.
void exerciseJournal::listAll() {
showRow("Name", "Date", "Time", "Calories", "Max Heartrate", "Note");
for (int i = 0; i < countAndIndex; i++)
showRow(eds[i].name, eds[i].date, eds[i].time,
eds[i].calories, eds[i].maxHeartRate, eds[i].note);
}
--------------------------------------------------------------------
//exerciseJournal.h
#ifndef _EXERCISE_JOURNAL_H_
#define _EXERCISE_JOURNAL_H_
#include "common.h"
#include <cstring>
#include <iostream>
#include <fstream>
using namespace std;
struct exerciseData {
char name[strSize];
char date[strSize];
char note[strSize];
int time;
int calories;
int maxHeartRate;
};
class exerciseJournal {
exerciseData eds[arraySize];
int countAndIndex;
char fileName[strSize];
public:
void queryFilename();
int loadData();
void writeData();
void add();
bool search();
void listAll();
};
#endif
----------------------------------------------------------------
// main.cpp
#include "common.h"
#include "exerciseJournal.h"
#include <iostream>
using namespace std;
int main() {
exerciseJournal journal;
cout << "Welcome to the exercise tracking program. ";
journal.queryFilename();
journal.loadData();
while (true) {
const char s = qSel("What would you like to do: (l)ist all, (s)earch by"
" name, (a)dd an exercise, or (q)uit? :", "lsaq");
if (s == 'l') {
journal.listAll();
} else if (s == 's') {
journal.search();
} else if (s == 'a') {
journal.add();
} else if (s == 'q') {
break;
}
}
journal.writeData();
cout << "Thank you for using the exercise tracking program. ";
return 0;
}
Explanation / Answer
main.cpp
---------------------------------------------------
/ qFH("What is the name of the exercise data text file to load?", fh);
#include <cstring>
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
// Reusable stuff -------------------------------
const int STRING_SIZE = 64;
const int LIST_SIZE = 4096;
// Return true if any char in cs satisfies condition.
// condition has type 'int (*condition)(int)' to match <cstring> convention.
bool any(const char cs[], int (*condition)(int)) {
for (int i = 0; cs[i]; i++)
if (condition(cs[i]))
return true;
return false;
}
// The q prefix indicates a function that queries the user.
// Ask the user a question. Dump the response into answer.
void qCString(const char question[], char answer[],
const int ss = STRING_SIZE) {
cout << question << ' ';
cin.getline(answer, ss);
}
// Bother the user until they enter a string containing graphical characters.
void qGCString(const char question[], char answer[],
const int ss = STRING_SIZE) {
qCString(question, answer, ss);
while (!any(answer, isgraph))
qCString("Try again:", answer, ss);
}
// Bother the user until they enter a valid integer. Return the integer.
int qInt(const char question[]) {
int resp;
bool fail;
cout << question << ' ';
while (true) {
cin >> resp;
fail = cin.fail();
cin.clear();
cin.ignore(STRING_SIZE, ' ');
if (!fail)
break;
cout << "Try again: ";
}
return resp;
}
// Bother the user until they enter a positive integer. Return the integer.
int qPInt(const char question[]) {
int response = qInt(question);
while (response <= 0)
response = qInt("Try again:");
return response;
}
// Get a character from user. Consumes entire line.
char qChar(const char question[]) {
cout << question << ' ';
const char resp = cin.peek();
cin.ignore(STRING_SIZE, ' ');
return resp;
}
// Return whether cs contains c.
bool contains(const char cs[], const char c) {
for (int i = 0; cs[i]; i++)
if (cs[i] == c)
return true;
return false;
}
// Bother user until they select an allowed character.
char qSel(const char question[], const char allowed[]) {
char resp = qChar(question);
while (!contains(allowed, resp))
resp = qChar("Try again:");
return resp;
}
// Bother the user until they enter y or n. Return true for y, false for n.
bool qYN(const char question[]) { return qSel(question, "yn") == 'y'; }
// Bother the user for a path to a real file. Return the open file.
void qFH(const char question[], ifstream& fh) {
char filename[STRING_SIZE];
qCString(question, filename);
fh.open(filename);
while (!fh.is_open()) {
qCString("Try again:", filename);
fh.open(filename);
}
}
// End of reusable stuff ------------------------
struct exerciseData {
char name[STRING_SIZE];
char date[STRING_SIZE];
char note[STRING_SIZE];
int time;
int calories;
int maxHeartRate;
};
// Populate an activity from user input.
void queryActivty(exerciseData &ed) {
qGCString("What exercise activity did you do?", ed.name);
qGCString("What was the date (mm/dd/yy):", ed.date);
ed.time = qPInt("How many minutes?");
ed.calories = qPInt("How many calories did you burn?");
ed.maxHeartRate = qPInt("What was you max heart rate?");
qGCString("Do you have any notes to add?", ed.note);
}
// Populate an activity from a line in a csv.
bool parseActivity(exerciseData &ed, ifstream &fh) {
fh.getline(ed.name, STRING_SIZE, ',');
fh.getline(ed.date, STRING_SIZE, ',');
fh.getline(ed.note, STRING_SIZE, ',');
fh >> ed.time;
fh.ignore();
fh >> ed.calories;
fh.ignore();
fh >> ed.maxHeartRate;
fh.ignore();
}
// Load all the data from a csv. Return number of loaded elements.
int loadData(exerciseData eds[LIST_SIZE]) {
int size = 0;
ifstream fh;
qFH("What is the name of the exercise data text file to load?", fh);
while (true) {
parseActivity(eds[size], fh);
if (!fh)
break;
size++;
if (size >= LIST_SIZE)
break;
}
return size;
}
template <class A, class B, class C, class D, class E, class F>
void showRow(A name, B date, C time, D calories, E maxHeartRate, F note) {
cout << left
<< setw(17) << name
<< setw(10) << date
<< setw(6) << time
<< setw(10) << calories
<< setw(15) << maxHeartRate
<< setw(12) << note
<< ' ';
}
// Search for specific exercise name. Print all matches.
void search(exerciseData eds[], int count) {
char name[STRING_SIZE];
qGCString("What activity would you like to search for?", name);
cout << "Here are the activities matching " << name << ": ";
showRow("Name", "Date", "Time", "Calories", "Max Heartrate", "Note");
for (int i = 0; i < count; i++)
if (strcmp(name, eds[i].name) == 0)
showRow(eds[i].name, eds[i].date, eds[i].time, eds[i].calories, eds[i].maxHeartRate, eds[i].note);
}
// Pretty print all the exercises.
void list(exerciseData eds[], int count) {
showRow("Name", "Date", "Time", "Calories", "Max Heartrate", "Note");
for (int i = 0; i < count; i++)
showRow(eds[i].name, eds[i].date, eds[i].time, eds[i].calories, eds[i].maxHeartRate, eds[i].note);
}
// Ask user to enter an exercise. Increment count if user chooses to save.
void add(exerciseData eds[], int &count) {
if (count >= LIST_SIZE) {
cout << "You need to stop exercising. ";
} else {
queryActivty(eds[count]);
if (qYN("Record the activity time and calories (y/n)?")) {
count++;
cout << "Your activity info has been recorded. ";
}
}
}
int main() {
exerciseData eds[LIST_SIZE];
int size;
cout << "Welcome to the exercise tracking program. ";
size = loadData(eds);
while (true) {
const char s = qSel("What would you like to do: (l)ist all, (s)earch by"
" name, (a)dd an exercise, or (q)uit? :", "lsaq");
if (s == 'l') {
list(eds, size);
} else if (s == 's') {
search(eds, size);
} else if (s == 'a') {
add(eds, size);
} else if (s == 'q') {
break;
}
};
cout << "Thank you for using the exercise tracking program. ";
return 0;
}
------------------------------------------------------------------------------
common.cpp
------------------------------------------------------------
#include "common.h"
// Return true if any char in cs satisfies condition.
// condition has type 'int (*condition)(int)' to match <cstring> convention.
bool any(const char cs[], int (*condition)(int)) {
for (int i = 0; cs[i]; i++)
if (condition(cs[i]))
return true;
return false;
}
// The q prefix indicates a function that queries the user.
// Ask the user a question. Dump the response into answer.
void qCString(const char question[], char answer[],
const int ss = strSize) {
cout << question << ' ';
cin.getline(answer, ss);
}
// Bother the user until they enter a string containing graphical characters.
void qGCString(const char question[], char answer[],
const int ss = strSize) {
qCString(question, answer, ss);
while (!any(answer, isgraph))
qCString("Try again:", answer, ss);
}
// Bother the user until they enter a valid integer. Return the integer.
int qInt(const char question[]) {
int resp;
bool fail;
cout << question << ' ';
while (true) {
cin >> resp;
fail = cin.fail();
cin.clear();
cin.ignore(strSize, ' ');
if (!fail)
break;
cout << "Try again: ";
}
return resp;
}
// Bother the user until they enter a positive integer. Return the integer.
int qPInt(const char question[]) {
int response = qInt(question);
while (response <= 0)
response = qInt("Try again:");
return response;
}
// Get a character from user. Consumes entire line.
char qChar(const char question[]) {
cout << question << ' ';
const char resp = cin.peek();
cin.ignore(strSize, ' ');
return resp;
}
// Return whether cs contains c.
bool contains(const char cs[], const char c) {
for (int i = 0; cs[i]; i++)
if (cs[i] == c)
return true;
return false;
}
// Bother user until they select an allowed character.
char qSel(const char question[], const char allowed[]) {
char resp = qChar(question);
while (!contains(allowed, resp))
resp = qChar("Try again:");
return resp;
}
// Bother the user until they enter y or n. Return true for y, false for n.
bool qYN(const char question[]) { return qSel(question, "yn") == 'y'; }
// Bother the user for a path to a real file. Return the open file.
void qFH(const char question[], ifstream& fh) {
char filename[strSize];
qCString(question, filename);
fh.open(filename);
while (!fh.is_open()) {
qCString("Try again:", filename);
fh.open(filename);
}
}
-------------------------------------------------------------------------------
common.h
------------------------------------------
#include <cstring>
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
const int strSize = 128;
const int arraySize = 100;
// Return true if any char in cs satisfies condition.
// condition has type 'int (*condition)(int)' to match <cstring> convention.
bool any(const char cs[], int (*condition)(int));
// The q prefix indicates a function that queries the user.
// Ask the user a question. Dump the response into answer.
void qCString(const char question[], char answer[],
const int ss = strSize);
// Bother the user until they enter a string containing graphical characters.
void qGCString(const char question[], char answer[],
const int ss = strSize);
// Bother the user until they enter a valid integer. Return the integer.
int qInt(const char question[]);
// Bother the user until they enter a positive integer. Return the integer.
int qPInt(const char question[]);
// Get a character from user. Consumes entire line.
char qChar(const char question[]);
// Return whether cs contains c.
bool contains(const char cs[], const char c);
// Bother user until they select an allowed character.
char qSel(const char question[], const char allowed[]);
// Bother the user until they enter y or n. Return true for y, false for n.
bool qYN(const char question[]);
// Bother the user for a path to a real file. Return the open file.
void qFH(const char question[], ifstream& fh);
-------------------------------------------------------------------------------
exerciseJournal.cpp
---------------------------------------------------------
#include "exerciseJournal.h"
// struct exerciseData {
// char name[strSize];
// char date[strSize];
// char note[strSize];
// int time;
// int calories;
// int maxHeartRate;
// };
// exerciseData eds[arraySize];
// int countAndIndex;
// char fileName[strSize];
// Populate an activity from a line in a csv.
bool parseActivity(exerciseData &ed, ifstream &fh) {
fh.getline(ed.name, strSize, ',');
fh.getline(ed.date, strSize, ',');
fh.getline(ed.note, strSize, ',');
fh >> ed.time;
fh.ignore();
fh >> ed.calories;
fh.ignore();
fh >> ed.maxHeartRate;
fh.ignore();
}
template <class A, class B, class C, class D, class E, class F>
void showRow(A name, B date, C time, D calories, E maxHeartRate, F note) {
cout << left
<< setw(17) << name
<< setw(10) << date
<< setw(6) << time
<< setw(10) << calories
<< setw(15) << maxHeartRate
<< setw(12) << note
<< ' ';
}
// Populate an activity from user input.
void queryActivty(exerciseData &ed) {
qGCString("What exercise activity did you do?", ed.name);
qGCString("What was the date (mm/dd/yy):", ed.date);
ed.time = qPInt("How many minutes?");
ed.calories = qPInt("How many calories did you burn?");
ed.maxHeartRate = qPInt("What was you max heart rate?");
qGCString("Do you have any notes to add?", ed.note);
}
// Load all the data from a csv. Return number of loaded elements.
int exerciseJournal::loadData() {
int countAndIndex = 0;
ifstream fh(fileName);
while (true) {
parseActivity(eds[countAndIndex], fh);
if (!fh)
break;
countAndIndex++;
if (countAndIndex >= arraySize)
break;
}
return size;
}
void exerciseJournal::writeData();
// Ask user to enter an exercise. Increment count if user chooses to save.
void exerciseJournal::add() {
if (countAndIndex >= arraySize) {
cout << "You need to stop exercising. ";
} else {
queryActivty(eds[countAndIndex]);
if (qYN("Record the activity time and calories (y/n)?")) {
countAndIndex++;
cout << "Your activity info has been recorded. ";
}
}
}
// Search for specific exercise name. Print all matches.
bool exerciseJournal::search() {
char name[strSize];
qGCString("What activity would you like to search for?", name);
cout << "Here are the activities matching " << name << ": ";
showRow("Name", "Date", "Time", "Calories", "Max Heartrate", "Note");
for (int i = 0; i < countAndIndex; i++)
if (strcmp(name, eds[i].name) == 0)
showRow(eds[i].name, eds[i].date, eds[i].time,
eds[i].calories, eds[i].maxHeartRate, eds[i].note);
}
// Pretty print all the exercises.
void exerciseJournal::listAll() {
showRow("Name", "Date", "Time", "Calories", "Max Heartrate", "Note");
for (int i = 0; i < countAndIndex; i++)
showRow(eds[i].name, eds[i].date, eds[i].time,
eds[i].calories, eds[i].maxHeartRate, eds[i].note);
}
---------------------------------------------------------------------------
exerciseJournal.h
----------------------------------
#include <cstring>
#include <iostream>
#include <fstream>
using namespace std;
const int strSize = 256;
const int arraySize = 128;
struct exerciseData {
char name[strSize];
char date[strSize];
char note[strSize];
int time;
int calories;
int maxHeartRate;
};
class exerciseJournal {
exerciseData eds[arraySize];
int countAndIndex;
char fileName[strSize];
public:
int loadData();
void writeData();
void add();
bool search();
void listAll();
};
-------------------------------------------------
exercise.txt
--------------
Elliptical,06/10/17,great workout,40,400,135
Treadmill,06/12/17,doggin it,20,150,120
Stationary Bike,06/15/17,felt good,30,200,130
Elliptical,06/20/17,great-worked out with Mike,45,350,140