Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

cybrscot

macrumors 6502
Original poster
Dec 7, 2010
282
0
Somewhere in Southeast Asia
Aha! I'm only posting because I'm quite happy that I just wrote my own program! Not required by the book. I decided I'd write a program to figure out the remainder. % of two numbers entered by a user (me). I'm pleased because I wrote it in only about 15 minutes! I feel like I'm getting better at understanding this stuff, and I know in some cases how to use the code I've learned so far to get it to do what I want it to do.

My primary problem is still understanding what the book wants me to do in certain (many, as you know) problems. I think when the problem is mine, I'm already a few steps ahead in the process of how to think about it and break it down (smaller parts) into what I want and in writing pseudo code. I guess I've got some trouble comprehending and understanding what the book wants sometimes.

Anyway, here it is for all to see! A small victory for me in my quest for C! Hey that rhymed!:)

Code:
#include <stdio.h>

main ()

{
	int remainder, numerator, denominator ;
	printf ("This program computes the remainder of user entered numbers," ) ;
	printf ("0 to exit\n") ;
	
	do {
	printf ("Enter a number: ") ;
	scanf ("%d", &numerator) ;
	if (numerator == 0) goto done;
	printf ("Enter a number: ") ;
	scanf ("%d", &denominator) ;
	
	remainder = numerator % denominator ;
	
	
	printf ("%d\n", remainder) ;
	} while (numerator != 0); 
	
	done: printf ("Thank you, have a nice day\n") ;
	
	return 0;
	
}
 
A small victory for me in my quest for C!

Code:
#include <stdio.h>

main ()

{
	int remainder, numerator, denominator ;
	printf ("This program computes the remainder of user entered numbers," ) ;
	printf ("0 to exit\n") ;
	
	do {
	printf ("Enter a number: ") ;
	scanf ("%d", &numerator) ;
	if (numerator == 0) [B]break[/B];
	printf ("Enter a number: ") ;
	scanf ("%d", &denominator) ;
	
	remainder = numerator % denominator ;
	
	
	printf ("%d\n", remainder) ;
	} while (numerator != 0); 
	
	done: printf ("Thank you, have a nice day\n") ;
	
	return 0;
	
}

Figuring things out is one of the best parts. :) I would recommend using a break statement or an if statement instead of the less-clear goto.
 
Figuring things out is one of the best parts. :) I would recommend using a break statement or an if statement instead of the less-clear goto.

Cool. I've never used a goto before, and all break statements are covered in my chapter. So I figured I'd at least get some experience with each, at least once, before I move on and maybe never use goto again. My book also mentioned that goto is not often used.

What I want to know from you is why do you consider the goto less clear? In my thinking based on my level of knowledge, it's about the most clear thing I've used because of the label. It says goto (label), and then you find the label, and it went there. Seems very precise and easy to read.

Tell me more, please.

Thanks
Scott
 
What I want to know from you is why do you consider the goto less clear? In my thinking based on my level of knowledge, it's about the most clear thing I've used because of the label. It says goto (label), and then you find the label, and it went there. Seems very precise and easy to read.

This has to do more with readability and maintainability than codeability. You understand the logic of the code that you just wrote, but it's less obvious to someone else trying to read it, whereas an if statement or a break statement has a certain logic build into it. One thing that isn't immediately obvious when you start programming with a higher-level programming language like C is that all statements are compiled down to gotos and such eventually. A loop is simply a goto statement.

Code:
int i;

i = 0;

start_Loop:

i+i+1;

if(i<10) goto start_Loop;

The idea behind what's call "syntactical sugar" is that pre-defined concepts are made into a unit and thus are easier to use.

http://en.wikipedia.org/wiki/Syntactic_sugar
 
What I want to know from you is why do you consider the goto less clear? In my thinking based on my level of knowledge, it's about the most clear thing I've used because of the label. It says goto (label), and then you find the label, and it went there. Seems very precise and easy to read.

Another way of thinking about it is also: break; always has the same behavior, and other programmers know exactly what to expect when they see a break: "Okay, we're done with this loop." On the other hand, goto can become very convoluted, and while it's simple enough in a short program like this, imagine having to hunt around a big block of code for that goto label, trying to figure out where you're supposed to go and what the intended behavior is. It's possible to not use for or while loops at all —*just use goto. But that would result in code that's very difficult to understand.
 
