Цикл 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;
}
Другие вопросы по тегам