18.3.2: do/while

[This section corresponds to K&R Sec. 3.6]

Briefly stated, a do/while loop is like a while loop, except that the body of the loop is always executed at least once, even if the condition is initially false. We'll motivate the usefulness of this loop with a slightly long example.

We know that the digit character '1' is not the same as the int value 1, and that the string "123" is not the same as the int value 123. We've learned that the atoi function will convert a string (containing digits) to the corresponding integer, and that we can use the sprintf function to generate a string of digits corresponding to an integer. Now let's see how we could convert an integer to a string of digits by hand, if for some reason we couldn't use sprintf but had to do it ourselves.

If the number were less than 10 and not negative, it would be easy. Since we know that the digit characters '0' to '9' have consecutive character set values, the expression i + '0' gives the character corresponding to i's value if i is an integer between 0 and 9, inclusive. So our very first stab at an integer-to-string routine, which would only work for one-digit numbers, might look like this:

	char string[2];
	string[0] = i + '0';
	string[1] = '\0';
(Remember, the null character \0 is required to terminate strings in C.)

The limitation to single-digit numbers is obviously not acceptable. Suppose we went a little further, and arranged to handle numbers less than 100, by using an if statement to choose between the 1-digit case and the 2-digit case:

	char string[3];
	if(i < 10)
		{
		string[0] = i + '0';
		string[1] = '\0';
		}
	else	{
		string[0] = (i / 10) + '0';
		string[1] = (i % 10) + '0';
		string[2] = '\0';
		}
In the two-digit case, the subexpression i % 10 gives us the value of the low-order (1's) digit of the result, and i / 10 gives us the high-order (10's) digit.

We've still got a pretty limited piece of code, and if we kept extending it in this way, with explicit if statements depending on how many digits the number could have, we'd duplicate a lot of code and end up with quite a mess, and we wouldn't necessarily know how many cases we'll need (at least 5, because type int is guaranteed to hold integers up to at least 32,767, but on some systems it can hold more). The right solution to this problem, therefore, involves a loop.

One way of thinking about if statements and while loops is that an if statement allows you to select a chunk of code which, if required, will complete some step towards the accomplishment of an overall task, while a while loop selects a chunk of code that will whittle away at some task or subtask, but without necessarily completing it on the first go, such that several trips through the loop might be required. Since the operation i % 10 does give us one digit of our answer, but since we may end up having many digits, our next attempt is to wrap the i % 10 and i / 10 code up in a while loop:

	char string[25];
	int j = 24;
	string[j] = '\0';
	while(i > 0)
		{
		string[--j] = (i % 10) + '0';
		i /= 10;
		}
Here we use an auxiliary variable j to keep track of which element of the string array we're filling in. We fill in the array from the end back towards the beginning, because successive remainders when dividing i by 10 give us digits in the reverse order (the reverse, that is, of the order we'd write the digits left-to-right). In this clde, j holds the index of the element we've just filled in, so we use the predecrement form --j to decrement j before filling in the next digit. When we're done, string[j] will be the first (leftmost) digit of our result. (For the string array as declared, i had better have fewer than 25 digits, but this is a safe assumption even for 64-bit machines.)

The third try just above, using a while loop, will work just fine except in the case when i == 0. If i is 0, the controlling expression i > 0 of the while loop will immediately be false, and no trips through the loop will be taken. This means that the integer 0 will be converted to the empty string "", not the string "0". In this case, we would like to take one trip through the loop (to generate the digit 0) even though the condition is initially false.

For loops like these, C has the do/while loop, which tests the condition at the bottom of the loop, after making the first trip through without checking. The syntax of the do/while loop is

	do statement
	while( expression );
The statement is almost always a brace-enclosed block of statements, because a do/while loop without braces looks odd even if there's only one statement in the body. Notice that there is a semicolon after the close parenthesis after the controlling expression.

Using a do/while loop, we can write our final version of the integer-to-string converter:

	char string[25];
	int j = 24;
	string[j] = '\0';
	do	{
		string[--j] = (i % 10) + '0';
		i /= 10;
		} while(i > 0);
This version is now almost perfect; its only deficiency is that it has no provision for negative numbers.

C's do/while loop is analogous to the repeat/until loop in Pascal. (C's while loop, on the other hand, is like Pascal's while/do loop.)


Read sequentially: prev next up top

This page by Steve Summit // Copyright 1996-1999 // mail feedback