Thread: Infinte loop with switch, Why??

  1. #1
    Registered User
    Join Date
    Jan 2004
    Posts
    13

    Infinte loop with switch, Why??

    Hi,
    I have made a simple menu program and use switch to handle the choices. The problem is, if i enter a number, it sends it into an infinite loop instead of the default command to say invalid input.
    Does anyone know why this is?
    Thanks

    Code:
    #include <stdio.h>
    
    void menu();
    
    void add()
    {
    	float a, b, ans;
    	a = 0;
    	b = 0;
    	ans = 0;
    
    	printf("********************************\n");
    	printf("          ADDITION\n\n");
    	printf("Enter first addend: ");
    	scanf("%f", &a);
    	printf("Enter second addend: ");
    	scanf("%f", &b);
    	
    	ans = a+b;
    
    	printf("\n %f plus %f equals %f \n", a, b, ans);
    
    	menu();
    }
    
    void subtract()
    {
    	float a, b, ans;
    	a = 0;
    	b = 0;
    	ans = 0;
    
    	printf("********************************\n");
    	printf("          SUBTRACTION\n\n");
    	printf("Enter Minuend: ");
    	scanf("%f", &a);
    	printf("Enter Subtrahend: ");
    	scanf("%f", &b);
    	
    	ans = a-b;
    
    	printf("\n %f minus %f equals %f \n", a, b, ans);
    
    	menu();
    }
    
    void multiply()
    {
    	float a, b, ans;
    	a = 0;
    	b = 0;
    	ans = 0;
    
    	printf("********************************\n");
    	printf("        MULTIPLICATION\n\n");
    	printf("Enter Multiplicand: ");
    	scanf("%f", &a);
    	printf("Enter Multiplier: ");
    	scanf("%f", &b);
    	
    	ans = a*b;
    
    	printf("\n %f plus %f times %f \n", a, b, ans);
    
    	menu();
    }
    
    void divide()
    {
    	float a, b, ans;
    	a = 0;
    	b = 0;
    	ans = 0;
    
    	printf("********************************\n");
    	printf("          DIVISION\n\n");
    	printf("Enter Dividend: ");
    	scanf("%f", &a);
    	printf("Enter Divisor: ");
    	scanf("%f", &b);
    	
    	ans = a/b;
    
    	printf("\n %f divided by %f equals %f \n", a, b, ans);
    
    	menu();
    }
    
    void retry()
    {
    	menu();
    }
    
    void menu()
    {
    	int ans = 0;
    
    	printf("\n\nWhat would you like to do?\n");
    	printf("1. Add: \n");
    	printf("2. Subtract: \n");
    	printf("3. Multiply: \n");
    	printf("4. Divide: \n");
    	scanf("%d", &ans);
    
    	switch(ans)
    	{
    	case 1:
    		add();
    		break;
    	case 2:
    		subtract();
    		break;
    	case 3:
    		multiply();
    		break;
    	case 4:
    		divide();
    		break;
    	default:
    		printf("Invalid input!!\n");
    		retry();
    		break;
    	}
    }
    
    
    int main()
    {
    	menu();
    	return 0;
    }

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Well for starters you're recursively calling menu. (The entire "retry" function is pointless, since you can just call menu directly anyway.) A loop would work better. Next, how about actually checking the return value of scanf to make sure they entered a number instead of something else?


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > printf("Invalid input!!\n");
    menu() calls retry() which immediately calls menu() again (and so on....)

    > scanf("%d", &ans);
    scanf() stops processing at the first character which does NOT match the conversion.
    The bad news for you is that input is NOT processed either, so unless you actually do something with the input, then scanf() gets stuck.

    This is what not to do
    http://faq.cprogramming.com/cgi-bin/...&id=1043284351

    Try this instead
    http://faq.cprogramming.com/cgi-bin/...&id=1043284385

    Also, you should have a while loop around your menu(). Calling functions recursively like you do is not good.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    9
    Another quick and dirty solution (above the one suggested by quzah: check scanf() return code) could be to flush standard input before scanf(): fflush(stdin) before scanf() could do the trick.

    But even in this case, if you put a breakpoint at start of menu(), you will see that your stack is growing and growing... This is due to the fact that menu() is called recursively and the stack never unwinds.

    So, instead of calling retry() at end of menu(), a goto to start of menu() or a big while (1) wrapping the whole menu() function (for purists ) is mandatory.

    Best regards, bilbo
    Last edited by bilbo; 06-15-2005 at 06:24 AM.

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    fflush(stdin) before scanf() could do the trick.
    That's not a solution. That's a problem. fflush is NOT for input streams! Ever. Any attempt to do so is undefined which means anything or nothing can happen. It was never ever intended for input streams. Then you go on to suggest goto? Why not tell them to use gets while you're at it?


    Quzah.
    Hope is the first step on the road to disappointment.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    9
    Quote Originally Posted by quzah
    That's not a solution. That's a problem. fflush is NOT for input streams! Ever. Any attempt to do so is undefined which means anything or nothing can happen. It was never ever intended for input streams.
    Sorry, quzah, I am new to this board (I have just subscribed today) and in a rush of giving my contribute I have not yet read the fuc*ed FAQ.
    I just thought that Kate was using Microsoft Visual C, where fflush(stdin) is perfectly legal (it is effectively seen as an extension to the C standard). Look at http://msdn.microsoft.com/library/en...crt_fflush.asp for a sample code.
    In fact, before answering, I tried my suggestion (with MSVC compiler) and it worked...

    Quote Originally Posted by quzah
    Then you go on to suggest goto? Why not tell them to use gets while you're at it?
    I based my suggestion on the result. The result is the way a program will work; the result is the compiled machine code which will allow the program to run.
    Now, please, look at the machine code that the compiler (alas... again the Microsoft one...) will generate for a goto and for a while...

    Code:
               while (1) a = 3;
                        mov eax,1
                        test eax,eax
                        je ...  // OUT OF LOOP
                        mov dword ptr [a],3
                        jmp ...  // START OF LOOP
    and this is for the goto...
    Code:
               retry: a = 3; goto retry;
                         mov dword ptr [a],3
                         jmp retry
    The second one seems even more compact than the first one, isn't it?

    Best regards, bilbo

    P.S. Ah, fortunately "goto" is not in the FAQ! Anyway you must give me credit that I did not discredit the purists!

    P.P.S Well, I hope we will become friends, if you leave me the time to make some other contribution, instead of flaming as fast as you can!

  7. #7
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    The reason we usually steer people away from goto is that it makes for horrible debugging and readability. It's also one of the reasons I don't like globals in general. It's too annoying to try and figure out where they're at, rather than just looking for defined variables at the top of the function / code block.

    Goto has its uses, and I wasn't debating speed. It's just not the best way to teach people how to control the flow of their application.

    As for fflush, I, as well as many others here, feel it's best to only present people with standard methods for handling problems. Especially considering there is a standard way to handle the flushing of the input stream. (It's quite a common topic, the board search and/or FAQ will cover it if you're curious.)
    I just thought that Kate was using Microsoft Visual C,
    That's the problem with non standard methods. We have no idea what compiler they're using, so why limit them to a "solution" that may or may not work for them, when we can provide on that will guarinteed fix the issue?


    Quzah.
    Hope is the first step on the road to disappointment.

  8. #8
    Registered User
    Join Date
    Jan 2004
    Posts
    13
    Thanks guys,

    Great help

  9. #9
    Registered User
    Join Date
    Jun 2005
    Posts
    9
    Quote Originally Posted by quzah
    As for fflush, I, as well as many others here, feel it's best to only present people with standard methods for handling problems.
    Ok, quzah, got it! Next time I'll specify "this is valid only for MSVC, or GCC, or something else", or - better - I'll avoid to suggest non-standard solutions, as you pointed out.

    Quote Originally Posted by quzah
    The reason we usually steer people away from goto is that it makes for horrible debugging and readability. It's also one of the reasons I don't like globals in general.
    Sorry, quzah, I - not always but sometimes - think goto is more readable because it avoids a lot of indenting in the code lines; or, using it, the creation of helper variables to go out of nidified loops can be avoided.
    And I - not always but sometimes - like globals because they do not need to be passed on the stack when calling some related function. I know, it is harmful, collateral effects may arise, etc etc, but I think the skill of the people, among many other things, can be evaluated by the way they are able of playing with fire... Anyway, I respect your point of view.

    Best regards, bilbo

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. how to loop in switch??
    By pczafer in forum C++ Programming
    Replies: 6
    Last Post: 05-04-2009, 01:53 AM
  2. break statement not within loop or switch
    By Arruba in forum C Programming
    Replies: 3
    Last Post: 11-04-2006, 01:36 AM
  3. Replies: 1
    Last Post: 10-27-2006, 01:21 PM
  4. Switch statement = infinite loop
    By Lucid003 in forum C++ Programming
    Replies: 10
    Last Post: 10-10-2005, 12:46 AM