【问题标题】:C++, Infinite while loopC++,无限while循环
【发布时间】:2013-11-06 01:03:31
【问题描述】:

我的 C++ 项目的目的是输出一个包含由简单字符组成的图片的文件。

我的项目的第一部分要求我“包含一个从输入文件读取命令并返回表示所读取命令的整数值的函数”。那是我的 takeCommand 函数。看起来效率极低,但如果我理解正确的话,我想这是必要的。

当前的问题是我的 main 函数中的 while 循环运行一个无限循环。输出文本“Works”时,它会不断重复。我的意图是制作一个文件结束控制循环。在takeCommand函数内部,当读取到最后一行时,takeCommand函数停止运行,while循环结束。

我需要关于如何让 while 循环工作而不不断重复的想法。

我目前拥有的是:

    int takeCommand(int& num, int& cmd);

    ifstream infile;
    ofstream outfile;

    int main()
    {
         const int MAX_FOR = 3;
         string str;
         int num, cmd;
         infile.open("DrawingInput_01.txt");
         outfile.open("DrawingOutput_01.txt");

         for (int i = 0; i < MAX_FOR; i++)
         {
             getline(infile,str);
         }

         takeCommand(num,cmd);
         while(infile)
         {
           cout << "Works";
           /*switch(cmd)
           {
               case '1': printSpace(infile, outfile); break;
               case '2': printChar(infile, outfile); break;
               case '3': printNewline(infile, outfile); break;
               case '0': break;
           }*/
           takeCommand(num, cmd);
         }

         infile.close();
         outfile.close();
         return 0;
     }

     int takeCommand(int& num, int& cmd)
     {
         string str;
         char firstChar;
         infile.open("DrawingInput_01.txt");
         for (int i = 0; i < 3; i++)
         {
             getline(infile.str);
         }
         infile >> firstChar >> str >> num;
         switch(firstChar)
         {
             case 's': cmd = 1; break;
             case 'p': cmd = 2; break;
             case 'n': cmd = 3; break;
             case 'q': cmd = 0; break;
         }
         return cmd;
     }

其中一个输入文件如下所示:

; CS 1044 Fall 2010
; Project 4
; Basic Cat
space 1
print 1 /
print 1 \
print 1 _
print 1 /
print 1 \
newline
print 1 (
space 1
print 1 o
print 1 .
print 1 o
space 1
print 1 )
newline
space 1
print 1 >
space 1
print 1 ^
space 1
print 1 <
newline
quit

输出文件应该是兔子。

void 函数在我的代码中,现在不是问题。

【问题讨论】:

  • takeCommand 中丢失infile.open()getlines() - 文件流已经打开并且在main() 中跳过了这些行。然后,使用if (infile &gt;&gt; firstChar &gt;&gt; str &gt;&gt; num) { ... } else { std::cerr &lt;&lt; "unexpected EOF\n"; exit(1); },以便在尝试使用变量之前检查变量是否被正确读取。
  • 我认为您实际上并没有从 infile 中获取任何内容。有关类似问题,请参阅 this question

标签: c++ stream while-loop pass-by-reference infinite-loop


【解决方案1】:

让我们首先从您的takeCommand 函数开始:您使用循环机制和getline 忽略文件中的前三行(因为它是一个简单的标题)。似乎合乎逻辑,但有一个警告。当您在 while 循环内多次调用此函数时,每次调用都会忽略 3 行。 “极其低效”是怎么回事?! :)

您不需要这样做。此外,您最初忽略了 main 函数中的前三行(在 while 循环之外),那么为什么在 takeCommand 中再次需要它呢?解决方案是删除 for 循环,以便之后的函数如下所示:

int takeCommand(int& num, int& cmd)
{
    char firstChar;
    infile.open("DrawingInput_01.txt");

    infile >> firstChar >> str >> num;

    switch (firstChar)
    {
        case 's': cmd = 1; break;
        case 'p': cmd = 2; break;
        case 'n': cmd = 3; break;
        case 'q': cmd = 0; break;
    }
    return cmd;
}

我的另一个烦恼是不必要的open 电话。如果您在构建文件流时已经知道文件的名称,则只需在创建文件流时提供它。这意味着从函数中删除该调用并改为:

ifstream infile("DrawingInput_01.txt");

还有一点,文件流不需要静态存储时长,也不需要作为全局变量,所以你应该把输入和输出文件流放在main中。

while 循环条件全部错误。 I/O 应该在检查流之前执行。因此,您可以将函数更改为:

std::basic_ios<char>& takeCommand(int& cmd)
{
    char firstChar;
    if (!inFile.get(firstChar))
    {
        return inFile;
    }

    inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    // ...

    return inFile;
//  ^^^^^^^^^^^^^^
}

这允许流返回到下面的while循环条件,以便它检查输入是否成功:

while (takeCommand(cmd))

请注意,我还检查了输入操作是否成功(如果有,我们将忽略该行的其余部分),并且我已经取出了不需要的参数。

在您进行了这些更改(以及其他更改)之后,您的程序应该是这样的:

#include <iostream>
#include <fstream>
#include <limits>

std::ios& takeCommand(std::istream&, int&);

int main()
{
    std::ifstream inFile("DrawingInput_01.txt");
    std::ofstream outFile("DrawingInput_01.txt");
    std::string str;

    for (int i = 0; i < 3; ++i) std::getline(inFile, str);

    int cmd;

    while (takeCommand(inFile, cmd))
    {
        std::cout << "Command was " << cmd;
        outFile << cmd;
   }
}

std::ios& takeCommand(std::istream& is, int& cmd)
{
    char firstChar;
    if (!is.get(firstChar))
    {
        return is;
    }

    is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    switch (firstChar)
    {
        case 's': cmd = 1; break;
        case 'p': cmd = 2; break;
        case 'n': cmd = 3; break;
        case 'q': cmd = 0; break;
    }

    return is;
}

【讨论】:

  • 如果我是正确的,那么 'inFile.ignore(std::numeric_limits<:streamsize>::max(), '\n')' 只会跳过该行的其余部分?另外,我想让 takeCommand 函数也读取数字并将其传递给 main 函数。这是否意味着我也必须更改参数?谢谢您的帮助。非常感谢。
  • @user2957787 “读取数字”是指文件中每一行的数字吗?
  • 是的,每条命令旁边的数字表示将要为图片打印多少个字符或空格。我相信它被传递到主函数中,然后根据它是打印还是空格,进入一个单独的函数。
  • @user2957787 然后是的,添加一个新的引用参数并提取字符串,然后像以前一样提取数字。确保在ignore 行之前执行此操作。
【解决方案2】:

您的问题是 infile 在整个 while 循环的执行过程中都处于活动状态,因此您的 while 循环始终为真,因为即使在文件关闭后对象仍然存在。

此外,您应该在使用 switch 语句测试之前获取输入的字符串,并且当 I/O 操作表明文件已被完全读取(即使用 eof () 函数,必须在 数据被读取后调用)。而您在第二个功能中 再次 打开文件。这段代码需要认真修改。

【讨论】:

  • infile 不是指针......你认为“将其设置为 NULL”会做什么? ifstream::operator= 无论如何都不接受任何指针参数。
  • 哎呀...你是对的,对不起,我会编辑我的帖子。然而,我关于他的结构和执行的其他观点仍然有效。
猜你喜欢
  • 2016-08-27
  • 2015-04-29
  • 2016-04-21
  • 2021-10-15
  • 2017-01-22
  • 1970-01-01
  • 2013-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多