Aha! I'm only posting because I'm quite happy that I just wrote my own program! Not required by the book. I decided I'd write a program to figure out the remainder. % of two numbers entered by a user (me). I'm pleased because I wrote it in only about 15 minutes! I feel like I'm getting better at understanding this stuff, and I know in some cases how to use the code I've learned so far to get it to do what I want it to do.

My primary problem is still understanding what the book wants me to do in certain (many, as you know) problems. I think when the problem is mine, I'm already a few steps ahead in the process of how to think about it and break it down (smaller parts) into what I want and in writing pseudo code. I guess I've got some trouble comprehending and understanding what the book wants sometimes.

Anyway, here it is for all to see! A small victory for me in my quest for C! Hey that rhymed!:)

Code:
#include <stdio.h>

main ()

{
	int remainder, numerator, denominator ;
	printf ("This program computes the remainder of user entered numbers," ) ;
	printf ("0 to exit\n") ;
	
	do {
	printf ("Enter a number: ") ;
	scanf ("%d", &numerator) ;
	if (numerator == 0) goto done;
	printf ("Enter a number: ") ;
	scanf ("%d", &denominator) ;
	
	remainder = numerator % denominator ;
	
	
	printf ("%d\n", remainder) ;
	} while (numerator != 0); 
	
	done: printf ("Thank you, have a nice day\n") ;
	
	return 0;
	
}

The while condition of the loop is redundant. If it evaluates the condition, then the condition must be false, because otherwise it would have followed the goto statement and exited the loop already. It could actually be replaced with do { ... } while(1);

Some advise about goto: never use it, not unless you have a damned good reason (like, say you're programming an operating system). If someone applied for a job and wrote that code it would certainly call into question whether or not to hire them.

http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html
 
Last edited:
It may make more sense to loop while denominator != 0
since 0 % denominator is valid but numerator % 0 is not
 
Figuring things out is one of the best parts. :) I would recommend using a break statement or an if statement instead of the less-clear goto.
Correct me if I'm wrong. But I think Scott can go without both break and goto. The computer will thank the user when the loop finishes running.
 
Correct me if I'm wrong. But I think Scott can go without both break and goto. The computer will thank the user when the loop finishes running.

That actually isn't true (assuming he changes his "if (numerator == 0)" to "if (denominator == 0)"). To my understanding, mod 0 is undefined and thus he would need to break before trying to calculate the remainder if he wants to have a program that won't crash.
 
That actually isn't true (assuming he changes his "if (numerator == 0)" to "if (denominator == 0)"). To my understanding, mod 0 is undefined and thus he would need to break before trying to calculate the remainder if he wants to have a program that won't crash.

That case can still be handled properly without a goto or break. Here's a slight modification of the code that just adds a couple of ifs.

It still bombs badly if you enter anything other than an integer due to scanf.

Code:
#include <stdio.h>

int main (void)

{
    int remainder, numerator, denominator ;
    printf ("This program computes the remainder of user entered numbers, \n" ) ;
    printf ("Enter 0 as dividend to exit\n\n") ;
    
    do {
        printf ("Enter a dividend: ") ;
        scanf ("%d", &numerator) ;
        if (numerator != 0) {
            printf ("Enter a divisor: ") ;
            scanf ("%d", &denominator) ;
            
            if (denominator != 0) {
                remainder = numerator % denominator ;
                printf ("\nRemainder: %d\n\n", remainder) ;
            }
            else 
                printf("\nERROR: denominator cannot be zero\n");    
        }
    } while (numerator != 0); 
    
    printf ("Thank you, have a nice day\n") ;
    
    return 0;
    
}

The nice thing about this method is that you can use an editor that supports code folding to hide the paths you don't need to to see right now. The downside is that you get more levels of indent and a bit more overhead from the extra ifs.

B
 
Last edited:
That case can still be handled properly without a goto or break. Here's a slight modification of the code that just adds a couple of ifs.

If statements are more clear in this case. I'm not disputing if vs break, I was just trying to get away from goto statements at any cost. There are many more cases where I would use break than I would use goto. The particular post I was responding to was suggesting just removing the if statement which doesn't work.
 
If statements are more clear in this case. I'm not disputing if vs break, I was just trying to get away from goto statements at any cost. There are many more cases where I would use break than I would use goto. The particular post I was responding to was suggesting just removing the if statement which doesn't work.

I concur 100%. I will generally avoid goto/break/continue where possible unless their use is immediately understandable on a single screen of code.

I was only providing an example that supports Bill's point. There is no need for break or goto in this loop.

The nice thing about using the numerator/dividend as the loop exit condition is that it allows you to not ask for a denominator/divisor and skip lots of the code. However, you do need to validate all input. In this case that means not calculating mod for cases where it would be undefined.

What book are you using to learn?

It's in his sig:


B
 
I've been avoiding the threads that reference goto because it makes my blood boil. The only reason to ever know anything about goto is to be able to read someone else's code that uses it so you can remove it and replace it with a more sane control structure. Even in the best of times it is going to be jarring for someone to deal with it, and it ruins all assumptions about flow control, invariants, etc.

http://xkcd.com/292/

My initial inclination when these threads popped up was to say "Run away, skip that chapter!", but especially for continue and break, you will see these used. Hopefully you are lucky enough never to see someone use a goto, but you may as well know alternatives and how to use them effectively so you can refactor goto-laden code if you come across it.

-Lee
 
I've been avoiding the threads that reference goto because it makes my blood boil.

It's just another example for me about how I don't quite like this book.

Goto should be relegated to a chapter right at the end of the book that you can only get to by breaking a seal that says: "Here be dragons. Enter at your own peril".

I see one of the dragons (or was that a dinosaur?) made it to the xkcd strip.

B
 
I honestly think that if you find yourself needing to use a goto, your code is already in a pretty much fundamentally broken. Take these cases:

Code:
//case 1
int x = 2;
if (x == 1) {
	goto xIsValid;
}

if (x == 2) {
	goto xIsValid;
}

printf("x is neither 1 or 2\n");

xIsValid:
	printf("x is 1 or 2\n");

This case uses GOTO to basically skip over the "neither 1 or 2" line if x is not equal to one of those numbers. The immediate and obvious fault is if x is not 1 or 2, it will "fall through" and print out the "IS 1 or 2" line.


Code:
//case 2
int x = 2
do {
	if (x == 1) {
		break;
	}
	if (x == 2) {
		break;
	}
	printf("x is neither 1 or 2");
} while (false);

printf("x is 1 or 2");

This code uses a do/while control structure so that a break can be used in lieu of a GOTO. Obviously it suffers from the same problem. Bottom line, this code is basically broken because it relies on a sequential structure.


Code:
//Case 3
void xIsValid(int x) {
	printf("x is %d and valid",x);
}

int x = 2
if (x == 1) {
	xIsValid(x);
} else if (x == 2) {
	xIsValid(x);
} else {
	printf("x is neither 1 or 2");
}

This is rewritten to not require a break or a GOTO. Not that this is awesome code and not to say there is never a case when a break is required, but in many cases people just use these simple control structures to avoid having to write cleaner and modularized code.
 
The only reason to ever know anything about goto is to be able to read someone else's code that uses it so you can remove it and replace it with a more sane control structure.

There are cases where I think goto is appropriate. When using a doubly nested loop to search through a data structure, I haven't found a cleaner way to exit the three loops than just a simple goto. The deeper the loop structure, the uglier the solution if you don't use a goto. If you know of a better way then please enlighten me. I've spent quite a bit of time trying to come up with something prettier.
Code:
for(int i = 0; i<10; i++)
{
  for(int j = 0; j<10;j++)
  {
    for(int k = 0; k<10;k++)
    {
      if(condition == true /* peudo-code*/)goto exit_loops;
    }
  }
}
exit_loops:

Other options:
Code:
for(int i = 0; i<10; i++)
{
  for(int j = 0; j<10;j++)
  {
    for(int k = 0; k<10;k++)
    {
      if(condition == true /* peudo-code*/)
      {
         i = 10;
         j = 10;
         k = 10;
      }
    }
  }
}

