2

I'm working on a menu driven program that has users basically keep track of their assignment tasks and due dates. My program deals with a text file titled "tasks.txt", and the user has 3 options for interacting with the text file: Enter a new task, Display all the tasks in the file, or Find a task by course. My program runs relatively nicely except that it doesn't seem to be able to fully interact with the file.

Below is my output/input file: tasks.txt

CS162;Finish Project 2;04/10/2015
CS162;Finish Project 3;04/20/2015
CS162;Finish Project 4;05/10/2015
CS162;Finish Project 5;05/20/2015

Here's my code:

#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include <fstream>
#include <iostream>

using namespace std;

//Global constants
const int CAP = 100;
const int MAXCHAR = 201; // Task description can be a max of 200 characters in case its a long description (ie: specific instructions)

//Task struct
struct Task
{
    char courseName[MAXCHAR];
    char taskDescrip[MAXCHAR];
    char dueDate[MAXCHAR];
};

//function prototypes
void openFile(ifstream &inFile);
void loadData(ifstream &inFile, Task tasks[], int &listSize);
void exeCommand(char option, Task tasks[], int &listSize);
void displayMenu();
char readOption();
void getUserTask(Task &tempTask);
void addUserTask(Task tasks[], int &listSize, Task tempTask);
void printTasks(Task tasks[], const int listSize);
void writeFile(ofstream &outFile, Task tasks[], const int listSize);


//Main function
int main()
{
    int listSize = 0; //keep track of list size
    ofstream outFile; //output file stream variable
    ifstream inFile; //input file stream variable
    Task tasks[CAP]; //array of tasks
    char option; // user menu input for option
    openFile(inFile); //open up tasks.txt
    loadData(inFile, tasks, listSize); //load the data while in file into the array of tasks
    do
    {
        displayMenu();
        option = readOption();
        exeCommand(option, tasks, listSize);
    } while (tolower(option) != 'q');
    return 0;
}

//open the file
void openFile(ifstream &inFile)
{
    inFile.open("tasks.txt");
    if (!inFile)
    {
        cout << "file not open" << endl;
        exit(0);
    }
}

//load the data from the file to the array
// parameters: 
void loadData(ifstream &inFile, Task tasks[], int &listSize)
{
    while (!inFile.eof())
    {
        inFile.get(tasks[listSize].courseName, MAXCHAR, ';');
        inFile.ignore(200, ';');
        inFile.get(tasks[listSize].taskDescrip, MAXCHAR, ';');
        inFile.ignore(200, ';');
        inFile.get(tasks[listSize].dueDate, MAXCHAR, ';');
        inFile.ignore(200, '\n');
        listSize++;
    }
    inFile.close();
}

void displayMenu()
{
    cout << "Welcome to TaskTracker v.1" << endl;
    cout << "(a) Add a task" << endl;
    cout << "(l) List all tasks" << endl;
    cout << "(f) Find any tasks by course" << endl;
    cout << "(q) Quit" << endl << endl;
}

char readOption()
{
    char option;
    cout << "Please make a selection: ";
    cin.get(option);
    cin.ignore(100, '\n');
    return option;
}

void exeCommand(char option, Task tasks[], int &listSize)
{
    Task tempTask;// created object tempTask
    switch (tolower(option))
    {
    case 'a':
        cout << "You chose to add a task!" << endl;
        getUserTask(tempTask);//used aVideo as a parameter for getVideo
        addUserTask(tasks, listSize, tempTask);//tempTask 
        cout << endl << endl;
        break;
    case 'l':
        cout << "You chose print tasks!" << endl;
        printTasks(tasks, listSize);
        cout << endl << endl;
        break;
    case 'f':
        cout << "You chose to find an item by course!"<< endl;

        cout << endl << endl;
        break;
    case 'q':
        return;
    default:
        cout << "Invalid input!" << endl;
    }
}

void getUserTask(Task &tempTask)
{
    cout << "Please enter the course name {less than 101 characters): ";
    cin.get(tempTask.courseName, MAXCHAR);//user enters the course name
    cin.ignore(100, '\n');//ignores the next 100 characters or until newline

    cout << "Please enter a brief description of your task (less than 101 characters): ";
    cin.get(tempTask.taskDescrip, MAXCHAR);//user enters the task description
    cin.ignore(100, '\n');//ignores the next 100 characters or until newline

    cout << "Please enter the due date of this task. (mm/dd/yyy): ";
    cin.get(tempTask.dueDate, MAXCHAR);//user enters the task description
    cin.ignore(100, '\n');

}

void addUserTask(Task tasks[], int &listSize, Task tempTask)
{
    tasks[listSize++] = tempTask;
}

