为什么这会在Mac上产生无限循环?

时间:2015-10-17 00:07:28

标签: c++ macos g++ infinite-loop

我编写了以下函数来从文件中读取并在Visual Studio 2015中将“记录”加载到BST中。它的工作方式与我在Windows中的预期相同但是当我在mac上运行该函数时,它会导致无限循环。我无法弄清楚为什么。有人可以对此有所了解。使用完整代码更新,问题在于以下功能:

BinarySearchTree readFile()
{
    ifstream myfile;
    myfile.open("character.txt");
    string name;
    string aString = "Empty";
    BinarySearchTree loadTree;
    List list1;
    int index = 1;
    bool finishRecord = false;
    if (!myfile.peek() == myfile.eof())
    {
        while (!myfile.eof())
        {
            getline(myfile, name);
            while (!finishRecord)
            {
                getline(myfile, aString);
                if (aString == "/")
                {
                    finishRecord = true;
                }
                else
                {
                    list1.insert(index, aString);
                    index += 1;
                }
            }

            KeyedItem an_item(name, list1, true);
            loadTree.searchTreeInsert(an_item);

            //reset variables used for each record
            index = 1;
            list1.removeAll();
            finishRecord = false;
        }
    }
    myfile.close();
    return loadTree;
}   // end readFile

完整代码:

#include <iostream>     //needed for input and output and the console screen
#include <fstream>      //needed to read/write a file
#include <iomanip>
#include <algorithm>    //needed to use the transform function

#include "ListP.h"  //linked list class
#include "BST.h" // binary tree operations

using namespace std;

string suspectsArray[256];  //array of the suspects
int suspectIndex = 0;
KeyedItem ADD();
BinarySearchTree readFile();
void QUIT(BinarySearchTree& passedTree, string addedItems[], int arrayIndex);
bool withinTree(BinarySearchTree& passedTree, string name);
string INQUIRY(BinarySearchTree& passedTree);
void suspects(TreeItemType& anItem);
void findTip(BinarySearchTree& passedTree, string tip, int &noSuspects);


int main()
{
    string aString;
    BinarySearchTree characterTree = readFile();
    KeyedItem an_Item;
    string addedItems[256] = {};
    int index = 0;
    string answer;
    string inquiryReturn = "";
    bool main = false;
    bool inTree = false;

    while (!main)
    {
        cout << "WE ARE AT MAIN LOOP. YOU CAN ADD, INQUIRY, OR QUIT";
        cout << endl;
        if (inquiryReturn == "")
        {
            cin >> answer;
            cin.ignore();   //need to flush the input for the getline()
        }
        else
        {
            inquiryReturn = "";
        }


        //since we need to accept the input regardless of it case
        //so going to make the input into lower case
        transform(answer.begin(), answer.end(), answer.begin(), tolower);
        //determine which operation the user called
        if (answer == "add")    //user wishes to ADD a character
        {
            cout << endl;
            an_Item = ADD();
            //need to determine if the record for the character
            //is already in the tree or not
            inTree = withinTree(characterTree, an_Item.getKey());
            if (!inTree)
            {
                addedItems[index] = an_Item.getKey();
                index += 1;
                characterTree.searchTreeInsert(an_Item);
            }
            else
            {
                cout << "Character already in tree." << endl;
            }
            inTree = false;
        }
        else if (answer == "inquiry")   //user wishes to do an INQUIRY
        {
            cout << "User wants to do an INQUIRY" << endl;

            characterTree.postorderTraverse(suspects);
            inquiryReturn = INQUIRY(characterTree);
            answer = inquiryReturn;
            suspectIndex = 0;
        }
        else if (answer == "quit")      //user wishes to QUIT the program
        {
            if (index > 0)      //if the user added a character, save
            {
                cout << "OK, saving database to file "
                    "\"character.txt\" ";
                QUIT(characterTree, addedItems, index);
                cout << "... Done.  Goodbye." << endl;
                main = true;
            }
            else
            {
                cout << "OK, saving database to file "
                    "\"character.txt\" ";
                cout << "... Done.  Goodbye." << endl;
                main = true;
            }
        }
        else
        {
            cout << "You didn't enter a valid command." << endl;
        }

    }

    return 0;
}   //end main

void suspects(TreeItemType& anItem)
{
    suspectsArray[suspectIndex] = anItem.getKey();
    suspectIndex++;
}

 //Function to get a record to add to the binary search tree
 //gets the record in the type KeyedItem
