Split Tasks into Functions - c++

I need to include 4 Functions WITH arguments in this code but I cant for the life of me think of a way to incorporate any that have an argument. Aren't function arguments usually used with integers for calculations? What are some examples of functions i could create for this code? If this is easy, excuse me for I am fairly new.
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
ofstream outFile;
ifstream inFile;
const int MAXCHAR = 101;
const int MAXLINE = 256;
struct task
{
char course[MAXCHAR];
char desc[MAXCHAR];
char date[MAXCHAR];
};
int main()
{
task track[MAXLINE];
bool quit = false;
while (quit == false)
{
char choice;
cout << "Welcome to my Task List: \n";
cout << "<a> to add task\n";
cout << "<s> to show the task list\n";
cout << "<f> to find a task by course name\n";
cout << "<q> to quit\n";
cin >> choice;
cin.ignore(100, '\n');
if (choice == 'a' || choice == 'A')
{
int count = 0;
outFile.open("tasks.txt", fstream::app);
cout << "Enter Course Name (less than 101 characters): ";
cin.get(track[count].course, MAXCHAR, '\n');
cin.clear();
cin.ignore(100, '\n');
cout << "Enter Task Description (less than 101 characters): ";
cin.get(track[count].desc, MAXCHAR, '\n');
cin.clear();
cin.ignore(100, '\n');
cout << "Enter due date (mm/dd/yyyy): ";
cin.get(track[count].date, MAXCHAR, '\n');
cin.clear();
cin.ignore(100, '\n');
char confirm;
cout << "\nAre you sure you want to add " << track[count].course << ";" << track[count].desc << ";"
<< track[count].date << "? (y/n)";
cin >> confirm;
if (confirm == 'y' || confirm == 'Y')
{
cin.clear();
cin.ignore(100, '\n');
outFile << track[count].course << ";" << track[count].desc << ";" << track[count].date << "\n";
cout << "Task has been added\n";
count++;
}
else if (confirm == 'n' || confirm == 'N')
{
cin.clear();
cin.ignore(100, '\n');
}
outFile.close();
}
else if (choice == 's' || choice == 'S')
{
int count = 0;
inFile.open("tasks.txt");
while (inFile)
{
inFile.getline(track[count].course, MAXLINE, ';');
inFile.getline(track[count].desc, MAXLINE, ';');
inFile.getline(track[count].date, MAXLINE, '\n');
if (inFile)
{
cout << track[count].course << ";" << track[count].desc << ";"
<< track[count].date << "\n";
count++;
}
}
inFile.close();
cin.clear();
}
else if (choice == 'f' || choice == 'F')
{
int count = 0;
char course[MAXCHAR];
cout << "Enter Course Name: ";
cin >> course;
inFile.open("tasks.txt");
while (inFile)
{
inFile.getline(track[count].course, MAXLINE, ';');
inFile.getline(track[count].desc, MAXLINE, ';');
inFile.getline(track[count].date, MAXLINE, '\n');
if (strcmp(track[count].course, course) == 0)
{
cout << track[count].course << ";" << track[count].desc
<< track[count].date << "\n";
count++;
}
}
inFile.close();
}
else if (choice == 'q' || choice == 'Q')
{
quit = true;
}
}
}

The cases you have for 'a' and 'A', 's' and 'S', 'f' and 'F' do not have much in common. So I do not think you can write one function to incorporate all of their functionality within one function, then based on a parameter do an action. You can, however, make your code more readable by enclosing all of the 3 different cases in one function that does not take a parameter and return void:
void Case_s_S()
{
int count = 0;
inFile.open("tasks.txt");
while (inFile)
{
inFile.getline(track[count].course, MAXLINE, ';');
inFile.getline(track[count].desc, MAXLINE, ';');
inFile.getline(track[count].date, MAXLINE, '\n');
if (inFile)
{
cout << track[count].course << ";" << track[count].desc << ";"
<< track[count].date << "\n";
count++;
}
}
inFile.close();
cin.clear();
}
One more suggestion I can give you, so you keep your "main" more neat, is to make use of function pointers. You can lookup std::function which is defined in . What you can do is have a map of chars and std::functions, which will look like std::map>. Then you can assign keys of 'a' and 'A' to point to value of function Case_a_A and so on and so forth. That way when the user presses the key, you just go to that key and call its value, which will be the function.

