Recursively transfer strings from istream into array - C++

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


Recursively transfer strings from istream into array - C++



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.


.txt


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?


dicReader


dict


while


for


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;
}





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
yesterday




dicReader


dictionaryReader





Are you sure you want to do it recursively?
– Martin York
yesterday




2 Answers
2



You are not using count correctly.


count



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.


if (!dictfile.eof())



The function can be simplified to:


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

return 0;
}





Tail recursion might be worth mentioning.
– john
yesterday





@john, that might be more than what the OP can digest.
– R Sahu
yesterday





OK well I'll have a go.
– john
yesterday





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
yesterday





@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
yesterday


true



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


count


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.


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.





That's definitely better as a second answer. It will be helpful to someone, I am sure.
– R Sahu
yesterday






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Stripe::AuthenticationError No API key provided. Set your API key using “Stripe.api_key = ”

CRM reporting Extension - SSRS instance is blank

Keycloak server returning user_not_found error when user is already imported with LDAP