KeyedItem ADD()
{
    string name;
    string a_string;
    List list1;
    int index = 1;
    bool end = false;

    cout << "OK, we are now adding a character to the database."
        << endl;
    cout << "Name of Character:" << setw(5) << " ";
    getline(cin, name);
    cout << "Attributes:" << setw(12) << " ";

    //loop to get attributes if any
    while (!end)
    {
        getline(cin, a_string);
        if (a_string == "")
        {
            //if no attributes were added, need to prompt for one
            if (list1.getLength() == 0)
            {
                cout << "Need to enter at least one attribute." <<
                    endl << setw(23) << " ";
            }
            else
            {
                cout << endl;
                end = true;
            }
        }
        else
        {
            list1.insert(index, a_string);
            index += 1;
            cout << setw(23) << " ";
        }
    }
    KeyedItem an_item1(name, list1, true);
    return an_item1;
}   // end ADD

//Function to read the database file and 
//load all of the records into a Binary Search Tree.
BinarySearchTree readFile()
{
    ifstream myfile;
    myfile.open("character.txt");
    string name;
    string aString = "Empty";
    BinarySearchTree loadTree;
    List list1;
    int index = 1;
    bool finishRecord = false;
    if (!myfile.peek() == myfile.eof())
    {
        while (!myfile.eof())
        {
            getline(myfile, name);
            while (!finishRecord)
            {
                getline(myfile, aString);
                if (aString == "/")
                {
                    finishRecord = true;
                }
                else
                {
                    list1.insert(index, aString);
                    index += 1;
                }
            }

            KeyedItem an_item(name, list1, true);
            loadTree.searchTreeInsert(an_item);

            //reset variables used for each record
            index = 1;
            list1.removeAll();
            finishRecord = false;
        }
    }
    myfile.close();
    return loadTree;
}   // end readFile

//Function to run if additional shady characters were manually added to the Binary Search Tree
//It should the added characters to the database text file.
void QUIT(BinarySearchTree& passedTree, string addedItems[], int arrayIndex)
{
    ofstream outfile;   //variable that will be assigned to the file
    KeyedItem an_item;  //record that needs to be added to file
    string aString;
    outfile.open("character.txt", ios::app);
    if (outfile.is_open())
    {
        for (int i = 0; i < arrayIndex; i++)
        {
            passedTree.searchTreeRetrieve(addedItems[i], an_item);
            outfile << an_item.getKey() << "\n";
            int jkl = an_item.attributes.getLength();
            for (int bnm = 1; bnm < jkl + 1; bnm++)
            {
                an_item.attributes.retrieve(bnm, aString);
                outfile << aString << "\n";
            }
            outfile << "/\n";
        }
        outfile.close();
    }
}   // end QUIT


//function to check whether or not the character is already in the tree
bool withinTree(BinarySearchTree& passedTree, string name)
{
    KeyedItem item;
    try
    {
        passedTree.searchTreeRetrieve(name, item);
    }
    catch (TreeException& error)
    {
        //the character is not within the tree
        return false;
    }
    //the character is within the tree
    return true;
}   // end withinTree

//Function to if the tip matches any of the attributes of the suspects
void findTip(BinarySearchTree& passedTree, string tip,int &noSuspects)
{
    KeyedItem aItem;
    bool tipFound = false;
    string aString;
    //look at each of the characters attributes
    //to see if they are a match for the tip
    for (int asd = 0; asd < suspectIndex; asd++)
    {
        tipFound = false;
        if (suspectsArray[asd] != "")
        {
            passedTree.searchTreeRetrieve(suspectsArray[asd], aItem);

            //goes through each of the attributes of a character
            for (int iop = 1; iop < aItem.attributes.getLength() + 1; iop++)
            {
                aItem.attributes.retrieve(iop, aString);
                transform(aString.begin(), aString.end(), aString.begin(), toupper);
                if (aString == tip)
                {
                    tipFound = true;
                }
            }
            //if none of character's attribute match
            //remove them from the suspectArray
            if (tipFound == false)
            {
                suspectsArray[asd] = "";
                noSuspects -= 1;
            }
        }
    }
}   // end findTIP

