Infinite Loop

the while loop I have that starts on line 48 is an infinite loop. The Input data is:

A 	www.barkingmad.org 	010.023.111.202
A 	www.toadstools.org 	111.162.001.122
A 	www.stools.com 		012.240.117.219
A 	www.stooges.biz 	113.021.097.138
A 	www.relish.edu 		014.126.222.047
A 	www.canuk.ca 		115.293.113.196
A 	www.cherokee.org 	016.015.131.215
A 	www.lancashire.com 	117.127.228.134
A 	www.froggy.biz 		018.233.106.263
A 	www.ewarrior.net	119.191.021.112
P
F	www.ewarrior.net
F	www.barkingmad.org
F	www.stooges.com
F	www.relish.edu
D	www.canuk.ca
D	www.cherokee.org 
A	www.odu.edu            192.012.174.002
F	www.lancashire.com
F	www.yorkshire.com
F	www.cherokee.org
F	www.canuk.ca
F	www.froggy.biz 
F	www.ewarrior.com
M	www.ewarrior.com 	192.168.113.112
D	www.barkingmad.org 
F	www.ewarrior.com
F	www.lancashire.com
F	www.odu.edu
Q



The output says:

Enter a valid command.
Enter a valid command.

Then it crashes the program.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <cmath>


using namespace std;

struct domList
{
string domName;
string ipAddress;
int counter;
};

void insertOne(domList list[], ifstream& inFile, int len);
void change(domList list[], string dName, string IpNum, int len);
void Delete(domList list[], string dName, int& lengthList);  
void find(domList list[], string dName, int len);  

int main (){
    
    char command;
    
    domList list[NULL];
    int listLength = 0;
    
    string ipNum, DomName;
    int counter = 0;
    bool x;
    ifstream dataFile;
    
    //stores the name of the dataFile
    string dataFile1;
    
    cout << "Please enter the data file you wish to use: ";
    cin >> dataFile1;
      
    dataFile.open (dataFile1.c_str());
    if (!dataFile) 
    {
       cout << "bummer file\n\n";
       system ("pause");
       return 1;
    }
    
    while(dataFile){
       dataFile >> command >> DomName >> ipNum;
       switch(command){
                       case 'A':
                                insertOne(list, dataFile, listLength);
                                listLength++;
                       break;
                       case 'M':
                                change(list, DomName, ipNum, listLength);
                       break;
                       case 'D':
                                Delete(list, DomName, listLength);
                                listLength--;
                       default: 
                                cout << "Enter a valid command." << endl;
    }
}
}

void insertOne(domList list[], ifstream& inFile, int len)
{
     domList one;
     inFile >> one.domName >> one.ipAddress;
     one.counter = 0;
     list[len] = one;
}

void change(domList list[], string dName, string IpNum, int len)
{
     for(int i = 0; i < len; i++)
     {
          if(list[i].domName == dName)
          {
                list[i].ipAddress = IpNum;
                list[i].counter += 1;
          }
     }
}

void Delete(domList list[], string dName, int& lengthList)
{
     for(int i = 0; i < lengthList; i++)
     {
          if(list[i].domName == dName)
          {
               for(int l = i; l < lengthList; l++)
               {
                     list[l] = list[l+1];
                     lengthList--;
               }
          }
     }
}

void find(domList list[], string dName, int len)
{
     for (int i = 0; i < len; i++)
     {
         if (list[i].domName == dName)
         {
              cout << list[i].ipAddress << endl;
         }    
     }
}
Forgot to ask this. Anyone see the problem with the loop? I don't see it.
I haven't studied the code in depth, but I do see that this line

dataFile >> command >> DomName >> ipNum;

is always trying to extract three values : a command plus two others. But not all lines in you file have three values.

Try editing you file to provide dumy values so all lines have three strings and see if that works.

If it does, you should consider swapping to use std::getline and then breaking the line up yourself. That way you can handle different numbers of parameters per line.

