1

所以我现在已经很久了,也许这就是为什么我无法弄清楚这一点。但是我这里的代码只在第一次执行时起作用,即,因为有一个大约有 4 个选项的菜单,所以它只对第一个被选中的选项起作用。当 do while 循环启动并再次显示菜单时,无论您选择什么,它都会重新显示菜单。我已经分析了 do while 循环,但我很确定这没有任何问题。我最近才开始学习文件 I/O,所以也许我错过了一些东西。任何帮助将非常感激。谢谢。

这是代码:

电话簿.h

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>

using namespace std;

class Phone
{ 
public:
void display_phonebook(ifstream& in_stream);// phonebook is the text file 
void display_backup(string a[], int size);// backup copy is a string array
void datacopy(ifstream& in_stream, string a[]);// to copy the phonebook to the array
int numberOfLines(ifstream& in_stream);// to check number of lines in the text file
};

电话簿.cpp

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include "Phonebook.h"

using namespace std;

void Phone::datacopy(ifstream& in_stream, string a[])
{
int i=0;
while(in_stream.good())
{
    string line;
    getline(in_stream, line);
    a[i]=line;
    i++;
}
int s=i;
for(int x=0;x<s;x++)
{
    cout<<a[x]<<endl;
}
}


int Phone::numberOfLines(ifstream& in_stream)
{
int count=0;
while(!in_stream.eof())
{
    string line;
    getline(in_stream, line);
    count++;
}
return count;
}

void Phone::display_phonebook(ifstream& in_stream)
{
while(!in_stream.eof())
{
    string line;
    getline(in_stream, line);
    cout<<line<<endl;
}
}

void Phone::display_backup(string a[], int size)
{
for(int i=0;i<size;i++)
{
    cout<<a[i]<<endl;
}
cout<<endl;
}

主文件

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include "Phonebook.h"

using namespace std;

int main()
{
Phone p;
int size=0;
ifstream fin;
ofstream fout;
char file[50], ch;
string backup[50];
int flag=0;
do
{
    cout<<"Enter the name of the file: "<<endl;
    cin>>file;
    fin.open(file);
    cout<<endl;
    if(fin.fail())
    {
        cout<<"File not found!"<<endl<<endl;
        cout<<"Try Again? (Y/N)"<<endl;
        cin>>ch;
        if(ch=='N' || ch=='n')
        {
            cout<<"Terminating..."<<endl;
            system("PAUSE");
            exit(1);
        }
    }
    else
    {
        flag=1;
    }
}
while((ch=='Y' || ch=='y') && flag==0);
cout<<"Success! File Opened"<<endl<<endl;
int choice;
do
{
    cout<<"1 - Display phonebook"<<endl;
    cout<<"2 - Display backup copy"<<endl;
    cout<<"3 - Update backup copy"<<endl;
    cout<<"4 - Exit"<<endl;
    cout<<"Enter your choice:  ";
    cin>>choice;
    if(choice==1)
    {
        p.display_phonebook(fin);
    }
    else if(choice==2)
    {
        size=p.numberOfLines(fin);
        p.display_backup(backup, size);
    }
    else if(choice==3)
    {
        p.datacopy(fin, backup);
    }
} 
while(choice!=4);
fin.close();
fout.close();
system("PAUSE");
return 0;
}
4

4 回答 4

3

所以要注意的一件事是,当您将 ifstream 发送到函数并调用 getline 时,“缓冲区”是高级的。因此,如果不再次打开缓冲区,您将无法重新读取该行。您需要重新组织代码以解决此问题,或者在内部保存文件中的数据,而不是在显示期间尝试重新读取它。

于 2012-05-08T15:50:06.230 回答
3

1)你不应该发布这么多代码。您应该发布一个最小的完整示例;也就是说,尽可能减少代码,同时仍然会产生不良行为。最终,要么错误会变得明显,要么你会得到更小更简单的东西供我们梳理。

2)您太累了,无法删除所有不相关的代码?没问题,只是一开始就不要写。从小处着手,逐步构建,在每个阶段进行测试,永远不要添加不起作用的代码。你不应该在没有发现问题的情况下让代码变得这么大。

3)

void Phone::display_phonebook(ifstream& in_stream)
{
  while(!in_stream.eof())
    {
      string line;
      getline(in_stream, line);
      cout<<line<<endl;
    }
}

这将显示文件的内容一次。然后文件流在文件的末尾,就像盯着一本书的封底一样。当您再次调用该函数时,它不会给您更多信息。您必须将文件的内容存储在变量中,或者关闭并重新打开流(或倒带,但这是一种更高级的技术,不推荐)。

于 2012-05-08T15:54:38.817 回答
0

您的代码存在许多问题。

您的代码仅“工作”一次的原因是因为您第一次读取文件完成,将输入留在文件末尾,因此进一步读取将失败。您应该预先将文件完全读入内存,然后将图像(可能是std::vector<std::string>各种函数)传递给,或者您应该在每个函数中创建一个新std::ifstream对象,作为局部变量(并且 std::ifstream在 main 中没有对象循环)。否则,您必须清除错误并在每个函数之前查找流的开头。

你做的另一件事是使用in_stream.good()or !in_stream.eof()作为循环的控制条件。然后,至少在datacopyand中display_phonebook,使用读取的字符串 std::getline而不验证是否std::getline成功。通常,这将导致最后一行被处理两次。 std::istream::good()是一个毫无价值的功能,st::istream::eof() 只有您检测到失败后才有意义。编写循环的正确方法是:

std::string line;
while ( std::getline( in_stream, line ) ) {
    //  ...
}

Phone::datacopy如果输入文件超过 50 行,则具有未定义的行为(并且可能会崩溃)。在这里使用std::vector<std::string> ,在函数顶部清除它,然后调用 push_back读取的每一行。

在阅读命令时,您还需要进行一些错误处理。例如,如果用户输入一个'a',您将进入一个无限循环。我可能也会std::getline用于交互式输入,分别解析该行。这样,实际输入不会进入错误状态,如果用户输入垃圾,则必须清除该错误状态。(如果他输入类似 的"Display phonebook"内容,您不必担心删除输入中的所有多余字符。)

最后,如果您使用 which uses定义一个用户类Line,您的大多数函数将简化为对、 using 和的一次调用 。operaator>>getlinestd::copystd::istream_iterator<Line>

哦,你可以用 aswitch代替if/else if链条。

于 2012-05-08T17:15:44.127 回答
0

嗯,谢谢大家的建议。但是,是的,问题是当控件传递给第二个函数时输入流卡在文件末尾。最简单的解决方法是在流到达文件末尾后关闭并重新打开流,这就是我所采用的。另外,我从你们那里了解了很多其他东西,这将帮助我成为一个更好的编码器(我希望!)。此外,肯定会研究代码的一些异常处理(感谢@James Kanze)。好吧,祝大家编码愉快。

于 2012-05-09T00:18:55.680 回答