3

How would I convert the following while loop into a proper do-while without double counting the first time?

void ctype()
{
    char c;
    while ((c = getchar()) != '.')
        printf("'%c' is %s a letter.\n", c, isalpha(c)? "indeed" : "not");
    printf("'%c' is %s a letter.\n", c, isalpha(c)? "indeed" : "not");
}

What I have thus far is:

void ctype()
// Print the letters up through the period, but quit on the period
{
    char c = getchar();
    do {
        printf("'%c' is %s a letter.\n", c, isalpha(c)? "indeed" : "not");
    } while ((c = getchar()) != '.') 
}

But this double-getchar's on the first item. What would be the proper way to do this? It's almost like I want the equivalent of a post-increment on the getchar() in the while loop.


Sample input/ouput of the while loop, which is currently correct:

$ run
.
'.' is not a letter.
$ run
Hello.
'H' is indeed a letter.
'e' is indeed a letter.
'l' is indeed a letter.
'l' is indeed a letter.
'o' is indeed a letter.
'.' is not a letter.
David542
  • 104,438
  • 178
  • 489
  • 842

4 Answers4

8

It can be done like this:

char c;
do {
    c = getchar();
    printf("'%c' is %s a letter.\n", c, isalpha(c)? "indeed" : "not");
} while(c != '.');

In the general case, you can always change

while(<expr>) {
    // Body
}

to

do {
    if(<expr>) break;

    // Body
} while(1);

Note that this is just for a plain conversion to a do-while. There are other flaws in the code. To correct these at the same time:

int c;
do {
    c = getchar();
    if(c == EOF) break;
    printf("'%c' is %s a letter.\n", c, isalpha(c)? "indeed" : "not");
} while(c != '.');
klutt
  • 30,332
  • 17
  • 55
  • 95
5

Another way to check for both '.' and EOF with no duplicate calls to either getchar or printf.

    int c;
    while ((c = getchar()) != EOF)
    {
        printf("'%c' is %s a letter.\n", c, isalpha(c)? "indeed" : "not");
        if(c == '.') break;
    }
dxiv
  • 16,984
  • 2
  • 27
  • 49
2

Following code is equivalent to code written using while loop:

void ctype()
{ 
    char c;
    do {
       c = getchar();
       printf("'%c' is %s a letter.\n", c, isalpha(c)? "indeed" : "not");
    } while (ch != '.');
}
klutt
  • 30,332
  • 17
  • 55
  • 95
g-217
  • 2,069
  • 18
  • 33
1

There's nothing wrong with do - while but generally while is more readable, so stick with the latter if you have the option. Also there's generally nothing wrong with an initial call to the function outside the loop, if that makes the loop code clearer.

There are more concerning problems with this code - you don't check for EOF, you don't discard line feed and you have assignment inside a control or loop condition.

The most readable form is perhaps this:

int c = getchar();

while (c!='.' && c!=EOF)
{
  /* handle the case where c == '\n' */

  /* other stuff */

  c = getchar(); 
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • thanks for the feedback. What's wrong with doing `you have assignment inside a control or loop condition` ? I thought that was a common practice in "c code" ? – David542 Jan 25 '21 at 19:08
  • @David542 There's many problems with it. The code may turn harder to read, you might get accidental mix up between `=` and `==` and you may end up with multiple side effects in the same expression which in turn leads to brittle code. Consider for example `if( (c=getchar()) == c ) // typed same character twice?` which might look like sensible code at a glance, but is actually an undefined behavior bug. – Lundin Jan 26 '21 at 08:46