//prints the task list
void printTasks(Task tasks[], const int listSize)
{
    for (int i = 0; i < listSize; i++)
    {
        cout << tasks[i].courseName << ';' << tasks[i].taskDescrip << ';' << tasks[i].dueDate << endl;
    }
}

//writes to file at the end of the program
void writeFile(ofstream &outFile, Task tasks[], const int listSize)
{
    outFile.open("tasks.txt");
    for (int i = 0; i < listSize; i++)
    {
        outFile << tasks[i].courseName << ';' << tasks[i].taskDescrip << ';' << tasks[i].dueDate << endl;
    }
    return;
}

The following is the output in the debugger:

Welcome to TaskTracker v.1
(a) Add a task
(l) List all tasks
(f) Find any tasks by course
(q) Quit

Please make a selection: l
You chose print tasks!
CS162;Finish Project 2;04/10/2015
CS162
CS162;Finish Project4;05/10/2015
CS162

Welcome to TaskTracker v.1
(a) Add a task
(l) List all tasks
(f) Find any tasks by course
(q) Quit

I have been peeling over the code for hours now and searching online for similar cases, but it seems like my fstream is able to read and load the course name for every line, but skips the task description and due date for every other task. Can someone please point me in the right direction?

The Add option of the menu seems to do okay with loading new user input tasks into the buffer, but the writefile function thats supposed to save all tasks in the buffer to the output file doesn't seem to work either.

I'll continue to look for a solution but any help is greatly appreciated!

  • 3
    First, fix this: `while (!inFile.eof())` ([its wrong; see here for why](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong)) and check **all** your IO operations. Assumption is the mother of all... – WhozCraig Jun 01 '15 at 09:20
  • 1
    For the strings in your structure, is there a reason you don't use e.g. `std::string`? Also, an array size of 201 will give you strings that can be at most *200* characters long. – Some programmer dude Jun 01 '15 at 09:21
  • @Joachim Pileborg - Yes, I am required to learn how to use cstrings and am strictly banned from using string. I was also kind of aiming to make the array size 200 characters long. Is that impractical/unneccessary? What would be a more reasonable number? My instructor initially gave that example but made the array size 10. An array of 10 would constantly give me errors so I jacked it up to 201 – Thomas Hamada Jun 01 '15 at 09:24
  • If the purpose is, among other things, to learn C-strings, then your arrays are okay. I just wanted to note the length because the comment after the `MAXCHAR` definition doesn't really match. – Some programmer dude Jun 01 '15 at 09:29
  • woops! Ha good catch. I don't think I was thinking there. – Thomas Hamada Jun 01 '15 at 09:31
  • @WhozCraig - Hey I'm having some trouble understanding the thread you provided for me. I was lead to believe that when using eof, the program will basically eat each line of the input file and check after each /n whether or not its the end of the file. If not, it continues to eat. In that thread, it sounded more like the eof or !eof is only found AFTER the program runs through the entire file. Could you possibly clarify? – Thomas Hamada Jun 01 '15 at 09:44
  • 1
    You were lead to believe wrong, and whoever told you that doesn't know what they're talking about. `eofbit` has specific conditions that set it. [See here](http://en.cppreference.com/w/cpp/io/ios_base/iostate) for more info. The short of it is as you're using it, eofbit is set upon request for data that is *not* fulfillable. – WhozCraig Jun 01 '15 at 09:48
  • @ThomasHamada: No need to clarify: you appear to have read that "thread" correctly, and were previously taught incorrectly. – Lightness Races in Orbit Jun 01 '15 at 09:55

1 Answers1

-1

Your input processing is marred. I suggest something more along these lines:

void loadData(ifstream &inFile, Task tasks[], int &listSize)
{
    while (inFile.get(tasks[listSize].courseName, MAXCHAR, ';') &&
        inFile.ignore(200, ';') &&
        inFile.get(tasks[listSize].taskDescrip, MAXCHAR, ';') &&
        inFile.ignore(200, ';') &&
        inFile.get(tasks[listSize].dueDate, MAXCHAR, '\n'))
    {
        inFile.ignore(200, '\n');
        listSize++;
    }
    inFile.close();
}

Produces the following output:

Welcome to TaskTracker v.1
(a) Add a task
(l) List all tasks
(f) Find any tasks by course
(q) Quit

Please make a selection: l
You chose print tasks!
CS162;Finish Project 2;04/10/2015
CS162;Finish Project 3;04/20/2015
CS162;Finish Project 4;05/10/2015
CS162;Finish Project 5;05/20/2015

In short, your request for the third field also terminating with a ';' (which it does not do on your sample lines) was skipping to the next line until it found the requested delimiter, thus including the intermediate newline and first field of the next line along for the ride. The remainder of the now-current line was discarded with the follow-up ignore.

Best of luck.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141