Using break, continue, goto, in C

Discussion in 'Mac Programming' started by cybrscot, Feb 24, 2011.

  1. cybrscot macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #1
    Hey,

    When exactly do I use these statements to break out of a loop, or to another point in the loop?

    What I mean is, I've already done several exercises in my book for while loops, do loops, and for loops, and I haven't used a statement to break the loop yet.

    As far as I can see, the condition that tests is what has been determining whether to continue looping, or break from the loop. This has always worked, so when is using break, continue or goto worthwhile? Or is it just a different way to write the same thing, as I have seen there are many ways to write code, depending on who writes it and their style I suppose.
     
  2. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #2
    Let's say you do a search function to look for something in a list. The end condition of the loop must be the end of the list, to look through it all. But in case you item is found earlier than the very last item, use break to exit the loop.

    Similarly, goto can be used if you are nesting loops. You might have three loops inside each other. Now, let's say you have found your item in the innermost loop. You can use goto to exit all loops.
     
  3. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #3
    A typical situation where you use break is this: You have a loop. However, the code that determines whether you exit the loop is not simple, but rather complex. For example, you might have to execute several statements until you find out whether you need to exit the loop at this point or not. Then you will use something like

    Code:
    for (;;) {
       ... lots of code
       if (done_with_this_loop) break; 
       ... more code
    }
    continue is used in a loop when you want to ignore one item in the loop. Let's say you want to perform some action for all customers stored in an array that purchased something in the last week:

    Code:
    for (i = 0; i < number_of_customers; ++i) {
       CustomerData* customer = customers [i];
       if (todaysDate - customer->purchaseDate > 7) continue; 
       ... code for customers that bought something in the last week
    }
    
    goto: The rule is very simple. If you have to ask when to use it, then don't use it.
     
  4. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #4
    I feel about the same for break and continue. Both of your examples can be replaced with adding a second conditional. It will probably be a bit less efficient, but the code may be easier to read and extend. (if can use cold folding break/continue/goto can't).

    First, to effectively evaluate the exit condition mid-loop as you did with break.

    Code:
    ]
    int done_with_this_loop=0;
    while (!done_with_this_loop) {
       ... lots of code
       set done_with_this_loop if exit requested
       if (!done_with_this_loop) {
       ... more code
       };
    }
    Similarly for the continue example to skip some cases as you did with continue.

    Code:
    for (i = 0; i < number_of_customers; ++i) {
       CustomerData* customer = customers [i];
       int lastweek = (todaysDate - customer->purchaseDate <= 7)
       if (lastweek) { 
       ... code for customers that bought something in the last week
       };
    }
    
    B
     
  5. KnightWRX macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #5
    At this point, the best advice I can give you is to refer to the comp.lang.c guys. Read their FAQ on this question :

    http://c-faq.com/~scs/cclass/notes/sx3f.html

    These guys are purists of a higher order and will always defer to K&R as the prime source (which anyone writing C code should anyway).

    As for GOTO, well, they do have a FAQ for that :

    http://c-faq.com/~scs/cclass/int/sx4cc.html

    Notice however the opening statement which reads quite clearly :

    For people trying to be as objective as can be in their writing, it pretty shows their stance on the matter.

    If you really are into learning C, you should definately get a copy of The C Programming Language, 2nd edition by K&R (they invented the language). While it doesn't cover ANSI C99, it is still one of the best reference for C programmers around.
     
  6. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #6
  7. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #7
    I'd say we disagree about what is easier to read :D

    for (;;) {} with break and continue statements in the right places is a very straightforward, easily used, and easily recognised pattern. Instead you introduce an artificial variable that needs to be declared with a pointless name that you need to make up, initialised with the right value, a test in the right place, an unnecessary if statement with unnecessary brackets. Instead you can just use break = "we are done with this loop" and continue = "we are done with this iteration of the loop".
     
  8. KnightWRX macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #8
    Of course they say in their FAQ that the code can be modified and made better. I think the point is to answer the question on how to use the statements. Same for the goto FAQ. Even though they say that code can usually be written to not use it, they then explain its use and how to apply it.

    This answers the OP's question on when to use it and inserts the caveat of "but don't".
     
  9. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #9
    In the end, all this gives some variety to achieve control flow in a program. Sure, there are do's and don'ts and typical recommended patterns, but besides this, it comes down to a question of style, imho.
     
  10. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #10
    ;)

    I think that the use of goto/break/continue/multiple returns is fine in small/simple cases like the examples, but when over-used it tends to lead to spaghetti code which becomes much harder to debug.

    (Without the break/continue I can pull out the body of a complex loop and test it or implement it as a function).

    B
     
  11. KnightWRX macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #11
    I think any programmer of experience agrees on this. Anyway, who was it that said that if your function is bigger than what fits in a standard screen, it's much too long and needs to be chopped up in smaller functions ? ;)
     
  12. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #12
    Absolutely. Lots of ways to separate cats from their skins.

    The delicate balancing act IMHO is letting novice programmers have tools like goto and then having them write BASIC-like spaghetti code because they rely on it too much.

    That's a style thing/affectation too. ;)

    B
     
  13. ulbador, Feb 25, 2011
    Last edited: Feb 25, 2011

    ulbador macrumors 68000

    ulbador

    Joined:
    Feb 11, 2010
    #13
    Ha, goto... There is a construct that should have died long ago, but somehow has found it's way back into some modern languages.

    They actually just put it back into PHP in some of the recent versions. I thought I had actually found a valid case to use it as a multi-level break, until I realized I was inventing a reason to use it by writing bad code.
     
  14. subsonix, Feb 25, 2011
    Last edited: Feb 25, 2011

    subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #14
    I have also seen it used to "clean up before we leave the sinking ship" scenarios, let's say, close files, free memory then exit.

    Here's such a scenario: http://books.google.com/books?id=K8...d=0CCMQ6AEwAQ#v=onepage&q=OUT_ON_NULL&f=false
     
  15. ulbador, Feb 25, 2011
    Last edited: Feb 25, 2011

    ulbador macrumors 68000

    ulbador

    Joined:
    Feb 11, 2010
    #15
    I could POSSIBLY see that too. Though you are probably just better off calling a cleanup function (though arguably in this case they largely accomplish the same thing). The biggest problem I see with this, is that with a proper goto (can't jump in/out of a function, method, class etc), you are basically guaranteeing the code following the goto will ALWAYS be executed at some point:

    Code:
    do stuff
    do more stuff
    
    myGotoLabel:
    stuff to do in goto
    
    The "stuff to do in goto" will ALWAYS be executed at some point in your program even if you never call "goto(myGotoLabel)" unless you use another goto to skip over it (or a function to kill your program). This would be different than a function which may or may not be called.

    I recently wrote a daemon in C that open all sorts of files and database connections. With a simple method and signal.h, I can ensure my cleanup is always called (short of a kill -9)
     
  16. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #16
    The only problem I see with a function is that it's hard to make generic, since all the variables are local to the function failing and will typically vary in their amount and types. So your cleanup function will have to be rewritten for each specific use.
     
  17. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #17
    Don't worry about break, continue, goto. Worry about patterns. The use of goto that you quoted establishes a pattern: You allocate resources at the beginning of a function, there may be a failure at any point in the function, so when this happens you go to the cleanup. Once you have learned the pattern, you can use it anywhere, and it works, and it is readable, and it is fine. As long as you don't deviate from the pattern.

    Any deviation from the pattern is really bad, because the reader of your code then has to figure out all the details, and they have to figure why you did deviate from the pattern. So instead of taking a glance at your code and saying "he uses the allocate-at-the-top-then-jump-to-cleanup-when-there-is-a-failure pattern", the reader has to completely analyse your code to see what you are doing. And you should try to use patterns that are simple and easy to follow and not error prone. (Question: How many things do you have to get right to use the pattern correctly? )
     
  18. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #18
    goto and break statements can be used to provide obvious secondary exits from loops... or to write undebuggable pure spaghetti code.

    But when used in a straight forward manner (e.g. a well known design pattern), their use is (provenly) identical with more obscurely written structured constructs. In those cases the only reason not to use them is "political correctness", or maybe a weakness in the static analyzers used for verification and optimization purposes.
     
  19. Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #19
    I don't understand that sentence. Is firewood saying that a code fragment with a goto in it does the same job as an obscure piece of code that doesn't use one? If I say that X is identical with Y, that means that X and Y stand for exactly the same thing. For "X is identical with Y" is true when X and Y both stand for President Barack Obama.
     
  20. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #20
    Back in the earliest days of "structured programming" a lot of work was done proving that some collection of "if gotos" was mathematically identical to another collection of only structured programming constructs (no gotos or breaks, etc.) Academic papers, from the circa late '60's maybe, on why Pascal and Algol were better than Fortran, etc.

    Note that Fortran still sees significant use in supercomputing numerical applications, whilst Pascal and Algol have pretty much faded from view.
     
  21. Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #21
    Firewood is right. But the latest version of Fortran, Fortran 95, I think, includes constructs that help programmers avoid gotos. Even Fortran 77 included some of those constructs. On the other hand, I can write obscure goto-less code in Fortran 77, too. Some languages, Eiffel, say, forbid gotos.
     
  22. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #22
    I would offer three rules for "proper" use of goto:

    1. Only go forward, never use goto to jump backward in code
    2. If you have multiple jumps to multiple labels, only use nested jumps
      Code:
      // OK:
      goto label2;
      ...
      goto label1;
      ...
      label1:
      ...
      label2:
      
      // not so good:
      
      goto label1;
      ...
      goto label2;
      ...
      label1:
      ...
      label2:
      
      — in other words, jump paths should not cross.
    3. If you can come up with an efficient way to do what you want without using gotos, use that

    Obviously, I am the ultimate authority on style ;)
     

Share This Page