【问题标题】:fstream <unable to read memory>. Trouble printing all items in listfstream <无法读取内存>。无法打印列表中的所有项目
【发布时间】:2015-06-01 09:18:22
【问题描述】:

我正在开发一个菜单驱动程序,让用户基本上可以跟踪他们的分配任务和截止日期。我的程序处理一个名为“tasks.txt”的文本文件,用户有 3 个选项用于与文本文件交互:输入新任务、显示文件中的所有任务或按课程查找任务。我的程序运行得相对不错,只是它似乎无法与文件完全交互。

下面是我的输出/输入文件: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

这是我的代码:

#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;
}

以下是调试器中的输出:

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

我已经研究了好几个小时的代码并在网上搜索类似的案例,但似乎我的 fstream 能够读取并加载每一行的课程名称,但跳过了其他所有的任务描述和截止日期任务。有人可以指出我正确的方向吗?

菜单的 Add 选项似乎可以将新的用户输入任务加载到缓冲区中,但应该将缓冲区中的所有任务保存到输出文件的 writefile 函数似乎也不起作用。

我会继续寻找解决方案,但非常感谢任何帮助!

【问题讨论】:

  • 首先,解决这个问题:while (!inFile.eof()) (its wrong; see here for why) 并检查所有您的 IO 操作。假设是一切的母亲......
  • 对于结构中的字符串,是否有不使用的原因,例如std::string?此外,大小为 201 的数组将为您提供最多 200 个字符长的字符串。
  • @Joachim Pileborg - 是的,我需要学习如何使用 cstrings 并且严格禁止使用字符串。我还打算使数组大小为 200 个字符长。这是不切实际/不必要的吗?什么是更合理的数字?我的导师最初给出了这个例子,但数组大小为 10。10 个数组会不断给我错误,所以我将它提升到 201
  • 如果目的是学习 C 字符串,那么你的数组是可以的。我只是想注意长度,因为MAXCHAR 定义之后的注释并不真正匹配。
  • 你被误导相信错误,告诉你的人不知道他们在说什么。 eofbit 具有设置它的特定条件。 See here 了解更多信息。简而言之,当您使用它时,eofbit 是根据对可实现的数据的请求设置的。

标签: c++ file menu fstream c-strings


【解决方案1】:

您的输入处理已损坏。我建议更多类似的内容:

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();
}

产生以下输出:

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

简而言之,您对第三个字段的请求也以 ';' 结尾(它在您的示例行中执行此操作)正在跳到下一行,直到找到请求的分隔符,因此包括中间换行符和下一行的第一个字段以供骑行。当前行的其余部分已被后续ignore 丢弃。

祝你好运。

【讨论】:

  • 谢谢!请问为什么将两者分开有帮助?什么时候需要这样做?
  • 感谢您的帮助和信息
猜你喜欢
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多