Paulithan
Paulithan

Reputation: 79

I can't figure out why I'm getting this infinite loop

This is a piece of a larger program that I'm writing which is, for some reason, giving me an infinite loop. It behaves as expected for inputs like "Roundup" and "what's up". These tell the user that the chosen word should be the correct length and contain only lowercase letters. However inputs like "round-up" and "round up" produce an infinite repetition of the message telling the user to choose words of the correct length and format. Can someone please help me figure out what the problem is? I'd really appreciate it. Thanks!

#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <ctime>   
#include <algorithm>
#include <iomanip>
#include <string>

using namespace std;

const int MINWORDLENGTH = 4;
const int MAXWORDLENGTH = 6;
const int NUMWORDS = 9000;


const char WORDFILENAME[] = "C:/Users/Paul/Desktop/words.txt";

int randInt(int lowest, int highest)
{

    if (highest < lowest)
        swap(highest, lowest);
    return lowest + (std::rand() % (highest - lowest + 1));
}

int loadWords(char words[][MAXWORDLENGTH+1], int maxWords)
{
    ifstream wordfile(WORDFILENAME);
    if ( ! wordfile)
    {
        cout << "Cannot open " << WORDFILENAME << endl;
        return -1;
    }
    const int LINELIMIT = 10000;
    char line[LINELIMIT];
    int numWords = 0;
    while (wordfile.getline(line, LINELIMIT))
    {
        if (numWords == maxWords)
        {
            cout << "Using only the first " << numWords
                 << " words from " << WORDFILENAME << endl;
            break;
        }
        int k;
        for (k = 0; islower(line[k]); k++)



        if (line[k] == '\r')
                line[k] = '\0';

        if (line[k] == '\0'  &&  k >= MINWORDLENGTH  &&  k <= MAXWORDLENGTH)
        {
            strcpy(words[numWords], line);
            numWords++;
        }
    }
    return numWords;
}
bool found(char characters[], int length, char target)  //seaches for the target character and returns true if it is found. Otherwise returns false.
{
        for (int i= 0; i<length; i++)
            if (characters[i] == target )
                return true;


    return false;



bool wordFound(const char allWords[][7], char targetWord[], int numWords)  //searches the array of loaded words for the target word. Returns true if it is found, otherwise returns false.
{
for(int j=0; j<numWords; j++)
    if (!strcmp(targetWord,allWords[j]) )
        return true;

return false;
}
bool properFormat(char guess[],int size)  //checks that words are of the proper length and contain only lowercase letters
{
if (( guess[0] == '\0')||strlen(guess) > MAXWORDLENGTH || strlen(guess) < MINWORDLENGTH)
    return false;
for (int i = 0; i < strlen(guess) ; i++)
    if ( !islower(guess[i]) )  //return false if a nonlowercase letter, punctuation or a space is found
        return false;

return true;
}

int manageOneRound(char words[][7],int num, int numwords)
{
    int x=num;
    int y=numwords;

    cout<<"The hidden word is "<<strlen(words[y])<<" letters long"<<endl;
    cerr<<words[y]<<endl;
    int tries =0;
    char guess[7];

    int appearances[MAXWORDLENGTH];
    char characters[MAXWORDLENGTH]="";

    int k=0;
    for ( int j = 0; j < strlen(words[y]); j++)
        if ( !found(characters,strlen(words[y]),words[y][j]) )  //put characters that make up word into an array. Each character appears only once.
        {
            characters[k] = words[y][j];
            k++;
        }

            while ( strcmp(guess,words[y]) )  //while the guessed word is not the correct word
    {

        cout<<"Trial word: ";

        cin.getline(guess, MAXWORDLENGTH+1,'\n');
        if ( !properFormat(guess,strlen(guess)) )   
            cout<<"Your trial word must be a word of "<<MINWORDLENGTH<<" to "<<MAXWORDLENGTH<<" lower case letters"<<endl;
        else if (!wordFound(words,guess,x) && guess[0] != '\0')  //determine if trial word is known
            cout<<"I don't know that word"<<endl;
        else
        {

        int guessAppearances[MAXWORDLENGTH];
        char guessCharacters[MAXWORDLENGTH]="";

        int l=0;
        for ( int j = 0; j < strlen(guess); j++)
        {
            if ( !found(guessCharacters,strlen(guess),guess[j]) ) //Store characters that make up trial word in an array
            {
                guessCharacters[l] = guess[j];
                l++;
            }
        }

        alphabetize(characters,k);
        alphabetize(guessCharacters,l);  //alphabetize the word characters and the guess word characters



        for ( int j = 0; j < k; j++ )
            appearances[j]=countAppearances( words[y], strlen(words[y]), characters[j] );
        for ( int j = 0; j < l; j++ )
            guessAppearances[j]=countAppearances( guess, strlen(guess), guessCharacters[j] );
        //count the number of appearnces of the characters in the word and the guess word.


        int comp[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
        int n=0;

    for (int i=0 ;i<k;i++)
        for(int j=0; j<l; j++)
        {
            if (characters[i]==guessCharacters[j] && appearances[i]==guessAppearances[j]) //if the characters match, and the number of its appearances matches, the current position of comp is set to the number of appearances
            {   
                comp[n]=appearances[i];
                n++;
            }
            else if (characters[i]==guessCharacters[j] && appearances[i] > guessAppearances[j])//if the characters match, and the number of appearances of the letter is less than the correct number, the current position of comp is set to the number of its appearances in the guess word.
            {   
                comp[n]=guessAppearances[j];
                n++;
            }
            else if (characters[i]==guessCharacters[j] && appearances[i] < guessAppearances[j])//if the characters match, and the number of appearances of the letter is greater than the correct number, the current position of comp is set to the number of its appearances in the correct word.
            {   
                comp[n]=appearances[i];
                n++;
            }
        }

        int correctSum=0;
        for (int w=0; w <n; w++)  //the number of correct letters is the sum of the elements in comp
            correctSum+= comp[w];
        if (strcmp(guess,words[y]))
            cout<<correctSum<<endl;
        }
        tries++;

}
            return tries;
}
int main()
{
int numRounds;

int max=0;
int min=10000;

cout<<"How many rounds do you want to play? ";
cin>>numRounds;
cin.ignore(10000, '\n');
if (numRounds < 1)
{
    cout<<"The number of rounds must be positive"<<endl;
    return 0;
}
char words[NUMWORDS][MAXWORDLENGTH + 1];

int x = loadWords(words, 10000);

srand(time(0));
int sum = 0;
for (int round=1; round <= numRounds; round++)
{

    cout<<"Round "<<round<<endl;
    int y= randInt(0, x);


    int tries = manageOneRound(words,x,y);


sum+=tries;
    //cerr<<sum<<endl;
cout<<"You got it in "<<tries<<" tries"<<endl;
if (tries < min)
    min = tries;
if (tries > max )
    max = tries;
double average= sum/round;
cout<<"Average: "<<setprecision(2)<<fixed<<average<<setprecision(1)<<fixed<<", minimum: "<<min<<", maximum: "<<max<<endl<<endl;

 }
return 0;
}

Upvotes: 0

Views: 200

Answers (1)

kunal
kunal

Reputation: 966

The problem with you code is that your buffer has MAXWORDLENGTH = 6 +1 = 7 , so when you enter round-up the length of "round-up" is 8 so contents of your buffer will be guess = {r,o,u,n,d,u,\0} and when the length of the input is greater than 6 this leads to the next getline statement getting '\n' that was not taken in this buffer and this executes continously leading infinite while loop. If the length of input is less than 6 for example "round" this will work fine.You are trying to read into a buffer more than its capacity and thus leading corruption of memory and undefined behaviour.

Upvotes: 1

Related Questions