Thread: How to exit from nested loops?

  1. #16
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    If you want your software to be readable and possible to upkeep then why would you want to sacrifice the simplicity of nested loops?
    Normally you nest loops because that's what needs to be done: an inner loop that exits wont effect when an outer loop exits. Rather, an outer loop impacts the condition of an inner loop usually. Since we're dealing with something unusual, the code probably already has some other logical problem, anyway.

    Since we don't know what OP is really doing either, we're all ........ing in the wind.

  2. #17
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    Structured Programming with goto Statements
    In case you haven't read it yet.

  3. #18
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Since we don't know what OP is really doing either, we're all ........ing in the wind.
    Nice.

    If you absolutely have to nest 50 deep then yes a goto is the preferred and simple way to break out of it. However the fact that you feel you 'must' nest loops as deep as you are indicates a flaw in the design to me. But that is just my two cents.

  4. #19
    Registered User
    Join Date
    Jun 2010
    Posts
    182
    Let's imagine I need to generate all the combinations of strings
    from '0' to "2147483647", the first idea I came up with was to use
    nested loops this way:

    Code:
         for (digit[0] = '0'; (int)digit[0] < four; (int)digit[0]++){
             for (digit[1] = '0'; (int)digit[1] < ten; (int)digit[1]++){
                 for (digit[2] = '0'; (int)digit[2] < ten; (int)digit[2]++){
    	          for (digit[3] = '0'; (int)digit[3] < ten; (int)digit[3]++){
    	              for (digit[4] = '0'; (int)digit[4] < ten; (int)digit[4]++){
    	                  for (digit[5] = '0'; (int)digit[5] < ten; (int)digit[5]++){
    	          		for (digit[6] = '0'; (int)digit[6] < ten; (int)digit[6]++){
    			          for (digit[7] = '0'; (int)digit[7] < ten; (int)digit[7]++){
    				       for (digit[8] = '0'; (int)digit[8] < ten; (int)digit[8]++){
    				           for (digit[9] = '0'; (int)digit[9] < ten; (int)digit[9]++){
    						do_something(digit);
    
    						y1 = last_active;
    						times++;
    						if (times > 2147483647){
    						    goto end_cycle;
    						} // end if											
    
    	          			    } // end digit[9] for
                                            if (last_active > 8)
    						last_active = 8;
    					    digit[9] = '0';	
    	          			} // end digit[8] for
                                        if (last_active > 7)
    					    last_active = 7;
    					digit[9] = '0';
    					digit[8] = '0';	
    	         		  } // end digit[7] for
                                   if (last_active > 6)
    				      last_active = 6;
    				  digit[9] = '0';
    				  digit[8] = '0';
    				  digit[7] = '0';	
    	          		} // end digit[6] for
                                 if (last_active > 5)
    				    last_active = 5;
    				digit[9] = '0';
    				digit[8] = '0';
    				digit[7] = '0';
    				digit[6] = '0'; 
    	                  } // end digit[5] for
                             if (last_active > 4)
    			       last_active = 4;
    			   digit[9] = '0';
    			   digit[8] = '0';
    			   digit[7] = '0';
    			   digit[6] = '0'; 
    			   digit[5] = '0'; 
    	              } // end digit[4] for
                         if (last_active > 3)
    			   last_active = 3;
    			digit[9] = '0';
    			digit[8] = '0';
    			digit[7] = '0';
    			digit[6] = '0'; 
    			digit[5] = '0'; 
    			digit[4] = '0'; 
    	          } // end digit[3] for
                     if (last_active > 2)
    		       last_active = 2;
    		   digit[9] = '0';
    		   digit[8] = '0';
    		   digit[7] = '0';
    		   digit[6] = '0'; 
    		   digit[5] = '0'; 
    		   digit[4] = '0'; 
    		   digit[3] = '0'; 
    	     } // end digit[2] for	
                if (last_active > 1)
    		  last_active = 1;
    	     digit[9] = '0';
    	     digit[8] = '0';
                digit[7] = '0';
    	     digit[6] = '0'; 
    	     digit[5] = '0'; 
    	     digit[4] = '0'; 
    	     digit[3] = '0';   
    	     digit[2] = '0';   
    	  } // end digit[1] for
             if (last_active > 0)
    	      last_active = 0;
    	  digit[9] = '0';
    	  digit[8] = '0';
       	  digit[7] = '0';
    	  digit[6] = '0'; 
    	  digit[5] = '0'; 
    	  digit[4] = '0'; 
    	  digit[3] = '0';   
    	  digit[2] = '0';   
    	  digit[1] = '0';   
         } // end digit[0] for
    
    end_cycle:
    But being the first idea it could be not the best of west, so to speak.

    What would you suggest to to for a task of this kind? Probably there are
    far more better ways, more elegant or efficient ones.

    I'm aware that some software engineers and architects consider nested
    loops evil in itselves, they speak about bad design and awful program logic.
    Last edited by frktons; 07-18-2010 at 02:46 PM.

  5. #20
    Registered User
    Join Date
    Oct 2006
    Posts
    250
    I hope you are merely jesting. Do the words, maintainable , extensible, and robust mean anything to you? Even from a conceptual point of view your example is none of the above. If anything, your example displays a complete lack of aptitude for programming.

  6. #21
    Registered User
    Join Date
    Jun 2010
    Posts
    182
    Quote Originally Posted by MWAAAHAAA View Post
    I hope you are merely jesting. Do the words, maintainable , extensible, and robust mean anything to you? Even from a conceptual point of view your example is none of the above. If anything, your example displays a complete lack of aptitude for programming.
    Thanks, very kind of you

    I'm a beginner in the C learning path, so if you can show me an
    example of doing this task in a better way it would be very appreciated.

  7. #22
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by frktons View Post
    Let's imagine I need to generate all the combinations of strings
    from '0' to "2147483647"
    Why do you need so many strings? The memory needed to store this is not insignificant. Even if you put it into a file, it would be so big that Notepad doesn't open it. I think you should try black box testing this. You might, for example, give input that is typical, give input that is atypical, and input that tests your constraints.

    Let's say that we made a calculator that handled answers from 0 up to 0x7fffffff. This is an example of a program constraint. When there is an overflow problem, say the error is logged and the user has to "start over". In black-box testing, we would arrange for problems that come to that answer or greater, to make sure our program responds as expected. If all is well, we have additional proof that the program is well behaved.

    So generate the strings you need rather than the whole lot.

    I'm aware that some software engineers and architects consider nested
    loops evil in itselves, they speak about bad design and awful program logic.
    You're abusing a language feature. There is no reason to go believing that something you misuse is evil.

    But do me a personal favor and kill this attempt WITH FIRE.
    Last edited by whiteflags; 07-18-2010 at 04:06 PM.

  8. #23
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Oh! He's got an aptitude for it, trust me! Maybe a bit too much enthusiasm, atm, but that will work itself out. (and just my opinion anywho)

    I would do it like this:

    Code:
    #include <stdio.h>
    #include <limits.h>
    #include <time.h>
    
    int main() {
      clock_t start, stop;
      long int i, shortMax; 
      char snum[11];
      double elapsed;
      printf("\n\n  Goal Number is: %ld", LONG_MAX);
      start=clock();
      shortMax = LONG_MAX-3;
      for(i=0;i<LONG_MAX;i++) {
        ltoa(i, snum, 10); //maximum of 33 bytes for Turbo C
        if(i>shortMax) 
          printf("\n%s",snum);
      }
      stop=clock();
      elapsed=(double) stop-start;
      printf("Elapsed time was: %lf: ", elapsed/CLK_TCK); //replace with CLOCKS_PER_SEC for VC
    
      printf("\n\n\t\t\t     press enter when ready");
      i = getchar();
      return 0;
    }
    I have my misgivings about the need for ALL these numbers, but this is how I'd generate all those numbers, as strings, if I needed to.

    The if statement inside the for loop, prevents Turbo C from smartly skipping over the entire for loop, in zero time. You'll want to add your output etc., and remove it, of course.

    I'm looking at this from a "you'll only need to do this just one time, so fast is great, but absolute blazing speed is not required", point of view.

    One of my Sudoku analyzer programs uses 81 nested for loops

    << let us pause for those so inclined to recover from their fainting spell >>

    So I'm not against nested loops. I just wouldn't use them, for this.
    Last edited by Adak; 07-18-2010 at 04:16 PM.

  9. #24
    Registered User claudiu's Avatar
    Join Date
    Feb 2010
    Location
    London, United Kingdom
    Posts
    2,094
    Quote Originally Posted by frktons View Post
    Let's imagine I need to generate all the combinations of strings
    from '0' to "2147483647", the first idea I came up with was to use
    nested loops this way:

    Code:
         for (digit[0] = '0'; (int)digit[0] < four; (int)digit[0]++){
             for (digit[1] = '0'; (int)digit[1] < ten; (int)digit[1]++){
                 for (digit[2] = '0'; (int)digit[2] < ten; (int)digit[2]++){
    	          for (digit[3] = '0'; (int)digit[3] < ten; (int)digit[3]++){
    	              for (digit[4] = '0'; (int)digit[4] < ten; (int)digit[4]++){
    	                  for (digit[5] = '0'; (int)digit[5] < ten; (int)digit[5]++){
    	          		for (digit[6] = '0'; (int)digit[6] < ten; (int)digit[6]++){
    			          for (digit[7] = '0'; (int)digit[7] < ten; (int)digit[7]++){
    				       for (digit[8] = '0'; (int)digit[8] < ten; (int)digit[8]++){
    				           for (digit[9] = '0'; (int)digit[9] < ten; (int)digit[9]++){
    						do_something(digit);
    
    						y1 = last_active;
    						times++;
    						if (times > 2147483647){
    						    goto end_cycle;
    						} // end if											
    
    	          			    } // end digit[9] for
                                            if (last_active > 8)
    						last_active = 8;
    					    digit[9] = '0';	
    	          			} // end digit[8] for
                                        if (last_active > 7)
    					    last_active = 7;
    					digit[9] = '0';
    					digit[8] = '0';	
    	         		  } // end digit[7] for
                                   if (last_active > 6)
    				      last_active = 6;
    				  digit[9] = '0';
    				  digit[8] = '0';
    				  digit[7] = '0';	
    	          		} // end digit[6] for
                                 if (last_active > 5)
    				    last_active = 5;
    				digit[9] = '0';
    				digit[8] = '0';
    				digit[7] = '0';
    				digit[6] = '0'; 
    	                  } // end digit[5] for
                             if (last_active > 4)
    			       last_active = 4;
    			   digit[9] = '0';
    			   digit[8] = '0';
    			   digit[7] = '0';
    			   digit[6] = '0'; 
    			   digit[5] = '0'; 
    	              } // end digit[4] for
                         if (last_active > 3)
    			   last_active = 3;
    			digit[9] = '0';
    			digit[8] = '0';
    			digit[7] = '0';
    			digit[6] = '0'; 
    			digit[5] = '0'; 
    			digit[4] = '0'; 
    	          } // end digit[3] for
                     if (last_active > 2)
    		       last_active = 2;
    		   digit[9] = '0';
    		   digit[8] = '0';
    		   digit[7] = '0';
    		   digit[6] = '0'; 
    		   digit[5] = '0'; 
    		   digit[4] = '0'; 
    		   digit[3] = '0'; 
    	     } // end digit[2] for	
                if (last_active > 1)
    		  last_active = 1;
    	     digit[9] = '0';
    	     digit[8] = '0';
                digit[7] = '0';
    	     digit[6] = '0'; 
    	     digit[5] = '0'; 
    	     digit[4] = '0'; 
    	     digit[3] = '0';   
    	     digit[2] = '0';   
    	  } // end digit[1] for
             if (last_active > 0)
    	      last_active = 0;
    	  digit[9] = '0';
    	  digit[8] = '0';
       	  digit[7] = '0';
    	  digit[6] = '0'; 
    	  digit[5] = '0'; 
    	  digit[4] = '0'; 
    	  digit[3] = '0';   
    	  digit[2] = '0';   
    	  digit[1] = '0';   
         } // end digit[0] for
    
    end_cycle:
    But being the first idea it could be not the best of west, so to speak.

    What would you suggest to to for a task of this kind? Probably there are
    far more better ways, more elegant or efficient ones.

    I'm aware that some software engineers and architects consider nested
    loops evil in itselves, they speak about bad design and awful program logic.
    Assuming you want to run that on your personal computer, that will take ages to compute. That's just a case where good ol' computer science slaps mindless programming in the face.
    1. Get rid of gets(). Never ever ever use it again. Replace it with fgets() and use that instead.
    2. Get rid of void main and replace it with int main(void) and return 0 at the end of the function.
    3. Get rid of conio.h and other antiquated DOS crap headers.
    4. Don't cast the return value of malloc, even if you always always always make sure that stdlib.h is included.

  10. #25
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    He can't do "mindless programming" -- I have a patent pending on it.

  11. #26
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    And alas we arrive back at my first assumption about this thread. There is probably no need to nest 3 deep here and therefore probably no need to worry about how to break out of nested loops. There is a need here, though, for some serious re-design.

    Scientific application often involve models of 3D space that are usually represented by 3D arrays, so 3 nested loops is hardly unusual.
    Um ok. What does that mean? Games use 3D and 4D vectors all the time and there is never a need to nest 3 deep or 4 deep. Just b/c there are 3 components of a vector does not mean you calculate each one in its own loop. Structures work just fine here.
    Last edited by VirtualAce; 07-18-2010 at 05:54 PM.

  12. #27
    Registered User
    Join Date
    Jun 2010
    Posts
    182
    Quote Originally Posted by whiteflags View Post
    . I think you should try black box testing this. You might, for example, give input that is typical, give input that is atypical, and input that tests your constraints.

    Let's say that we made a calculator that handled answers from 0 up to 0x7fffffff. This is an example of a program constraint. When there is an overflow problem, say the error is logged and the user has to "start over". In black-box testing, we would arrange for problems that come to that answer or greater, to make sure our program responds as expected. If all is well, we have additional proof that the program is well behaved..
    Well, this is a good point. I assumed the limits are already defined when we
    declare a function:

    Code:
    int itoas(long num, char [], char sep);
    I am not sure I've grasped your message, nevertheless...
    What kind of atypical input could I use? The arguments filter the input
    and I cannot pass a number bigger or smaller than a long, as the first
    parameter, otherwise the compiler is going to complain. I could make an error
    with the second argument if I use a buffer that is
    too small to contain the biggest possible string, and this is one of the reason
    I was thinking about a structure to pass to the function via a pointer:

    Code:
    typedef struct num2format{
       long num;
       char buffer[15];
       char sep;
    } ntof;
    As per the separator, if I use a bad one I'll see it when I first use the program,
    and then I'd change it.

    But probably you are talking about something else. I can only imagine that
    you are referring to situations with user misbehaviour. Or what?

    Are you talking about this specific test for itoas() or in general?

    Quote Originally Posted by claudiu View Post
    Assuming you want to run that on your personal computer, that will take ages to compute. That's just a case where good ol' computer science slaps mindless programming in the face.
    Actually I tested it and it takes about 1/3 second.

    Quote Originally Posted by Adak View Post
    Oh! He's got an aptitude for it, trust me! Maybe a bit too much enthusiasm, atm, but that will work itself out. (and just my opinion anywho)

    I would do it like this:

    Code:
    #include <stdio.h>
    #include <limits.h>
    #include <time.h>
    
    int main() {
      clock_t start, stop;
      long int i, shortMax; 
      char snum[11];
      double elapsed;
      printf("\n\n  Goal Number is: %ld", LONG_MAX);
      start=clock();
      shortMax = LONG_MAX-3;
      for(i=0;i<LONG_MAX;i++) {
        ltoa(i, snum, 10); //maximum of 33 bytes for Turbo C
        if(i>shortMax) 
          printf("\n%s",snum);
      }
      stop=clock();
      elapsed=(double) stop-start;
      printf("Elapsed time was: %lf: ", elapsed/CLK_TCK); //replace with CLOCKS_PER_SEC for VC
    
      printf("\n\n\t\t\t     press enter when ready");
      i = getchar();
      return 0;
    }
    I have my misgivings about the need for ALL these numbers, but this is how I'd generate all those numbers, as strings, if I needed to.

    The if statement inside the for loop, prevents Turbo C from smartly skipping over the entire for loop, in zero time. You'll want to add your output etc., and remove it, of course.

    I'm looking at this from a "you'll only need to do this just one time, so fast is great, but absolute blazing speed is not required", point of view.

    One of my Sudoku analyzer programs uses 81 nested for loops

    << let us pause for those so inclined to recover from their fainting spell >>

    So I'm not against nested loops. I just wouldn't use them, for this.
    Thanks Adak. I'll have a detailed look at this [slow] way to perform the task ASAP.

    Quote Originally Posted by Adak View Post
    He can't do "mindless programming" -- I have a patent pending on it.
    Would you like to share the patent?
    Last edited by frktons; 07-18-2010 at 06:04 PM.

  13. #28
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    Um ok. What does that mean? Games use 3D and 4D vectors all the time and there is never a need to nest 3 deep or 4 deep. Just b/c there are 3 components of a vector does not mean you calculate each one in its own loop. Structures work just fine here.
    Something I am doing right now, actually: I have a block of matter (space) divided into cells, where each cell has several properties of the medium that change with time and space, and I need to solve differential equations on each cell. The simplest and most readable way is to iterate over each cell and perform the necessary operations, and the arrangement of cells that most intuitively models 3D space is a 3D array.

    of course it would be possible to make it a 1D array and just perform mapping and avoidn nested loops completely, but it would be completely inconprehensible to anyone working on it after me.

    Incidentally, a 3D vector is just a 1D array with 3 components. Completely different from what I was talking about.

  14. #29
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by frktons View Post
    But probably you are talking about something else. I can only imagine that
    you are referring to situations with user misbehaviour. Or what?

    Are you talking about this specific test for itoas() or in general?
    I had high hopes that you would understand me with an example but I just disappointed myself. You took a long time to mention things like small arrays and really big numbers, and these things are important, but I feel like we're getting off track.

    The whole point of black-box testing is to take long ridiculous tests like you want to perform and condense them, because it's infeasible or impossible to run the full battery of possible inputs. For instance, pick a four digit number at random. Now if itoas handles that number correctly, why on earth would you need to test the other hundreds of four digit numbers? That's the point I was trying to make here.

    I imagine you want to test itoas return value against hard-coded strings, and that is smart. What is not smart is running the gamut. You'll want to test all powers of ten that fit into a long, and not all examples are equal -- 100,000 for example, might come out as 100,0 or something if sprintf was used wrongly -- but you have to find a reasonable subset. You can't really store all the right answers without a really big file. You might do that test anyway but I don't have to care.

    God knows we've given you enough implementations of this boring function for you to compare outputs. Really...

  15. #30
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Gladly will I share the "mindless programming" patent, but I'm keeping the "totally mindless programming" patent, for myself!

    One way I've worked with problems like this (too much data for an array), is to have a for loop inside the innermost while() loop. When the biggest array you can handle is full (by testing you know this already), you call the function that tests all the numbers.

    When the testing on those numbers is finished, control returns to the while loops, and they pick up where they left off, very neatly. I would not call the test function for every number - just for the whole string array, when you have 40,000 or whatever you can handle, in the string array, full.

    Upon it's return, you exit the for loop, and the counter is reset to 0 again. Works well, easy to code, and I don't know of anything faster.
    Last edited by Adak; 07-18-2010 at 08:32 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need help in C programming (too lazy)
    By cwillygs in forum C Programming
    Replies: 12
    Last Post: 04-20-2010, 12:23 AM
  2. Displaying a table using nested loops
    By leviterande in forum C Programming
    Replies: 13
    Last Post: 09-29-2009, 04:42 PM
  3. Dynamic array of pointers
    By csisz3r in forum C Programming
    Replies: 8
    Last Post: 09-25-2005, 02:06 PM
  4. Evaluation of nested loops
    By Mister C in forum C Programming
    Replies: 2
    Last Post: 08-13-2004, 01:47 PM
  5. nested for loops
    By akub3 in forum C Programming
    Replies: 2
    Last Post: 04-01-2004, 06:21 AM