Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version nyu B notes v1.5 12/10/84; site csd2.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!think!harvard!cmcl2!csd2!dimitrov From: dimitrov@csd2.UUCP (Isaac Dimitrovsky) Newsgroups: net.lang.c Subject: Re: C Style (goto or not goto, that is the question) Message-ID: <3090008@csd2.UUCP> Date: Thu, 26-Sep-85 19:55:00 EDT Article-I.D.: csd2.3090008 Posted: Thu Sep 26 19:55:00 1985 Date-Received: Sun, 29-Sep-85 08:02:20 EDT References: <190@rtp47.UUCP> Organization: New York University Lines: 127 [] Someone asked for a readable version of the following code: >[example reformatted a bit] > > noecho(); >retry: > move(4,10); > refresh(); > ch = getch(); > if ((ch < '1' || ch > '5') && ch != 'E') { > putchar(BELL); > goto retry; > } > addch(ch); > refresh(); OK, I've now read enough different responses on this to want to finish this topic off once and for all. This code is an example of the general pattern: repeat do stuff; if termination condition has not been satisfied then give error indication; until the termination condition becomes true; If the stuff to be done is very simple, this can be tersely expressed in C as follows: while (combine doing stuff and check that termination condition is not true into one messy expression) give error indication; or, more readably, as: for (do stuff; termination condition is not true; do stuff) give error indication; For example, if we assume that the retry label in the code above is not jumped to from anywhere else, then we could move it down two lines to just before ch=getch() (the calls to move and refresh should not be needed since echoing is turned off with noecho). This assumption is made in all the goto-less versions of this code segment that I've seen. Then the "stuff" to be done just reduces to the assignment ch=getch(), and so the code segment can be written tersely as: noecho(); move(4,10); refresh(); while (((ch=getch())<'1' || ch>'5') && ch!='E') putchar(BELL); addch(ch); refresh(); or, the while loop could be rewritten: for (ch=getch(); ((ch<'1' || ch>'5') && ch!='E'); ch=getch()) putchar(BELL); If the stuff to be done is more complicated, these two forms quickly become unreadable. In this case, you can either combine the stuff to be done as a separate function, and then use the above forms again, or use a do-while loop: do { do stuff; if (termination condition is not true) give error indication; } while (termination condition is not true); or, if the check for the termination condition is very expensive: do { do stuff; if (termination condition is not true) give error indication; else break; } while (TRUE); For example, suppose the calls to move and refresh above *are* necessary before each call to getch. The code above could then be rewritten: mygetch() { move(4,10); refresh(); return getch(); } noecho(); while (((ch=mygetch())<'1' || ch>'5') && ch!='E') putchar(BELL); addch(ch); refresh(); or using a do-while loop: #define invalid(ch) (((ch)<'1' || (ch)>'5') && (ch)!='E') noecho(); do { move(4,10); refresh(); ch=getch(); if (invalid(ch)) putchar(BELL); } while (invalid(ch)); addch(ch); refresh(); or rewrite the do-while loop as: do { move(4,10); refresh(); ch=getch(); if (invalid(ch)) putchar(BELL); else break; } while (TRUE); Isaac Dimitrovsky allegra!cmcl2!csd2!dimitrov (l in cmcl2 is letter l not number 1) 251 Mercer Street, New York NY 10012 (212) 674-8652 ... Hernandez steps in to face ... Orl ... HERchiiiser ... and it's a liiine driive, deeeeep to the gap in left center ... - Bob Murphy, Voice of the Mets