The point of methods is in a lot of ways to segment your code so that it's easier to read. Consider the parts of your code that could be self contained, and then separate that into functions of their own.
One basic example with your code might be:
if (choice == 'a' || choice == 'A')
DoStuff_a(<params>);
else if (choice == 's' || choice == 'S')
DoStuff_s(<params>);
//...
else if (choice == 'f' || choice == 'F')
DoStuff_f(<params>);
else if (choice == 'q' || choice == 'Q')
quit = true;
There are many ways to segregate your code (e.g., GetInput(), GetFileData(), etc.) - a pretty decent discussion on this can be found here. Just remember that function design is (a) largely up to personal preference, and (b) should be considered even for main()!
Many developers firmly believe that main() should be 95%+ function calls, and very little "worker-code".

Related

what is the reason user cannot enter input after the 2nd question and compiler finish the program?

I'd like to write a program that asks the user if he/she tends to work as a delivery service. If yes he/she should have some eligibilities. If the user have them he/she can be hired.
I've written some code, but when I compile and run it, after the user answered 2 first questions the cmd doesn't let the user to enter his/her answers for remaining questions (the cin code doesn't work anymore or as though there is no cin code.)
What's wrong with my code? Why cin doesn't work after 2 first question but it works at first 2 ones? How can I make it work?
#include <iostream>
using namespace std;
int main()
{
string answer{}, ssn1{}, a, b;
int age{0};
bool parental_consent{false}, ssn{false}, accidents{false};
cout << boolalpha;
cout << "Do you want to work as a local delivery (Y/N)? \n";
cin >> answer;
if (answer == "Y" || answer == "y")
{
cout << "Do you have any social security number(yes/no)? \n";
cin >> ssn;
ssn = ("yes" || "Yes");
cout << "How old are you? \n";
cin >> a;
cout << age;
cout << "If you're between 15 and 18 years old please answer this question: \n Do have parental "
"consent(yes/no)? \n";
cin >> ssn1;
// cout << parental_consent;
parental_consent = ("yes" || "Yes");
cout << "Have you ever had any accidents? \n";
cin >> b;
accidents = ("yes" || "Yes");
if ((age >= 18 || (age >= 16 && parental_consent)) && ssn && !accidents)
{
cout << "Yes, you can work.";
}
else if (age <= 15)
{
cout << "Sorry, your age is not eligble!\n";
}
}
else
cout << "sorry to hear that.";
cout << endl << endl << endl;
return 0;
}
From cppreference:
If the type of v is bool and boolalpha is not set, then if the value to be stored is ​0​, false is stored, if the value to be stored is 1, true is stored, for any other value std::ios_base::failbit is assigned to err and true is stored.
From the code, i can see that the second std::cin doesn't have boolalpha and is assigning to a bool value. This causes td::ios_base::failbit to be assigned to err, preventing other input. You have to do std::cin.clear(); to be able to use std::cin >> a; again.
If it still skips
Try using cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); after every std::cin to clear out whitespaces that causes it to return immediately.
It seems you wanted to use std::boolalpha to convert your questions into boolean. This obviously didn't work because you used it on std::cout to use it on input you need to use it on std::cin like this:
cin >> boolalpha >> ssn;
But you can't answer yes or Yes, you need to answer true or false so it's better to just std::cin >> answer and compare the string instead like this:
#include <iostream>
int main()
{
std::string answer{};
int age{ 0 };
bool parental_consent{ false }, ssn{ false }, accidents{ false };
std::cout << "Do you want to work as a local delivery (Y/N)? \n";
std::cin >> answer;
if (answer == "Y" || answer == "y")
{
std::cout << "Do you have any social security number(yes/no)? \n";
std::cin >> answer;
ssn = (answer == "yes" || answer == "Yes");
std::cout << "How old are you? \n";
std::cin >> answer;
age = atoi(answer.c_str());
if (age >= 15 && age <= 18) {
std::cout << "If you're between 15 and 18 years old please answer this question: \n Do have parental "
"consent(yes/no)? \n";
std::cin >> answer;
parental_consent = (answer == "yes" || answer == "Yes");
}
std::cout << "Have you ever had any accidents? \n";
std::cin >> answer;
accidents = (answer == "yes" || answer == "Yes");
if ((age >= 18 || (age >= 16 && parental_consent)) && ssn && !accidents)
{
std::cout << "Yes, you can work.";
}
else if (age <= 15)
{
std::cout << "Sorry, your age is not eligble!\n";
}
}
else {
std::cout << "sorry to hear that.";
}
std::cout << std::endl << std::endl << std::endl;
return 0;
}
cin>>answer;
if(answer=="yes"||"Yes"== answer)
ssn=true;
This line will only make the left of the = being true:
ssn = ("yes" || "Yes");

