Цикл Do-while - что не так с завершающим условием?
Поэтому я недавно начал изучать книгу Стивена Кочана "Программирование на C", и сейчас я нахожусь на главе 8 - "Функции". У меня проблема с упражнением 8.16: "Измените Программу 8.14 так, чтобы пользователь мог преобразовать любое количество целых чисел. Обеспечьте завершение программы при вводе нуля в качестве значения числа, которое нужно преобразовать".
Код для Программы 8.14 следующий:
#include <stdio.h>
#include <stdlib.h>
int convertedNumber[64];
long int numberToConvert;
int base;
int digit = 0;
void getNumberAndBase(void)
{
printf("Number to be converted? ");
scanf("%li", &numberToConvert);
printf("Base? ");
scanf("%i", &base);
if ( base < 2 || base > 16)
{
printf("Bad base - must be between 2 and 16\n");
base = 10;
}
}
void convertNumber(void)
{
do
{
convertedNumber[digit] = numberToConvert % base;
digit++;
numberToConvert /= base;
}
while ( numberToConvert != 0);
}
void displayConvertedNumber (void)
{
const char baseDigits[16] =
{ '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
int nextDigit;
printf ("Converted number =");
for (--digit; digit >= 0; digit--)
{
nextDigit = convertedNumber[digit];
printf("%c", baseDigits[nextDigit]);
}
printf("\n");
}
int main (void)
{
void getNumberAndBase (void), convertNumber(void),
displayConvertedNumber (void);
getNumberAndBase();
convertNumber ();
displayConvertedNumber ();
return 0;
}
Сначала я хотел использовать цикл do-while вокруг трех функций в следующих основных функциях:
do
{
getNumberAndBase();
convertNumber ();
displayConvertedNumber ();
}
while ( numberToConvert != 0);
но, видимо, это не работает. Это последнее упражнение в этой главе, мне удалось сделать все остальное, но не для всего мира, я могу понять, что здесь не так. Возможно, я просто упускаю что-то очевидное.
3 ответа
Когда ваш do-while
условие проверено, всегда ноль. Метод convertNumber()
имеет свой do-while
это продолжается до тех пор, пока numberToConvert не станет равным нулю.
do
{
getNumberAndBase();
convertNumber (); // Sets numberToConvert to zero before returning
displayConvertedNumber ();
}
while ( numberToConvert != 0);
void convertNumber(void)
{
do {
...
} while ( numberToConvert != 0);
}
Частично проблема заключается в том, что переменные-члены используются для передачи возвращаемых значений методов. Методы имеют побочные эффекты, которые не очевидны.
Вместо этого рассмотрим возврат значений из методов.
long int numberToConvert = 0;
do
{
numberToConvert = getNumberAndBase();
long int convertedNumber = convertNumber( numberToConvert );
displayConvertedNumber ( convertedNumber );
}
while ( numberToConvert != 0);
Теперь локальная переменная numberToConvert не зависит от метода convertNumber(), и вы можете определить поведение цикла из локального контекста.
numberToConvert
уже используется convertNumber()
так что давайте не будем беспокоить это.
Поставить весь блок
getNumberAndBase();
convertNumber (); // Sets numberToConvert to zero before returning
displayConvertedNumber ();
внутри while(1)
цикл и поставить проверку на numberToConvert
значение в getNumberAndBase()
функция. Вырвитесь из цикла, как только вы получите значение 0.
Конечно, вы можете использовать другой do...while
цикл, но каким-то образом вам нужно использовать numberToConvert
отсканированное значение для соответствия условию
"... Обеспечить завершение программы при вводе нуля в качестве значения числа, которое нужно преобразовать".
Это сказало,
- Всегда проверяйте возвращаемое значение
scanf()
обеспечить успех. - Не просто используйте глобальные переменные, они могут нести скрытые проблемы, когда программа начинает расширяться. Определите локальные переменные и передайте их (или указатель на них) как можно дольше.
Большой уровень инкапсуляции - это все, что нам нужно. :)
Это упражнение является сложным, потому что оно требует использования глобальных переменных - что работает против правильного использования функций.
Во всяком случае, вот мое решение. Обратите внимание, что gDigit должен быть установлен в 0 каждый раз, когда число должно быть преобразовано.
/* Exercise 7.16
Modify Program 7.15 so that the user can convert any number of integers.
Make provision for the program to terminate when a zero is typed in as
the value of the number to be converted.
notes: includes the modified version of Program 7.15 from Exercise 7.15
the statement gDigit = 0 has been moved from the start of the program to
the start of the convertNumber() function -- gDigit must be set to 0 each
time a number is to be converted
*/
#include <stdio.h>
int gConvertedNumber[64];
long int gNumberToConvert;
int gBase;
int gDigit;
void getNumber (void)
{
printf ("\nNumber to be converted (0 to exit)? ");
scanf ("%li", &gNumberToConvert);
}
void getBase (void)
{
do {
printf ("Base (between 2 and 16)? ");
scanf ("%i", &gBase);
}
while ( gBase < 2 || gBase > 16 );
}
void convertNumber (void)
{
gDigit = 0;
do {
gConvertedNumber[gDigit] = gNumberToConvert % gBase;
++gDigit;
gNumberToConvert /= gBase;
}
while ( gNumberToConvert != 0 );
}
void displayConvertedNumber (void)
{
const char baseDigits[16] =
{ '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
printf ("Converted number = ");
for ( --gDigit; gDigit >= 0; --gDigit )
printf ("%c", baseDigits[gConvertedNumber[gDigit]]);
printf ("\n");
}
int main (void)
{
void getNumber (void);
void getBase (void);
void convertNumber (void);
void displayConvertedNumber (void);
while (1) {
getNumber ();
if ( gNumberToConvert == 0 )
break;
getBase ();
convertNumber ();
displayConvertedNumber ();
}
return 0;
}