1

I am trying to copy in strings from a .txt file (every word is on a new line) into an array. The main routine would look like this.

const int MAXDICTWORDS = 5000;

int main()
{
    string dict[MAXDICTWORDS];
    ifstream dictfile;  // file containing the list of words

    dictfile.open("words.txt");
    if (!dictfile) {
        cout << "File not found!" << endl;
        return (1);
    }

    int nwords = dicReader(dictfile, dict);
    // dict should now hold array of words from words.txt
    // nwords will be the amount of words in the array
}

This is my current implementation of dicReader. dict will always be empty when passed to this function. I am practicing with recursion, so no while or for loops can be used. Any ideas on what I am missing?

int dicReader(istream &dictfile, string dict[])
{
    int count = 0; // know this is wrong, recursive call will always reset count to 0
    string item;

    if (!dictfile.eof())
    {
        dictfile >> item;
        dict[0] = item;
        dicReader(dictfile, dict + 1); // is this the correct recursive call?
        count++;
    }

    return count;
}
aelarabi
  • 51
  • 7
  • It's not the correct call, if only because the function is called `dicReader` not `dictionaryReader`. A minor point but it is a good idea to avoid confusion by posting the genuine code, not untested code that might or might not illustrate your real problem. – john Jul 25 '18 at 20:30
  • Are you sure you want to do it recursively? – Martin York Jul 25 '18 at 21:27

2 Answers2

1

You are not using count correctly.

You need to keep accumulating the value in the recursive calls.

Also, if (!dictfile.eof()) is wrong. See Why is iostream::eof inside a loop condition considered wrong? for details.

The function can be simplified to:

int dictionaryReader(istream &dictfile, string dict[])
{
    if (dictfile >> dict[0])
    {
        return (1 + dictionaryReader(dictfile, dict + 1));
    }

    return 0;
}
R Sahu
  • 196,807
  • 13
  • 136
  • 247
  • Tail recursion might be worth mentioning. – john Jul 25 '18 at 20:32
  • @john, that might be more than what the OP can digest. – R Sahu Jul 25 '18 at 20:38
  • OK well I'll have a go. – john Jul 25 '18 at 20:41
  • Thanks @john! Please do. @R Sahu - I am assuming the conditional will always cast to true if there are words left in the istream. Is that correct? Also, does the recursive call's second parameter of dict+1 ensure that we cannot return a value of MAXDICTWORDS? i.e. if we don't copy in a string from dictfile because dict[0] doesn't point anywhere, we return 0 and end our recursive call? – aelarabi Jul 25 '18 at 20:53
  • @aelarabi, the expression will evaluate to `true` as long as the read is successful. it does not say anything about what's left in the stream. No to the second question. If you need to make sure that you don't read more than what the original can array can hold, you'll have to add more bookkeeping data. – R Sahu Jul 25 '18 at 20:59
1

R Sahu has given you a complete answer, but there is an alternative way to formulate the recursive function. This alternative has the count variable as a parameter to the function. Like this

int dictionaryReader(istream &dictfile, string dict[], int count)
{
    if (dictfile >> dict[0])
    {
        return dictionaryReader(dictfile, dict + 1, count + 1);
    }
    return count;
}

When the function is initially called you supply a value of zero for count.

int nwords = dictionaryReader(dictfile, dict, 0);

In this implementation dictionaryReader calls itself and returns the resulting value directly. This is called tail recursion. In the alternative implementation dictionaryReader calls itself and then adds one to the result, so it isn't tail recursive.

The advantage of tail recursion is that it is trivially converted into a while loop (the while loop you were told to avoid). Some compilers perform this conversion for you as an optimisation. So you write a tail recursive function but end up with the same code as if you had written a while loop.

john
  • 71,156
  • 4
  • 49
  • 68