input validation c++ with menu

i have this menu like so.
int choice;
cout <<"1: Exit\n2: Print Mark\n3: Print Name"<<endl;
cin >> choice;
while (choice != 1 && choice != 2 && choice != 3)
{
cout << "Invalid Choice <<endl;
cout <<"1: Exit\n2: Print Mark\n3: Print Name"<<endl;
cin >> choice;
}
so that is what i have so far but when ever i input letters it terminates is there a easier way to test for invalid inputs.
i know there is something like cin.fail()
but not sure on how to implement it
This simple line skip when it's a bad input.
td::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore and skip bad input
okay you can structure your code like this
do {
if (choice ==1)
{
exit(1);
}else if (choice==2)
{
//code
}
}else if (choice==3)
{
//code
}
}else if (choice==4)
{
//code
}else{
cout <<"Please enter a correct option"<<endl;
cin.clear();
string choice;
cin>>choice;
}
}while(!cin.fail())
This works 100%
If it is possible for changing that int to char you can do like this.
Its easy this way.
char choice;
cout <<"1: Exit\n2: Print Mark\n3: Print Name"<<endl;
cin >> choice;
while (choice != '1' && choice != '2' && choice != '3')
{
cout << "Invalid Choice <<endl;
cout <<"1: Exit\n2: Print Mark\n3: Print Name"<<endl;
cin >> choice;
}
If you want to get the choice back as int, you can do
int choiceInt = choice - '0';
First take a string as input then try to cast it to int to see if it is valid. You can make it like this (if using c++11):
#include <iostream>
#include <cstring>
using namespace std;
int main() {
int choice = -1;
while (true) {
string input;
cout << "1: Exit\n2: Print Mark\n3: Print Name" << endl;
cin >> input;
try {
choice = stoi(input);
if (choice > 0 && choice < 4) {
break;
}
} catch (const std::exception& e) {
}
cout << "Invalid input" << endl;
}
cout << "Your valid choice: " << choice << endl;
}

file i/o problems with task tracker