Andy

P.S. To see what's going on, you could use cout to display the command, dataFile, DomName it read each time.
Last edited on
You should read the command first and then determine what else you need to read as you seem to know what each command is supposed to do.
If you do take Warnis route, I would read the command as a string. If your code is trying to read a single char (before the next whitespace) but is then given more than one char (i.e. a string), the input processing for the rest of the line will be thrown off.

Note that your insertOne() function is using the istream directly, but the other functions are relying on the main loop to do the work for them. This inconsistency needs to be eliinated!

I find it easier to validate the string when I first read the whole line and then chop it up; see the code below. The intention is to split the processing of the input from the handling of specific commands. The file-to-command code should be reusable in other apps, where you just have to provide updated versions of processCommand() and reportError()

I've also spotted that you declared a zero size array, on line 26

domList list[NULL];

NULL == 0, to this is a zero sized array, which is not much use!

As you've chose to use an array as a list, you need to give it a reasonable size and then convert insertOne to something like.

1
2
3
4
5
6
void insertOne(domList list[], string dName, string IpNum, int len)
{
	list[len].domName = dName;
	list[len].ipAddress = IpNum;
	list[len].counter = 0;
}


I would also consider moving the incrementing and decrementing of listLength inside the list functions, to the list looks after itself (as you are already doing in Delete()).

Note that if you do take Warnis' route, then your current implementation of insertOne() is (probably) the better approach, and you need to rework all the other command functions to use the same one. In that case the extraction in the main loop would then be just dataFile >> command; Error handling will prob. be a bit harder to implement in this case.

Andy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// split line into strings using whitespace as separator
void splitLine(const string& line, vector<string>& args);

// see below
void reportError(int errorCode, int lineNum, const vector<string>& args);

// see below
int processCommand(const vector<string>& args, domList list[], int& listLength);

    ...

    int ret = 0; // should really use enum or consts for error codes

    string line;
    int lineNum = 0; // for error reporting
    vector<string> args;

    while((0 == ret) && dataFile){
        ++lineNum; // increment here so line number starts at 1
        getline(dataFile, line);
        // can add code to skip comments easy enough here
        args.clear();
        splitLine(line, args);
        // if we got no args as the string was just whitespace
        if(0 == args.size())
            continue;
        // if the command wasn't just a single char
        if(1 != args[0].length())
            ret = 1;
        else
            ret = processCommand(args, list, listLength);
    }

    if(0 == ret)
    {
        ...
    }
    else
    {
        reportError(ret, lineNum, args);
    }

    ...


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
int processCommand(const vector<string>& args, domList list[], int& listLength)
{
    int ret = 0;

    char command = args[0][0];

    switch(command){
        case 'A':
            if(3 != args.size())
            {
                ret = 2;
            }
            else
            {
                const string& DomName = args[1];
                const string& ipNum = args[2];
                // could check the strings are in the expected format?
                insertOne(list, DomName, ipNum, listLength);
                listLength++;
            }
        break;
        case 'M':
            if(3 != args.size())
            {
                ret = 2;
            }
            else
            {
                const string& DomName = args[1];
                const string& ipNum = args[2];
                change(list, DomName, ipNum, listLength);
            }
        break;
        case 'D':
            if(2 != args.size())
            {
                ret = 2;
            }
            else
            {
                const string& DomName = args[1];
                Delete(list, DomName, listLength);
                listLength--;
            }
        break;
        default: 
            ret = 1;
    }
    
    return ret;
}

void reportError(int errorCode, int lineNum, const vector<string>& args)
{
    cerr << "Error on line #" << lineNum << endl;
    switch(errorCode)
    {
        case 1: cerr << "- invalid command : " << args[0] << endl; break;
        case 2: cerr << "- invalid param count for command : " << args[0] << endl; break;
        default: cerr << "- unknown error" << endl;
    }
}

Last edited on
Topic archived. No new replies allowed.