简体   繁体   中英

recursive function stack overflow

This function takes a string wild containing '*' and '?' wild cards, and replaces the wildcards with possible chars from a tree database with nodeT *w . out holds a temporary string. Each candidates is added to a referenced bst.

void Lexicon::matchRegExpHelper(nodeT *w, string wild, Set<string> &matchSet, string out)
{   
    if (wild == "") matchSet.add(out);

    else {
        if (wild[0] != '*' || wild[0] != '?') { //this parses up to the wildcard, earlier versions used a position parameter and looped through the prefix chars recursively
            for (int j = 0; j < w->alpha.size(); j++)
                if (wild[0] == w->alpha[j].letter) matchRegExpHelper(w->alpha[j].next, wild.substr(1), matchSet, out+=wild[0]);
        } else {
            for (int i = 0; i < w->alpha.size(); i++) { 
                if (wild[0] == '?') matchRegExpHelper(w->alpha[i].next, wild.substr(1), matchSet, out+=w->alpha[i].letter);//follow path
                else { //logically, wild[0] == '*' must be true
                    if (ontLength == (wild.length() + out.length())) matchRegExpHelper(w->alpha[i].next, wild.substr(1), matchSet, out+=w->alpha[i].letter); //ontology is full, treat like a '?'
                    else matchRegExpHelper(w->alpha[i].next, wild.substr(1), matchSet, out+=(w->alpha[i].letter+'*')); //keep adding chars
                }
            }
        }
    }
}

When the first wildcard is reached the function starts over - I have tried rewriting this with the for loops, without the loops, and in differing 'prune' approaches. I am missing something basic and suspect this is a backtracking issue. Eventually the stack overflows.

Question: 1) what am I missing conceptually, and 2) how do I fix this function?

version without for loop - the test case is a bit different but similar, I'd have to test it to find it again

else {
            if (wild[0] == '?'){
                matchRegExpHelper(w, wild, ++pos, matchSet, out);//return and check next path
                matchRegExpHelper(w->alpha[pos].next, wild.substr(1), 0, matchSet, out+=w->alpha[pos].letter);//follow path
            }
            if (wild[0] == '*'){
                matchRegExpHelper(w, wild, ++pos, matchSet, out);//return and check next path
                if (ontLength == (wild.length() + out.length()))matchRegExpHelper(w->alpha[pos].next, wild.substr(1), 0, matchSet, out+=w->alpha[pos].letter); //ontology is full, treat like a '?'
                else matchRegExpHelper(w->alpha[pos].next, wild.substr(1), 0, matchSet, out+=(w->alpha[pos].letter+'*')); //keep adding chars
            }
            if (wild[0] == w->alpha[pos].letter) matchRegExpHelper(w->alpha[pos].next, wild.substr(1), 0, matchSet, out+=wild[0]);  

            matchRegExpHelper(w, wild, ++pos, matchSet, out);//check next path
        }
        for (int i = 0; i < w->alpha.size(); i++) matchRegExpHelper(w->alpha[i].next, wild.substr(1), 0, matchSet, out+=wild[0]);//step over char

the for loop at the end was an attempt to fix the overflow, i thought maybe there was no case for some threads, but I wanted those to prune, so not sure what to do

this condition is always true: (wild[0] != '*' || wild[0] != '?')

As any character is different from one of the two, maybe you meant (wild[0] != '*' && wild[0] != '?')

I hope this helps you to make some progress...

Also conceptually, I usually don't use 'for' inside a recursive function, try to rewrite it without using 'for' probably it will be clearer, maybe not efficient but once it works you can start fine tuning the algorithm..

Every recursion should have a base terminating condition.

I've got the feeling that

 if (wild[0] != '*' || wild[0] != '?') 

is wrong (that test is always true, because a character cannot be at the same time a '*' and a '?' ), it should be a conjunction && not a disjunction ||

But as I said in a comment, you really should learn how to use a debugger (ie putting breakpoints , asking for backtraces , querying value of variables).

Familiarity with debugging is a skill that will be valuable for all your life, beyond this particular program (or homework).

There were three issues with this code:

@Basile_Starynkevitch noted the importance of using the debugger to follow the path - in this case with VS2008, the stack allowed parsing the steps and noting the path moving back through several functions.

@Picarus correctly noted the error in the terminating condition

These solutions led to finding:

the solution, this void function requires two return; , one after the termination condition to terminate and another at the end to catch pruned threads. from reading several websites, it seems that a return; in a void function is unusual, but this case with the recursion and multiple paths, it was required.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM