There is nothing wrong with goto in and of itself!
This is what most people fail to understand, instead simply parroting a poorly chosen snippet from a paper given decades ago, one that Dijkstra himself later came to regret, stating something along the lines of having "a bad feeling that people are making a religion out of it".
If people would simply try to understand the reasons behind guidelines like use of goto, break and continue, or limiting exit points from functions, and so on, they'd be far better practitioners of the art.
What Dijkstra actually railed against, and what I agree with whole-heartedly, was the "unbridled use of the go to statement", in a computing environment where there was mostly little else in terms of iteration. The fact that many environments only had goto could lead to a lot of spaghetti code, very hard to follow.
I actually consider blind dogmatism in the industry far more of a problem than goto statements ever were :-) The problem with goto is its misuse, since, as mentioned, it can make code much harder to follow and what I tend to do when I hear these pronouncements is ask:
Is this code hard to follow or maintain because it breaks the "rules"?
If you were to restructure your code as follows:
// ===================================================
// Get the second number, disallowing zero if dividing.
getSecondNum:
printf ("Enter 2nd number: ");
scanf ("%d", &num2);
if ((o == '/') && (num2 == 0)) {
printf ("You can't divide by zero \n");
goto getSecondNum;
}
// ===================================================
you would be hard-pressed trying to come up with a do or while based solution that was more readable or understandable. You may match the readability but you'll often find that a poorly selected choice between the zero-or-more do and one-or-more while can render the code less readable.
For what it's worth, this is about as close as I can get to the same code in a non-goto-using way:
// ===================================================
// Get the second number, disallowing zero if dividing.
do {
printf ("Enter 2nd number: ");
scanf ("%d", &num2);
if ((o == '/') && (num2 == 0)) {
printf ("You can't divide by zero \n");
} while ((o == '/') && (num2 == 0));
// ===================================================
but that has other issues such as code duplication. That too can be fixed but it generally involves the use of more variables, or the use of break which has exactly the same issue as goto here(b).
So, bottom line, don't take as gospel something you don't understand, it doesn't matter whether it comes from Dijkstra, Knuth, dkr, or even whatever other gods you may believe in :-)
Think about why it may be considered gospel in the first place, then that's how you decide whether it applies in a given situation(a).
I frequently use goto in state machines, error handling and so on, places where it actually simplifies the code that would otherwise be harder to understand.
(a) This includes advice from random people on the net, even from those called "paxdiablo" :-)
(b) One thing you might want to consider is to let the user enter zero even for a division, and then just sort it out in the calculation with something like:
case '/':
if (num2 == 0)
printf ("%d / 0 is undefined, cannot divide by zero", num1);
else
printf ("%d / %d = %d", num1, num2, num1 / num2);
break;
I'd probably prefer the catch-early option myself but this may be a viable solution for you.