Вложенные циклы в C (требуется лучшее название)

#c #loops

#c #циклы

Вопрос:

Я заканчиваю проект C для класса, который должен быть завтра в 11 вечера, и последняя часть вызывает у меня некоторые проблемы. Я настроил дерево на доске, чтобы у меня была правильная логика, но на самом деле ее реализация оказалась немного сложнее, чем я изначально предполагал.

Назначение для этой части проекта

Функция char_game позволяет пользователю попытаться угадать значение, которое передается в качестве параметра. Подсказка (которая должна быть точно «буквой?» будет печататься каждый раз, когда пользователю предлагается ввести новое значение. Если пользователь вводит символ, который не является алфавитным, функция отвечает, печатая строку «не алфавитный». Если пользователь вводит символ с неправильным регистром (верхний регистр, когда ожидался нижний регистр, или наоборот), функция отвечает, печатая строку «неправильный регистр». Если пользователь угадывает значение, которое слишком велико (позже в алфавите), программа отвечает «слишком высоко», а если пользователь угадывает значение, которое меньше значения параметра, программа отвечает «слишком низко». Если пользователь пытался угадать MAX_GUESSES раз, и до сих пор не угадал значение, функция возвращает 0 вызывающему. Если пользователь угадывает правильное значение, функция возвращает 1 вызывающему. */int char_game(char correct_char);

Дерево, которое я создал для логики, находится здесь: Древовидная диаграмма логики программы

Функция, которую я создал до сих пор, выглядит следующим образом:

 int char_game(char correct_char)
{
    char ch;
    int count;
    int return_num;
    for (count=0;count<=MAX_GUESSES;count  )
    {
        do
        {
            printf("letter?");
            scanf("%c", amp;ch);
        }
        while ((ch <= 'A' || ch >= 'z') || (ch > 'Z' amp;amp; ch < 'a'));

        if ((ch < 'A') || (ch > 'Z' amp;amp; ch < 'a') || (ch > 'z'))
        {
            printf("not alphabeticn");
        }
        else
        {
            break;
        }

        if ((ch >= 'A' amp;amp; ch <= 'Z') amp;amp; (correct_char >= 'a' amp;amp; correct_char <= 'z'))
        {
            printf("wrong casen");
        }
        else if ((ch >= 'a' amp;amp; ch <= 'z') amp;amp; (correct_char >= 'A' amp;amp; correct_char <= 'Z'))
        {
            printf("wrong casen");
        }
        else
        {
            break;
        }

        if (correct_char > ch)
        {
            printf("too lown");
        }
        else if (correct_char < ch)
        {
            printf("too highn");
        }
        else
        {
            break;
        }

    }

    if (correct_char == ch)
    {
        return_num = 1;
    }
    else if (count == MAX_GUESSES);
    {
        return_num = 0;
    }
    else if (correct_char < ch)
    {
        printf("too highn");
    }
    else
    {
        break;
    }
}

if (correct_char == ch)
{
    return_num = 1;
}
else if (count == MAX_GUESSES);
{
    return_num = 0;
}

return return_num;
}
 

Комментарии:

1. Я дам вам 1 за красивую картинку на доске 😉

Ответ №1:

Поскольку вы указали, что у вас возникли проблемы с написанием логики для реализации этого, я бы попробовал этот подход: подумайте о том, что ваша программа должна делать в соответствии с назначением, и попытайтесь описать шаги простым английским языком.

Например:

  1. Получите письмо от пользователя.
  2. Правильна ли буква?
    • верните 1, если это так.
  3. Это неправильный случай?
    • выведите какое-нибудь сообщение пользователю.
  4. Если мы перейдем к этому шагу, мы знаем, что заглавные буквы те же, но ответ неверен. Поэтому проверьте, ниже ли оно.
    • Выведите что-нибудь для этого сценария, если это так.
  5. На данный момент он не ниже, поэтому единственная оставшаяся возможность выше.
    • Выведите что-нибудь для этого сценария.
  6. У нас остались еще какие-нибудь догадки?
    • Если мы вернемся к шагу 1.
    • В противном случае перейдите к следующему шагу.
  7. Мы исчерпали все наши догадки, и мы не угадали правильно. Поэтому верните 0.

После того, как вы отработали шаги, и в вашей голове все стало ясно, возьмите написанный псевдокод и вставьте его в свою функцию в качестве комментария. Попробуйте реализовать каждый из написанных вами шагов.

