Thread: Function Self-Call error

  1. #1
    Registered User QuestionKing's Avatar
    Join Date
    Jan 2009
    Posts
    68

    Question Function Self-Call error

    Hi, I am new to C++, self learning, and not really sure why this is happening, here are the details.

    I prompt the user for an int input between 1 and 100 (inclusive) or 0 to exit...
    When a valid (0-100) reply is entered, everything works fine. The problem is a non-int or over 100 value is entered, my function is supposed to inform them that was an invalid entry, and recall the function for the input to allow them to retry or again enter 0 to exit.

    However, an invalid entry results in the function looping (seeming) endlessly with the invalid entry message. Here is the code:

    Code:
    void Input()
    {
        int depth = 0;
        cout<< "Enter the number (1-100), 0 to exit.\n";
        cin>> depth;
        if(depth > 0 && depth < 101)
        {
            //  code removed... operates as expected
        }
        else if(depth == 0)
        {
            //  code removed... operates as expected
        }
        else
        {
            cout<< "Your entry was not valid, please try again\n";
            cout<< "Enter 0 to Exit\n";
            Input();
        }
    }
    I do know (what I think is the long way) to accomplish this by recalling the function from within main after an invalid entry, or is that the shortest way possible?
    Is it just not possible to self-call a function?
    Is it possible, but poor practice?
    ANY teaching offered on anything would be much appreciated, for example it seems to me there would be a better way to prompt for an input and filter it, but so far this is the best way I have learned, most frequently expected answers on the first filter etc

    (ps... I have read many posts in searching for help on this, however FYI I do not want the answer written out for me, just some tips on which direction to travel)

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    One way to do this is with an infinite loop:
    Code:
    loop indefinitely
        print message
        read input
        if input is invalid
            print error message
        else
            break from the loop
    Another way is with a do while loop and a function:
    Code:
    function isValidInput(input)
        if input is invalid
            print error message
            return false
        else
            return true
    
    
    do
        print message
        read input
    while isValidInput(input) does not return true
    Quote Originally Posted by QuestionKing
    Is it just not possible to self-call a function?
    It is possible, and the technique is known as recursion.

    Quote Originally Posted by QuestionKing
    Is it possible, but poor practice?
    Some problems lend themselves well to a recursive solution, so in such a case recursion could be a good approach. Other than that recursion should be avoided as the depth of recursion is much more limited than with iteration, and recursion often requires more memory as the entire state of the function must be saved at the point of the call, even if the recursion only requires some of the state to be saved.
    Last edited by laserlight; 01-29-2009 at 03:28 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User QuestionKing's Avatar
    Join Date
    Jan 2009
    Posts
    68
    Thank you for the advice!

    I totally understand your first example with the loop.

    Your second example is a better explanation of what I called the long way in my first post, and I actually have it functional with that design.

    I guess my only remaining question which I am thinking you sorta answered, and that is which would you think is the best approach to this specific use? It looks to me like your first example would be the choice here, right? or does it just not matter enough to be picky?

    Also I wanted to mention this, with the code I posted originally, when the function is called, the first time an invalid entry is made, it seems to loop indefinately... as if there is input each time. I am trying to understand why there is no pause for input again as the function is recalled from the final else as it reaches cin>> depth; (line 5 in the original post). It seems to me (but what do i know yet lol) that there should be a pause for a new value of depth at this point, but rather the program just prints the full set of messages from "Enter the number...." all the way through "Enter 0 to Exit\n" (omitting the 2 failed preceeding if's)

    ...and thank you again for the suggestions

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It works as expected for me. But you can try adding
    cin.ignore();
    After each cin >> line, to see if it solves your problem.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by QuestionKing
    I guess my only remaining question which I am thinking you sorta answered, and that is which would you think is the best approach to this specific use? It looks to me like your first example would be the choice here, right? or does it just not matter enough to be picky?
    I prefer the first version, but some find the second version better.

    Quote Originally Posted by QuestionKing
    Also I wanted to mention this, with the code I posted originally, when the function is called, the first time an invalid entry is made, it seems to loop indefinately... as if there is input each time. I am trying to understand why there is no pause for input again as the function is recalled from the final else as it reaches cin>> depth; (line 5 in the original post). It seems to me (but what do i know yet lol) that there should be a pause for a new value of depth at this point, but rather the program just prints the full set of messages from "Enter the number...." all the way through "Enter 0 to Exit\n" (omitting the 2 failed preceeding if's)
    You probably tested with say, alphabetic input. The problem is that there are two kinds of invalid input errors here. One is where the input contains (or more precisely, begins with) invalid characters, and the other is when the input constitutes an integer, but the integer is not in the desired range.

    Your original code only handles the latter. To handle the former, you should clear std::cin's error flags and then ignore whatever is left in the input buffer in preparation for the next read.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User QuestionKing's Avatar
    Join Date
    Jan 2009
    Posts
    68
    Elysia:
    In my down-time I did try to cin.ignore();, but was of no use, the end result was the same looping of the function, curious how it works for you...*see below

    laserlight:
    I did in fact test with an alphabetical input as well as an out-of-range int, and both give me the same result again. I even tried to flush the buffer at the first line of the function. Perhaps I should investigate more... It seems the past few minutes of trial/error have left my software acting a whole new way, lol...

    Thank you both for your help, and Elysia if you stumble upon what made it work for you I would like to know. I just feel like I am overlooking something simple... making the problem more complicated than it is.


    Edit:
    FYI I am going to continue on with your (laserlight) first two examples and compare the overall performance of both for this specific app.
    Learning is so fun...
    Last edited by QuestionKing; 01-29-2009 at 04:16 AM. Reason: addon

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by QuestionKing
    I did in fact test with an alphabetical input as well as an out-of-range int, and both give me the same result again.
    Show the smallest and simplest compilable program that demonstrates the problem. Provide the sample inputs that demonstrates the problem.

    Quote Originally Posted by QuestionKing
    I just feel like I am overlooking something simple.
    You did not clear the error flags, and you have to ignore everything (or at least all invalid characters) that is left in the input buffer, not just the next character.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User QuestionKing's Avatar
    Join Date
    Jan 2009
    Posts
    68
    I found where the code changed which caused the looping, I was doing some trial and error before I posted the original post, and seems I did not originally initialize depth with a value as shown in my first post, marked *1 in the code below. It seems a failure to store a letter in an int variable, fails to change the value from zero, which drops you off at (if=0) and exits the program. Try it again and you will see the looping I think. Also if you have any suggestions on using time delays in terms of portability, reliability, please do tell.
    Edit: To help you understand, think of this short program as an introductory to a 101 choice menu, where each depth output provides different end results, all valid answers now jump back to retry for our debugging purpose.
    Quote Originally Posted by laserlight View Post
    Show the smallest and simplest compilable program that demonstrates the problem.
    Simplified and cut down as much as I could without disturbing the function in question, here you have the
    Code:
    #include <cstdlib>  //  part of Dev-C++ compiler
    #include <iostream>
    #include <windows.h>  //  Using Sleep - is there a better alternative?
    using namespace std;
    //    -    -    -    -    -    -    -    -    -    -    -    -    -    -functions
    void Input();
    void Output(int depth);
    //  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  M A I N   S  T  A  R  T
    int main()
    {
        Input();
        return EXIT_SUCCESS;   // any issue with using this rather than returning 0...?
    }
    //  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  M A I N   E N D
    void Input()
    {
            // *2
    	int depth;  // *1 -This is where things changed-
    	cout<< "Enter the number (1-100), 0 to exit.\n";
    	cin>> depth;
    	if(depth > 0 && depth < 101)
    	{
    		Output(depth);
    	}
    	else if(depth == 0)
    	{
    		cout<< "See you next time . . .\n";
    		Sleep(1000);  //  One use of sleep to delay closing long enough to read
    	}
    	else
    	{
                    // *2
    		cout<< "Your entry was not valid, please try again or enter 0 to EXIT\n";
                    // *2
    		Input();
    	}
    }
    //    -    -    -    -    -    -    -    -    -    -    -    -    -    -
    void Output(int depth)
    {
    	cout<< "The depth " << depth << " has been sent . . . (repeating)\n\n";
    	Input();//  recall Input() to omit code...
    }
    Quote Originally Posted by laserlight View Post
    Provide the sample inputs that demonstrates the problem.
    Enter any letter, I used 'a', 's', and 'j'.


    Quote Originally Posted by laserlight View Post
    You did not clear the error flags
    This is foreign to me still... perhaps when I more fully understand the c++ syntax/environment

    Quote Originally Posted by laserlight View Post
    you have to ignore everything (or at least all invalid characters) that is left in the input buffer, not just the next character.
    I have tried using cin.ignore(); in various places throughout the code, one at a time, (marked *2 in the code above) it does not seem to be the answer to this.

    ...again, I can not express my gratitude for your time and efforts in assisting me, thank you all
    Last edited by QuestionKing; 01-29-2009 at 12:56 PM. Reason: adding FYI

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by QuestionKing
    Also if you have any suggestions on using time delays in terms of portability, reliability, please do tell.
    You do not need the time delay at all. Just run your program from the command prompt. Some IDEs pause the program for you just prior to exit, and if not you can insert a breakpoint and step through the code using the debugger. If you really want to keep the console window open even when not running from the command prompt, you can simply wait for input (this is described in the FAQ).

    Quote Originally Posted by QuestionKing
    Simplified and cut down as much as I could without disturbing the function in question
    That's good. Unfortunately, I cannot duplicate the problem where the program went into an infinite loop with out of range integer input. I suspect that you are simply mistaken, or the simplification of the code also removed that mysterious bug.

    Quote Originally Posted by QuestionKing
    This is foreign to me still... perhaps when I more fully understand the c++ syntax/environment
    Quote Originally Posted by QuestionKing
    I have tried using cin.ignore(); in various places throughout the code, one at a time, (marked *2 in the code above) it does not seem to be the answer to this.
    What I mean is this:
    Code:
    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    std::numeric_limits is found in the <limits> standard header, but you could just use some arbitrary large number like 1000.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User QuestionKing's Avatar
    Join Date
    Jan 2009
    Posts
    68
    Quote Originally Posted by laserlight View Post
    You do not need the time delay at all.
    I actually need a time delay in many other parts of the software once 'depth' is sent to 'Output()'... I added it in as a pause here simply for reuse already included code (and only temporary in this shortened version), and mainly to avoid the 'system pause attacks' I have seen on other posts, as that is the default 'pause' of Dev-C++. However since other aspects of the software do require a pause, I am interested in a more suitable method, but have not yet researched far enough to learn the best for my needs. This is just basically the first method I could google up and use in order to complete the program to a functional stage. I will be doing more research on this very soon.

    Quote Originally Posted by laserlight View Post
    Unfortunately, I cannot duplicate the problem where the program went into an infinite loop with out of range integer input. I suspect that you are simply mistaken, or the simplification of the code also removed that mysterious bug.
    Agreed, out of range int does not cause the loop, an alpha character does: Sample inputs which do cause the looping were listed, I tried the letters 'a', 's', and 'j'. The numerical values, in and out of range, all function properly. I did copy-paste the code from my last post, and tried again, and the loop still does exist (at least for me) using Bloodshed's Dev-C++ 4.9.9.2 ...did you try a letter, or just an int? Could be related to the compiler? *scratches bald spot*



    Quote Originally Posted by laserlight View Post
    What I mean is this:
    Code:
    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    std::numeric_limits is found in the <limits> standard header, but you could just use some arbitrary large number like 1000.
    This defines the rest of my day thank you again!

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by QuestionKing
    I actually need a time delay in many other parts of the software once 'depth' is sent to 'Output()'.
    In that case, I must say that Sleep() is non-standard and thus to the best of my knowledge, not portable, but you could wrap the function call in another function that you can change to suit the platform. So, while it would not become portable, you can more easily port it.

    Quote Originally Posted by QuestionKing
    did you try a letter, or just an int?
    I can duplicate the infinite loop with alphabetic input, as expected.

    Quote Originally Posted by QuestionKing
    thank you again!
    You're welcome
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. temperature sensors
    By danko in forum C Programming
    Replies: 22
    Last Post: 07-10-2007, 07:26 PM
  2. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  3. <Gulp>
    By kryptkat in forum Windows Programming
    Replies: 7
    Last Post: 01-14-2006, 01:03 PM
  4. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM
  5. UNICODE and GET_STATE
    By Registered in forum C++ Programming
    Replies: 1
    Last Post: 07-15-2002, 03:23 PM