Если оператор внутри цикла while с тем же условием - PullRequest
0 голосов
/ 31 октября 2018

Есть ли лучший способ написать следующий код, исключив повторяющиеся условия в операторе if в C?

while (n < 0) {
   printf("Enter a positive integer: ");
   scanf("%d", &n);

   if (n < 0) {
      printf("Error: please enter a positive integer\n");
   }
}

Спасибо.

Ответы [ 5 ]

0 голосов
/ 31 октября 2018

Другая альтернатива - разделить на функцию:

int func(){
   int n;
   printf("Enter a positive integer: ");
   scanf("%d", &n);
   return scanf("%d", &n) == 1 ? n : -1;
}

и цикл становится

while ((n = func()) < 0){
    printf("Error: please enter a positive integer\n");
}

хотя назначение в проверке состояния не всем по вкусу. Обратите внимание, что я возвращаю -1, если возвращаемое значение scanf не равно 1, что вы всегда должны проверять.


Что я делаю в этой ситуации (см. Ответ Эрика), так это пишу

switch (0) do {
    printf("Error, please enter a positive integer\n");
case 0:
    printf("Enter a positive integer: ");
    scanf("%d", &n);
} while (n/*ToDo - make sure n is initialised if scanf fails*/ < 0);
0 голосов
/ 31 октября 2018

Вы можете использовать:

while (printf("Enter a positive integer: ") > 0 &&
       scanf("%d", &n) == 1 &&
       n < 0)
{
    printf("Error: please enter a positive integer\n");
}

Останавливается, если происходит сбой printf(), если происходит сбой scanf() или если значение в n неотрицательно. Хорошая идея всегда проверять, что scanf() успешен. Просто удобно, что printf() возвращает количество написанных им символов (или отрицательное число при неудаче), чтобы его можно было использовать и в условии. Вы также можете добавить fflush(stdout) == 0 && в стек операций.

Или вы можете решить, что код в условии должен быть в функции:

static int read_positive_integer(void)
{
    int value;
    if (printf("Enter a positive integer: ") > 0 &&
        fflush(stdout) == 0 &&
        scanf("%d", &value) == 1 &&
        value >= 0)
        return value;
   return -1;
}

, а затем вызывающий код:

while ((n = read_positive_integer()) < 0)
    printf("Error: please enter a positive integer\n");

Есть много вариаций на тему; вы можете заключить цикл while в функцию; Вы можете сделать подсказки в параметрах функции. Возможно, вы решите быть более осторожным, сообщая о том, что идет не так (другие действия, если printf() завершается неудачей, по сравнению с тем, что происходит, если scanf() возвращает 0 (нечисловые данные на входе) или EOF (больше нет данных на входе).

0 голосов
/ 31 октября 2018

Следующие примеры представлены в том духе, что люди должны знать, что доступно на языке. 1 То, как я обычно пишу код, показано в ответ Frankie_C . Как уже отмечалось, оптимизация обычно делает этот простой случай не заслуживающим беспокойства, но вопрос не ограничивается простой оценкой, такой как n < 0; тест может быть вызовом функции для дорогостоящей оценки более сложных критериев.

Людям это не понравится, но:

    goto middle;
    do
    {
        printf("Error, please enter a positive integer\n");
middle:
        printf("Enter a positive integer: ");
        scanf("%d", &n);
    } while (n < 0);

Если вы категорически против goto, вы можете использовать урезанную версию устройства Даффа :

    switch (0)
    do
    {
        printf("Error, please enter a positive integer\n");
    case 0:
        printf("Enter a positive integer: ");
        scanf("%d", &n);
    } while (n < 0);

Но вы не должны.

Сноска

1 Обычно разработчикам программного обеспечения приходится работать с кодом, написанным другими, поэтому они должны быть готовы к распознаванию и пониманию всего, что можно выразить в языке, даже если это только первый шаг к его переписыванию. в лучший код. И иногда возникают ситуации, когда «уродливый» код становится желательным по коммерческим или другим практическим причинам.

0 голосов
/ 31 октября 2018

Это то, что IMO лучше всего выполнить с небольшим рефакторингом:

#include <stdio.h>
#include <stdbool.h>

static bool get_postive_integer(int *pOut) {
    int n;
    printf("Enter a positive integer: ");
    scanf("%d", &n);

    if(n < 0)
        return false;

    *pOut = n;
    return true;
}

int main(void)
{
   int n;
   while (!get_postive_integer(&n)) {
       printf("Error: please enter a positive integer\n");
   }
}

Дайте операции имя , проверьте, что она не удалась, и только затем распечатайте сообщение соответствующим образом. Условие успеха или сбоя здесь кодируется только один раз в указанной операции.

0 голосов
/ 31 октября 2018

Просто переделайте разрыв вашей петли, когда задан правильный ввод. Таким образом, проверка выполняется только один раз:

while (1)
{
   printf("Enter a positive integer: ");
   scanf("%d", &n);

   if (n >= 0)
       break;

   printf("Error: please enter a positive integer\n");
}

И, как указано в комментариях, оптимизированный компилятор должен иметь возможность полностью перевернуть цикл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...