Если конкретный шаг кажется сложным или сложным, запишите его как отдельную функцию и вызовите ее. Например, вы можете написать Inputletter для обработки шага 1. В нем вы можете проверить, что пользователь ввел что-то разумное, например, букву, и он будет продолжать запрашивать пользователя, если это не так. Когда эта функция возвращает, вы знаете, что пользователь ввел букву, а не что-то фиктивное, например, число или символ.

Наконец, C предоставляет несколько удобных функций, которые вы можете использовать:

  • toupper
  • tolower
  • isalpha

Итак, ваш код, подобный:

 while ((ch <= 'A' || ch >= 'z') || (ch > 'Z' amp;amp; ch < 'a'));

if ((ch < 'A') || (ch > 'Z' amp;amp; ch < 'a') || (ch > 'z'))
 

превращается в гораздо более читаемый:

 while (!isalpha(ch));

if  (!isalpha(ch))
 

Комментарии:

1. Предостережение для последней части ( isalpha и т. Д.) Заключается в том, что учителя иногда наказывают учеников за использование материала, который они еще не преподавали, поскольку они хотят, чтобы они решили это сами.

2. @Matthew Это хороший момент. В таком случае они могут тривиально реализовать свою собственную isalpha функцию.

3. Одна очень раздражающая вещь при написании действительно полезных комментариев к программам заключается в том, что мы используем терминал, и когда я прокручиваю вниз, он не выполняет плавную прокрутку, он прыгает вниз по эквиваленту экрана, а не плавно построчно (надеюсь, вы понимаете, что я говорю), но этоочень хорошее предложение, я начну это делать.

4. @colle Я понимаю, что вы имеете в виду в такой среде. Обратите внимание, что вы можете обрезать псевдокод без подробностей. Основная идея заключается в том, что вы используете его, чтобы направлять свой мыслительный процесс на более высоком уровне, сохраняя при этом содержательный комментарий к вашему коду. Когда вы разрабатываете сложную логику, общая картина легко запутывается кровавыми деталями. Вы можете использовать это, чтобы не сбиться с пути.

Ответ №2:

Где-то у вас слишком много закрывающих фигурных скобок } . В двух местах у вас неуместная точка с запятой в конце следующего:

 else if (count == MAX_GUESSES);
                              ^
 

Комментарии:

1. Спасибо, что указали на точку с запятой. Я не думаю, что какие-либо фигурные скобки являются проблемой, так как 26% 2 ! = 1 😉

2. @colle: Посмотрите еще раз, опубликованный код содержит несбалансированные фигурные скобки.

Ответ №3:

Сначала разбейте его на функции (например, isWrongCase(char правильный, char фактический). Это улучшит читаемость и поможет вам найти ошибки. Вам не нужны два оператора if для неправильного регистра. Помните, что у вас могут быть промежуточные bool или int переменные:

 bool firstPart = ...;
bool secondPart = ...;
if(firstPart || secondPart)
 

Это также может помочь вам организовать.

Вы неправильно используете операторы break. Вы не хотите выходить из цикла в условиях else, но переходите к следующей проверке. Так что вам на самом деле не нужно else .

Поскольку у вас есть цикл for, вы можете просто выполнить MAX_GUESSES возврат после цикла for . Вам не нужно снова проверять количество догадок (count == MAX_GUESSES) в теле цикла.

Комментарии:

1. Я не думаю, что это разрешено в руководстве по проекту, но это хорошая идея. Я могу удалить все остальные {break;}?

2. как вы думаете, я должен поцарапать его и начать все сначала? кажется, это немного зашло далеко. есть ли у вас какой-либо конкретный тип цикла, который, по вашему мнению, наиболее эффективен для этого приложения?

3. Нет, я бы не стал отказываться от него полностью. Цикл for на самом деле в порядке. Я не думаю, что вам нужен цикл do while. В принципе, это будет продолжать вызывать их, пока они не введут букву. Однако проверка букв уже выполнена в другом месте (с выводом). Как уже упоминалось, вы также можете избавиться от дополнительной проверки MAX_GUESSES .

4. Мэтью, спасибо миллион. В конце концов я подождал до сегодняшнего дня и попросил друга помочь мне, и он фактически сделал те же предложения, что и вы.