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.
Related
I want to read a string from cin until the return key is pressed. What's wrong with the following code? The output repeatedly says "Invalid response found, please enter again: " even when i enter single words.. I've updated the code..
int readInt() {
int num;
while (!(std::cin >> num)) {
std::cout << "Invalid response found, please enter again: ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return num;
}
string readString() {
string str;
while (std::getline(std::cin, str) && std::cin.fail()) {
std::cout << "Invalid response found, please enter again: ";
std::cin.clear();
std::cin.ignore();
}
return str;
}
DVD_Node* addNewDvd(DVD_Node *head) {
DVD_Node* temp = new DVD_Node;
int new_id = getNewID(head);
temp->id = new_id;
cout << "\n\n-- Add a new DVD to your collection --";
cout << "\n\nEnter movie name: ";
temp->title = readString();
cout << "\n\nEnter duration in minutes: ";
temp->duration = readInt();
cout << "\n\nEnter movie year: ";
temp->year = readInt();
cout << "\n\nEnter movie actor 1 name: ";
temp->actor1 = readString();
cout << "\n\nEnter movie actor 2 name: ";
temp->actor2 = readString();
temp->next = head;
changes_remaining = 1;
cout << "\n\nYour DVD Data has been added successfully.";
return temp;
}
The below test is not correct if you want to detect error :
std::getline(std::cin, str) && std::cin.fail()
Indeed, because getline return the input, you want to detect null input or errors with :
std::getline(std::cin, str) == 0 || std::cin.fail()
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".
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.
Okay so when I started using classes to make functions, it gives me an error file is invalid, normally doesn't if I don't use classes. If you run it, enter in some info, and then run it again, normally it should read in the data correctly, it still reads it in, but it says there's an error. I don't really know what I'm doing wrong, any tips? Thanks!
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
using namespace std;
const int TEMP_SIZE = 10;
const int NAME_SIZE = 100;
const int BREED_SIZE = 100;
const int DESC_SIZE = 250;
const int REASON_SIZE = 250;
const int ID_SIZE = 50;
//creating the struct
struct animal
{
char name[NAME_SIZE];
char ID[ID_SIZE];
char breed[BREED_SIZE];
float age;
float weight;
char desc[DESC_SIZE];
char reason[REASON_SIZE];
int day;
int month;
int year;
float length;
};
struct adopted
{
char hostName[100];
char hostAddress[100];
int numPets;
};
class petAdoption
{
public:
petAdoption();
//~petAdoption();
void enroll(animal newAnimal[]);
void read(animal newAnimal[]);
private:
int count;
int numPets;
int * pets;
};
petAdoption::petAdoption()
{
count = 0;
pets = NULL;
numPets = 0;
}
void petAdoption::enroll(animal newAnimal[])
{
cout << "Please enter your pet's name: ";
cin.get(newAnimal[count].name, NAME_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter a unique ID for your pet (combinations of numbers EG: 432FD3): ";
cin.get(newAnimal[count].ID, ID_SIZE, '\n');
cin.ignore(100, '\n');
cout << "What type of breed is your pet?: ";
cin.get(newAnimal[count].breed, BREED_SIZE, '\n');
cin.ignore(100, '\n');
cout << "How old is your pet?: ";
cin >> newAnimal[count].age;
cin.ignore(100, '\n');
cout << "How much does your pet weigh? (in LBS): ";
cin >> newAnimal[count].weight;
cin.ignore(100, '\n');
cout << "Please describe your pet's personality!: ";
cin.get(newAnimal[count].desc, DESC_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please explain why the pet is being put up for adoption: ";
cin.get(newAnimal[count].reason, REASON_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter your pet's day of birth (1-31): ";
cin >> newAnimal[count].day;
cin.ignore(100, '\n');
cout << "Please enter your pet's month of birth (1-12): ";
cin >> newAnimal[count].month;
cin.ignore(100, '\n');
cout << "Please enter your pet's year of birth (1900-2012) : ";
cin >> newAnimal[count].year;
cin.ignore(100, '\n');
cout << "Please enter the length of time your pet has spent in a shelter (in months): ";
cin >> newAnimal[count].length;
cin.ignore(100, '\n');
/*** WRITES the pet ID into the list of pets***/
ofstream write;
write.open("pets.txt", ios::app);
write << newAnimal[count].name << '\n';
write.close();
/*** WRITES EACH PET INFO ****/
//this opens the file / creates a file if it's not made yet
//and it writes the pet's information
write.open(newAnimal[count].name, ios::app);
write << newAnimal[count].name << '\n'
<< newAnimal[count].ID << '\n'
<< newAnimal[count].breed << '\n'
<< newAnimal[count].age << '\n'
<< newAnimal[count].weight << '\n'
<< newAnimal[count].desc << '\n'
<< newAnimal[count].reason << '\n'
<< newAnimal[count].day << '\n'
<< newAnimal[count].month << '\n'
<< newAnimal[count].year << '\n'
<< newAnimal[count].length << '\n';
//this closes the file
write.close();
}
void petAdoption::read(animal newAnimal[])
{
ifstream read;
//open the file apps.txt
read.open("pets.txt");
//if apps.txt doesn't exist, then print out this error
if(!read)
{
cout << "pets.txt doesn't exist! This is your first time!" <<endl;
}
//else if it does exist, read in the names and store them back
//into the struct member name(s)
else
{
//while the document isn't empty
//read in each line
while(!read.eof())
{
read.getline(newAnimal[count].name, NAME_SIZE, '\n');
++count;
}
count = count-1;
}
//close the file
read.close();
for (int i = 0; i < count; ++i)
{
//open the file of the name of the app
read.open(newAnimal[count].name);
//if the file doesn't exist
//then we probably deleted it
//without removing it from the apps.txt
//but it prints out an error
if( !read)
{
cout << "invalid file!" <<endl;
}
//however if the file does exist,
//read in each line and store them back
//into the struct members
while(!read.eof())
{
read.getline(newAnimal[count].name, NAME_SIZE, '\n');
read.ignore(100, '\n');
read.getline(newAnimal[count].ID, ID_SIZE, '\n');
read.ignore(100, '\n');
read.getline(newAnimal[count].breed, BREED_SIZE, '\n');
read.ignore(100, '\n');
read >> newAnimal[count].age;
read.ignore(100, '\n');
read >> newAnimal[count].weight;
read.ignore(100, '\n');
read.getline(newAnimal[count].desc, DESC_SIZE, '\n');
read.ignore(100, '\n');
read.getline(newAnimal[count].reason, REASON_SIZE, '\n');
read.ignore(100, '\n');
read >> newAnimal[count].day;
read >> newAnimal[count].month;
read >> newAnimal[count].year;
read >> newAnimal[count].length;
read.ignore(100, '\n');
}
//close the file
read.close();
}
}
int main()
{
animal newAnimal[10];
petAdoption adopt;
adopt.read(newAnimal);
adopt.enroll(newAnimal);
}
I think I know what's going on. when you say read.open("pets.txt"); it should say read.open("pets.txt"),ios::app because then it so snot delete the data it already stores. Also go in to your file explorer and search pets.txt and read it to see what's going on. I hope I helped you.
I figured some stuff out, but I suck at fstreams, and this is just killing me, for BREED + DESC, they have a space between them and name, but when I remove them completely then I get no spaces and it works again. Could someone tell me what I'm doing wrong?
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
using namespace std;
const int NAME_SIZE = 100;
const int BREED_SIZE = 100;
const int DESC_SIZE = 250;
const int REASON_SIZE = 250;
//creating the struct
struct animal
{
//members
char name[NAME_SIZE];
char breed[BREED_SIZE];
char desc[DESC_SIZE];
char reason[REASON_SIZE];
float age;
float weight;
int day;
int month;
int year;
float length;
};
class petAdoption
{
public:
petAdoption();
void enroll(animal newAnimal[], int & count);
void read(animal newAnimal[], int & count);
//void display(animal & newAnimal);
//void adopt(animal & newAnimal);
private:
};
petAdoption::petAdoption()
{
}
int main()
{
int count = 0;
animal * newAnimal = new animal[count];
petAdoption adopt;
adopt.read(newAnimal, count);
adopt.enroll(newAnimal, count);
delete[] newAnimal;
}
void petAdoption::read(animal newAnimal[], int & count)
{
int pets = 0;
ifstream read;
read.open("pets.txt");
if(!read)
{
cout << "Checking... File doesn't exist!" <<endl;
}
else
{
while(!read.eof())
{
read.getline(newAnimal[pets].name, NAME_SIZE, '\n');
read.ignore(100, '\n');
++pets;
}
count = pets + 1;
}
read.close();
for (int i = 0; i < pets; ++i){
read.open(newAnimal[i].name);
if( !read)
{
cout << "Checking... File doesn't exist!" <<endl;
}
else{
while(!read.eof())
{
read.getline(newAnimal[i].name, NAME_SIZE, '\n');
read.getline(newAnimal[i].breed, BREED_SIZE, '\n');
read.getline(newAnimal[i].desc, DESC_SIZE, '\n');
read.getline(newAnimal[i].reason, REASON_SIZE, '\n');
read.ignore(100, '\n');
read >> newAnimal[i].age;
read >> newAnimal[i].weight;
read >> newAnimal[i].day;
read >> newAnimal[i].month;
read >> newAnimal[i].year;
read >> newAnimal[i].length;
read.ignore(100, '\n');
}
}
read.close();
}
}
/*
ENROLL FUNCTION
*/
void petAdoption::enroll(animal newAnimal[], int & count)
{
//making a write variable
ofstream write;
//stores the name into the struct member
cout << "Please enter a name: ";
cin.get(newAnimal[count].name, NAME_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter a breed: ";
cin.get(newAnimal[count].breed, BREED_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter a desc: ";
cin.get(newAnimal[count].desc, DESC_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter a reason (EG: eats people): ";
cin.get(newAnimal[count].reason, REASON_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter an age (EG: 5): ";
cin >> newAnimal[count].age;
cin.ignore(100, '\n');
cout << "Please enter a weight (in LBS): ";
cin >> newAnimal[count].weight;
cin.ignore(100, '\n');
cout << "Please enter a day (EG: 2): ";
cin >> newAnimal[count].day;
cout << "Please enter a month (EG: 11): ";
cin >> newAnimal[count].month;
cout << "Please enter a year (EG: 2002): ";
cin >> newAnimal[count].year;
cout << "How long has the pet been in a shelter? (in months): ";
cin >> newAnimal[count].length;
//error
if(!write)
{
cout << "Invalid File" << endl;
}
else{
write.open(newAnimal[count].name, ios::app);
write << newAnimal[count].name << '\n'
<< newAnimal[count].breed << '\n'
<< newAnimal[count].desc << '\n'
<< newAnimal[count].reason << '\n'
<< newAnimal[count].age << '\n'
<< newAnimal[count].weight << '\n'
<< newAnimal[count].day << '\n'
<< newAnimal[count].month << '\n'
<< newAnimal[count].year << '\n'
<< newAnimal[count].length << '\n';
write.close();
}
if(!write)
{
cout << "Invalid File";
}
else {
write.open("pets.txt", ios::app);
write << newAnimal[count].name << '\n';
write.close();
}
}
As people mention (in response to an earlier version of this question already) you shall not use eof() to control your loop . Furthermore you shall test that you successfully received your input after you [attempted] to read it.
The problem with extra newlines at the end if a line is due to your use of get() rather than getline(): the former retains the stop character while the latter does not. You should als consider using std::string together with std::getline(): it reads arbitrary length strings.