I have been trying to make a task tracker console application that is able to perform three different functions --> add a task, show the task list, and search task list by classname. My code for adding a task works fine, but im trying to work out how to display the task list properly, but it keeps outputting only part of the tasks.
for example if you add the task CS162;Lab Due;04/20/2014 and the task
MTH251;Quiz;04/22/2014. If you close the file and look at it, they were written to tasks.txt fine, but when i go to read them back, the output looks like:
Due04/20/2014
MTH251Quiz
which is only a fraction of the desired output.
I also need to search by name but I think I can figure that out easily after I figure out the other issue
my textfile looks like this:
CS162;Lab Due;04/20/2014
MTH251;Quiz;04/22/2014
and my code looks like this:
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
ofstream outFile;
ifstream inFile;
const int MAXCHAR = 101;
const int MAXLINE = 256;
struct task
{
char course[MAXCHAR];
char desc[MAXCHAR];
char date[MAXCHAR];
};
int main()
{
task track;
bool quit = false;
while (quit == false)
{
char choice;
cout << "Welcome to my Task List: \n";
cout << "<a> to add task\n";
cout << "<s> to show the task list\n";
cout << "<f> to find a task by course name\n";
cout << "<q> to quit\n";
cin >> choice;
cin.ignore(100, '\n');
if (choice == 'a' || choice == 'A')
{
outFile.open("tasks.txt", fstream::app);
cout << "Enter Course Name (less than 101 characters): ";
cin.get(track.course, MAXCHAR, '\n');
cin.clear();
cin.ignore(100, '\n');
cout << "Enter Task Description (less than 101 characters): ";
cin.get(track.desc, MAXCHAR, '\n');
cin.clear();
cin.ignore(100, '\n');
cout << "Enter due date (mm/dd/yyyy): ";
cin.get(track.date, MAXCHAR, '\n');
cin.clear();
cin.ignore(100, '\n');
char confirm;
cout << "\nAre you sure you want to add " << track.course << ";" << track.desc << ";" << track.date << "? (y/n)";
cin >> confirm;
if (confirm == 'y' || confirm == 'Y')
{
cin.clear();
cin.ignore(100, '\n');
outFile << track.course << ";" << track.desc << ";" << track.date << "\n";
cout << "Task has been added\n";
}
else if (confirm == 'n' || confirm == 'N')
{
cin.clear();
cin.ignore(100, '\n');
}
outFile.close();
}
else if (choice == 's' || choice == 'S')
{
inFile.open("tasks.txt");
char str[MAXCHAR];
while (inFile >> str)
{
inFile.getline(track.course, MAXLINE, ';');
inFile.getline(track.desc, MAXLINE, ';');
inFile.getline(track.date, MAXLINE, ';');
cout << track.course << track.desc << track.date;
}
inFile.close();
cin.clear();
cin.ignore(100, '\n');
}
else if (choice == 'f' || choice == 'F')
{
char course[MAXCHAR];
cout << "Enter Course Name: ";
cin >> course;
inFile.open("tasks.txt");
while (!inFile)
{
}
inFile.close();
}
else if (choice == 'q' || choice == 'Q')
{
cin.clear();
cin.ignore(100, '\n');
quit = true;
}
}
}
edit:
I now have the "show task list" working properly, but can somebody explain to me why using something like this doesnt work for the "search course"??
else if (choice == 'f' || choice == 'F')
{
char course[MAXCHAR];
cout << "Enter Course Name: ";
cin >> course;
inFile.open("tasks.txt");
while (inFile)
{
inFile.getline(track.course, MAXLINE, ';');
inFile.ignore(100, '\n');
while (strcmp(course, track.course) != 0)
{
cout << track.course;
}
}
}
while (inFile >> str) {
inFile.getline(track.course, MAXLINE, ';');
inFile.getline(track.desc, MAXLINE, ';');
inFile.getline(track.date, MAXLINE, ';');
std::cout << track.course << track.desc << track.date;
}
The first line will read all chars into str until it hits the first whitespace, so if your input is
CS162;Lab Due;04/20/2014
MTH251;Quiz;04/22/2014
it will read up to and including Lab into str.
The next three lines will read until they hit ;, so your track struct will look as follows
course = "Due"
desc = "04/20/2014\nMTH251" // note the newline
date = "Quiz"
Changing the while loop and changing the last extractor should fix this:
while (inFile) {
inFile.getline(track.course, MAXLINE, ';');
inFile.getline(track.desc, MAXLINE, ';');
inFile.getline(track.date, MAXLINE, '\n');
if (inFile)
std::cout << track.course << track.desc << track.date;
}
although it's worth mentioning that there are a number of things you can do here to simplify the code, including using std::string instead of char arrays, like this for instance.

Why is my loop acting the opposite of how it's supposed to, based on the user input?