Code:
for(int i = 0; i<10; i++)
{
  for(int j = 0; j<10;j++)
  {
    for(int k = 0; k<10;k++)
    {
      if(condition == true /* peudo-code*/)break;
    }
    if(condition == true /* peudo-code*/)break;
  }
  if(condition == true /* peudo-code*/)break;
}

Code:
bool found = false;
for(int i = 0; i<10 && !found; i++)
{
  for(int j = 0; j<10 && !found;j++)
  {
    for(int k = 0; k<10 && !found;k++)
    {
      if(condition == true /* peudo-code*/)found = true;
    }
  }
}
 
I haven't found a cleaner way to exit the three loops than just a simple goto.
Your last one is more to my taste personally. I can look immediately at the for statements and know that they might not run through all the indices.

Why do you find the goto cleaner?

Personally, I would prefer to use while loops and manually initialize and increment the counters. It would be more verbose, but IMHO clearer since the exit condition would be explicit.

B
 
When using a doubly nested loop to search through a data structure, I haven't found a cleaner way to exit the three loops than just a simple goto.

I maintain there has to be a better way to write this code. I don't think well planned and written code should actually ever even have a multi-level break. If you do actually need a structure like this, I would probably break down the "nests" into a series of functions instead.

Given the methods you mention, I agree with balamw and using expressing the the break in the invariant.
 
Here's another alternative that gets rid of the nested loops and makes the purpose of the loop transparent:

Code:
bool found = false;
long unsigned int count = 0;
while (!found) {
  /* extract i, j, k indices from count and do stuff with them */ 
  /* condition now has to check that i, j and k are out of range as well as if the item was found*/
  if(condition == true) found = true; 
  count++;
}

I'm not saying I particularly like it, but it is an alternative that could work well in certain situations.

EDIT: The extraction bit could be implemented as something like:
Code:
i = count/(10*10);
j = (count/10)%10;
k = count%10;
for the case where i, j, k are 0-9.

B
 
Last edited:
There are cases where I think goto is appropriate. When using a doubly nested loop to search through a data structure, I haven't found a cleaner way to exit the three loops than just a simple goto. The deeper the loop structure, the uglier the solution if you don't use a goto. If you know of a better way then please enlighten me. I've spent quite a bit of time trying to come up with something prettier.

I'm glad someone brought this up. I'm new to programming, and although I completely understand that the use of goto is bad in some situations, I've been wondering why there is such avoidance of continue and break. I've read several articles about it. I'm wondering whether the avoidance is really on the level of superstition. Code with continue and break is easy to understand, so isn't the issue really whether it works well with computer architecture? The following is quoted from http://en.wikipedia.org/wiki/Structured_programming:

Knuth proposed a looser structural constraint: It should be possible to draw a program's flow chart with all forward branches on the left, all backward branches on the right, and no branches crossing each other. Many of those knowledgeable in compilers and graph theory have advocated allowing only reducible flow graphs.

This seems to make sense. But I wouldn't really know.
 
Code with continue and break is easy to understand, so isn't the issue really whether it works well with computer architecture?

Code with continue and break can be easy to understand, but it can also be far more difficult than the alternatives depending on the specific situation.

When the code is more complicated than the simple examples we are talking about here and several break/continue statements are buried in the body of the loop it can really confuse things.

I've mentioned it already somewhat in the thread, but I find Code Folding extremely useful, and having alternative ways out of the loop decreases its functionality quite a bit.

B
 
I think the key point here is modularity and encapsulation. You have these control structures in C which are all governed by these "{", "}" things. What lives within those braces should be discreet, logically opaque and blind to what is outside them. The main reason for this is so that you can modify a section of code without affecting the flow of what lives outside its braces or encapsulated within it. As soon as you start using goto to cross encapsulation boundaries, you sacrifice the discreet modularity of your code, compromise its resilience increase its maintenance requirement.

break and continue are problematic because they muddy the readability of you source. Alternative design is not at all difficult to come up with, and it becomes habit very quickly.
 
Please get rid of the goto. Use break instead. GOTO is useful in assembly code, but in a language like C, it just continues a practice that will lead to spaghetti code. Nip it in the bud, and you'll be thankful later.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.