//Function to find the perpetrator, if any
string INQUIRY(BinarySearchTree& passedTree)
{
    string codeName;        //string variable for inquiry code name
    string command;         //string variable for command input
    string aString;
    string checkSuspect;
    int noSuspects = suspectIndex;
    bool tipFound = false;


    cout << "OK, we are now conducting an inquiry." << endl;
    cout << endl << "Enter a Code Name for this Inquiry:";
    cout << setw(5) << " ";
    getline(cin, codeName);

    while (command != "ADD" && command != "QUIT" && command != "INQUIRY")
    {
        cout << "What would you like to do?" << endl;
        getline(cin, command);

        transform(command.begin(), command.end(), command.begin(), toupper);
        if (command == "TIP")
        {
            cout << "Enter Tip Info:" << setw(25) << " ";
            getline(cin, command);
            transform(command.begin(), command.end(), command.begin(), toupper);

            findTip(passedTree, command, noSuspects);

            //if there's only 1 suspect left, alert the user
            if (noSuspects == 1)
            {
                cout << "ALERT! That leaves only one \n"
                    << "suspect in the " << codeName << " inquiry:"
                    << setw(13) << " ";
                for (int k = 0; k < suspectIndex; k++)
                {
                    if (suspectsArray[k] != "")
                    {
                        cout << suspectsArray[k] << endl;
                    }
                }
            }
            else if (noSuspects == 0) //all suspects have been eliminated 
            {
                cout << "There no suspects that are match." << endl;
            }
        }
        else if (command == "CHECK")
        {
            bool found = false;
            cout << "Enter Name of character:" << setw(16) << " ";
            getline(cin, checkSuspect);
            transform(checkSuspect.begin(), checkSuspect.end(),
                checkSuspect.begin(), toupper);
            for (int p = 0; p < suspectIndex; p++)
            {
                aString = suspectsArray[p];
                transform(aString.begin(), aString.end(), aString.begin(), toupper);
                if (aString == checkSuspect)
                {
                    cout << aString << " is a suspect." << endl;
                    found = true;
                }
            }
            if (!found)
            {
                cout << checkSuspect << " is not a suspect." << endl;
            }
        }
        else if (command == "PRINT")
        {
            cout << "Current Suspects are:" << endl;
            for (int k = 0; k < suspectIndex; k++)
            {
                if (suspectsArray[k] != "")
                {
                    cout << suspectsArray[k] << endl;
                }               
            }
        }
        else if (command == "ADD" || command == "QUIT" || command == "INQUIRY")
        {
            return command;
        }
    }
}   // end INQUIRY

2 个答案:

答案 0 :(得分:1)

我的猜测是你的程序没有在输入流中找到“/”,因此从不设置finishRecord = true;。您可能应该在内循环和外循环中检查eof。

答案 1 :(得分:0)

使用Visual Studio而不是Mac编译时这种方法有效的原因是你运气不好。你有一个错误使它看起来就像在Windows上工作一样,但Mac更幸运并且失败了。

readFile函数开始,因为如果无法正确读取文件,则无法测试程序的其余部分。垃圾在==垃圾输出。

 if (!myfile.peek() == myfile.eof())

以int两个块的形式分解,然后比较其结果。

!myfile.peek()

返回所有错误的读取字符或EOF。那不是吗。除非从文件中读取NULL,否则会导致false。

myfile.eof()

如果查看文件的末尾,则总是返回true,否则返回false。

如果进入if的正文,那么空文件大小写将false与true进行比较。不知道你如何在这里获得无限循环。

至于

while (!myfile.eof())

阅读Why is iostream::eof inside a loop condition considered wrong?

getline(myfile, name)返回对输入流的引用,输入流有一个groovy operator bool(),如果流是可读的,则返回true,所以

while (getline(myfile, name))

实际上就是你所需要的。如果因任何原因无法读取文件,包括EOF,繁荣!该计划已离开这里。

这意味着所有输入都可以简化为:

while (getline(myfile, name))
{ // loop until read fails
    string aString;
    while (getline(myfile, aString) && aString != "/")
    { // loop until read fails or find end of record
        list1.insert(index, aString);
        index += 1;
    }
    KeyedItem an_item(name, list1, true);
    loadTree.searchTreeInsert(an_item);

    //reset variables used for each record
    index = 1;
    list1.removeAll();
}

尽管有一个强有力的案例可以单独捕获aString != "/",因此程序可以在当前记录结束之前处理文件结束(或以其他方式变得不可读)。上面的代码只是包装起来,并称它为一天好像没有出错。

while (getline(myfile, name))
{ // loop until read fails
    string aString;
    while (getline(myfile, aString) && aString != "/")
    { // loop until read fails or find end of record
        list1.insert(index, aString);
        index += 1;
    }
    if (!myfile)
    {
        // handle error
    }

    KeyedItem an_item(name, list1, true);
    loadTree.searchTreeInsert(an_item);

    //reset variables used for each record
    index = 1;
    list1.removeAll();
}

填补这一空白。

此外,利用Visual Studio的调试器逐步执行代码并查看出错的地方。这将为您节省大量时间。

我们没有节点或树的代码,所以我们无法提供更多帮助。但是一旦你知道你有数据并且知道它是正确的(再次使用调试器来查看你的节点和树以确保一切正常),你要么已经完成或者处于有利位置要求新的,多更具体的问题。