Here is what is meant to happen: After the user is prompted with, "Would you like to enter another name?" if the user enters 'Y' they should be prompted to add another name. Instead, the program runs the loop that starts after cin << response, which I thought I set the condition to only run if the user doesn't enter 'Y,' 'y,' 'N,' or 'n.' In fact the program seems to be doing the opposite of what I want it to no matter how the user answers that question.
#include <iostream>
#include <cstring>
using namespace std;
int main(){
const int MAX_NUM = 101;
char name[MAX_NUM];
char response;
char nameCorrect = 'n';
double total = 0;
do{
do{
cout << "Please enter name: ";
cin >> name;
cin.ignore(100, '\n');
cout << "It looks like you entered " << name
<< ". Is this correct? (Y/N) " << endl;
cin >> nameCorrect;
while (nameCorrect != 'y' & nameCorrect != 'Y' & nameCorrect != 'n' & nameCorrect != 'N')
{
cin.clear();
cin.ignore(200, '\n');
cout << '\n' << "If " << name <<
" is what you are trying to enter, "
<< "please enter Y." << '\n'
<< "If " << name << " is not correct, plese enter N."
<< '\n' << "(Y/N): ";
cin >> nameCorrect;
}
} while (nameCorrect == 'n' || nameCorrect == 'N');
cout << "Would you like to enter another name? (Y/N) ";
cin >> response;
if (response != 'y' & response != 'Y' & response != 'n' & response != 'N');
{
cin.clear();
cin.ignore(200, '\n');
cout << '\n' << "If you would like to enter another name Y."
<< '\n' << "If you are finished, please enter N. " << '\n' << "(Y/N): ";
cin >> response;
}
} while (response == 'y' || response == 'Y');
return 0;
}
For this code:
if (response != 'y' & response != 'Y' & response != 'n' & response != 'N');
Remove the ; at the end
the ; is what the if is conditionally executing and the block below will always run.
if (response != 'y' & response != 'Y' & response != 'n' & response != 'N');
& is the bitwise operator in C/C++, use && for boolean comparisons. Also, the semicolon at the end means you want the if to have exactly no effect, and always execute the following code block no matter the outcome of this line.

does not stop at, clearing cin creates infinite loop

I am a beginner at C++ and I have read various problems and solutions, but I still cannot get my code to work! The problem is that if i do not include the commented-out cin.clear() or cin.synch() my code does not stop at the beginning getline. When i do add them, it loops infinitely. Is there something that I am not including? Here is my source code:
#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string inputFileName, outputFileName, inData, outData, inWord, outWord;
ifstream inFile, testStream;
ofstream outFile;
bool outPutOpened = false;
char outChar;
int shiftNum = 0, idx = 0;
do {
inWord.clear();
outWord.clear();
//cin.clear();
//cin.sync();
cout << "Available options: " << endl;
cout << "1. ENCRYPT - Encrypt a file using Caesar Cypher" << endl // menu
<< "2. Quit - Exit the program" << endl << endl;
cout << " Enter keyword or option index: ";
getline(cin, inWord); // get option
outWord.resize(inWord.length());
transform(inWord.begin(), inWord.end(), outWord.begin(), ::toupper); //capitalize
if (outWord.compare("ENCRYPT") == 0 || outWord.compare("1") == 0) {
cout << "CAESAR CYPHER PROGRAM" << endl
<< "======================" << endl << endl;
do {
cout << "Provide the input file name: ";
getline(cin, inputFileName);
inFile.open(inputFileName.c_str());
if (inFile.fail()) {
cout << "Cannot open file, please try again!" << endl;
inFile.clear();
}
}
while (!inFile.is_open());
getline(inFile, inData);
do {
cout << "Provide the output file name: ";
cin >> outputFileName;
testStream.clear();
testStream.open(outputFileName.c_str());
if(testStream.good()) {
cout << "That file already exists, choose another" << endl;
testStream.clear();
testStream.close();
}
else {
testStream.clear();
testStream.close();
outFile.open(outputFileName.c_str());
if (outFile.good()) {
outPutOpened = true;
}
}
}
while (!outPutOpened);
cout << "Enter the shift number: ";
cin >> shiftNum;
for (idx = 0; idx <= inData.length() - 1; idx++) {
if (inData[idx] >= 'a' && inData[idx] <= 'z') {
outChar = (((inData[idx] - 'a') + shiftNum) % 26) + 'a';
outFile.put(outChar);
}
else if (inData[idx] >= 'A' && inData[idx] <= 'Z'){
outChar = (((inData[idx] - 'A') + shiftNum) % 26) + 'A';
outFile.put(outChar);
}
else {
outFile.put(inData[idx]);
}
}
}
else if (outWord.compare("2") == 0 || outWord.compare("QUIT") == 0) {
break;
}
else {
cout << inWord << " is an unrecognized option, please try again"
<< endl;
}
}
while (outWord.compare("2") || outWord.compare("QUIT"));
return 0;
}
The problem that in all your places where you use something like:
cin >> something;
the new line character remains in cin, so that what you will be reading next. Just every time you are finished reading from a line with this, write
string trash;
getline(cin, trash);
like:
cin >> something;
string trash;
getline(cin, trash);
and then the new line character won't remain in cin and you will start with a fresh line.