Почему моя программа FizzBuzz на C++ работает неправильно?

Я создавал программу FizzBuzz на C++, в которой вы печатаете числа от 1 до 100 и заменяете кратные 3 на «Fizz», кратные 5 на «Buzz» и кратные 3 и 5 на «FizzBuzz».

Хотя при запуске кода я не получаю никаких ошибок, но цифры 6, 21, 36 и т. д. не заменяются на «Fizz», тогда как числа 10, 25, 40 и т. д. не заменяются на «Buzz».

Я не понимаю, почему это происходит.

Мой код приведен ниже:

#include <stdio.h>
#include <iostream>
using namespace std;

int main() 
{
    
    for (int i = 1; i < 101; i++)
    {
        
        if ((i%3) == 0 && (i%5) == 0)
        {
            printf("FizzBuzz ");
            i++;
        }
        else if ((i%3) == 0)
        {
            printf("Fizz ");
            i++;
        }
        else if ((i%5) == 0)
        {
            printf("Buzz ");
            i++;
        }
        
        printf("%d ", i);

    }

    return 0;

}

По моему мнению, ожидаемый результат должен быть (с использованием кода Geeks for Geeks):

[Running] cd "d:\Projects\VS Code\Jetlag\helloworld\" && g++ fzz.cpp -o fzz && "d:\Projects\VS Code\Jetlag\helloworld\"fzz
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz 
[Done] exited with code=0 in 6.043 seconds

Это точный результат, который я получаю:

[Running] cd "d:\Projects\VS Code\Jetlag\helloworld\" && g++ FizzBuzz.cpp -o FizzBuzz && "d:\Projects\VS Code\Jetlag\helloworld\"FizzBuzz
1 2 Fizz 4 Buzz 6 7 8 Fizz 10 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz 21 22 23 Fizz 25 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz 36 37 38 Fizz 40 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz 51 52 53 Fizz 55 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz 66 67 68 Fizz 70 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz 81 82 83 Fizz 85 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz 96 97 98 Fizz 100 
[Done] exited with code=0 in 0.987 seconds

Как видно выше, некоторые числа не заменяются.

Любая помощь будет оценена по достоинству.

Вы ++ слишком много раз.

lastchance 27.08.2024 16:31

Я бы также сказал, что порядок оценки неправильный. Если все сделано правильно, вам никогда не придется явно писать «FizzBuzz».

sweenish 27.08.2024 16:33

Вы увеличиваете i как в операторе цикла for, так и в ifs. Также последний отпечаток самого номера должен находиться в ветке else.

wohlstad 27.08.2024 16:33

Добро пожаловать в Stack Overflow! Похоже, вам, возможно, придется научиться использовать отладчик для пошагового выполнения кода. С помощью хорошего отладчика вы можете выполнять программу построчно и видеть, где она отклоняется от ожидаемого. Это важный инструмент, если вы собираетесь заниматься программированием. Дальнейшее чтение: Как отлаживать небольшие программы и Руководство по отладке

NathanOliver 27.08.2024 16:34

Примечание: в C++ обычно рекомендуется не использовать ввод-вывод C (printf).

wohlstad 27.08.2024 16:34

@MarkRansom Я почти уверен, что цель FizzBuzz — стать инструментом обучения. Я не вижу цели вашего комментария. Он не ищет разъяснений, не дает указаний или иным образом помогает ОП. Это снисходительно.

sweenish 27.08.2024 17:24

@sweenish его часто используют в качестве быстрого теста на собеседовании, чтобы проверить, обладает ли кандидат базовым уровнем навыков программирования. Вот несколько примеров обсуждения этого: blog.codinghorror.com/why-cant-programmers-program blog.tdwright.co.uk/2022/07/14/…

Mark Ransom 27.08.2024 17:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
79
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

В вашем коде есть несколько проблем:

  1. Вы увеличиваете i как в операторе цикла for, так и под if. Поскольку вам нужно увеличивать его на каждой итерации, подходящее место — это оператор for.

  2. Последняя печать самого номера должна находиться под блоком else (после предыдущих if/else if): вам следует печатать сам номер только в том случае, если предыдущие случаи обрабатывались блоками if/else if (для «FizzBuzz», «Fizz» и «Базз») не удержались, и для этого нужен финальный else (см. в исправленной версии ниже).

  3. Хотя это может работать, не рекомендуется использовать ввод-вывод C в C++. Вместо этого вы можете использовать std::cout от <iostream>, который вы все равно #included. Еще более современный способ (из C++23) — использовать std::print.

  4. Рекомендуется избегать using namespace std;. См. здесь: В чем проблема с «использованием пространства имен std;»?.

Фиксированная версия:

#include <iostream>

int main()
{
    for (int i = 1; i < 101; i++)
    {
        if (((i % 3) == 0) && ((i % 5) == 0)) {
            std::cout << "FizzBuzz ";
        }
        else if ((i % 3) == 0) {
            std::cout << "Fizz ";
        }
        else if ((i % 5) == 0) {
            std::cout << "Buzz ";
        }
        else {  // this block will be executed only if the previous cases did not hold
            std::cout << i << " ";
        }
    }
}

Live demo

или std::print, если доступен C++23

Caleth 27.08.2024 16:47

В @sweenish OP нет else, в фиксированном коде он есть

Caleth 27.08.2024 16:47

@sweenish Я отредактировал и попытался подчеркнуть тот факт, что его следует печатать в блоке else после предыдущих if. Пожалуйста, не стесняйтесь перефразировать, если вы можете помочь лучше прояснить суть.

wohlstad 27.08.2024 16:50

@Калет Я думал, что упоминание std::print слишком сложно для этого поста, но я добавлю комментарий по этому поводу.

wohlstad 27.08.2024 16:51

@wohlstad Я считаю это типобезопасным printf

Caleth 27.08.2024 16:52

@Caleth добавил комментарий по этому поводу.

wohlstad 27.08.2024 16:53

@sweenish снова отредактировал и приложил все усилия, чтобы прояснить ситуацию.

wohlstad 27.08.2024 16:58

Большое спасибо за понимание. Я попробую, но обычно std:cout меня сбивает с толку, поэтому я избегаю его использования (даже не знаю, почему я включил <iostream>). К тому же, мне больше привычна stdio библиотека. Причина, по которой я увеличиваю i в if, заключается в том, чтобы пропустить это число, перейдя к следующему номеру после того, как будет напечатано «Fizz»/«Buzz»/«FizzBuzz». Это устраняет необходимость в утверждении else.

Redstoner824 27.08.2024 17:38

@Redstoner824 рад помочь. Кстати, я не понимаю, как ваша попытка сохранить else путем увеличения i в ifs может быть правильно реализована без усложнения решения, и думаю, что использование else здесь вполне естественно. Что касается использования printf — решать вам, конечно, но многие эксперты по C++ рекомендуют его избегать. Вы можете посмотреть std::print, упомянутый в моем ответе, а также в другом ответе.

wohlstad 27.08.2024 17:47

Ответ выше хорошо отвечает на вопрос. Я просто хотел предоставить альтернативную версию FizzBuzz.

#include <print>

int main() {
  for (int i = 1; i < 101; ++i) {
    if (i % 3 == 0) {
      std::print("Fizz");
    }
    if (i % 5 == 0) {
      std::print("Buzz");
    }
    if (i % 3 != 0 && i % 5 != 0) {
      std::print("{}", i);
    }
    std::print("\n");
  }
}

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

std::print взят из C++23 и намного безопаснее, чем printf. В противном случае я бы тоже рекомендовал std::cout.

FizzBuzz действительно требует разных решений, и ваша демонстрация альтернативной логики будет полезна. +1.

wohlstad 27.08.2024 17:26

Я обнаружил ошибку в своем коде. Мне пришлось поместить оператор printf в блок else и удалить приращение i из оператора if.

Это, конечно, мой способ решения FizzBuzz.

Окончательный код выглядит так:

#include <stdio.h>

int main()
{
    for (int i = 1; i < 101; i++)
    {
        if ((i % 3) == 0 && (i % 5) == 0)
        {
            printf("FizzBuzz ");
        }
        else if ((i % 3) == 0)
        {
            printf("Fizz ");
        }
        else if ((i % 5) == 0)
        {
            printf("Buzz ");
        }
        else
        {
            printf("%d ", i);
        }
    }
}

Спасибо всем за помощь и быстрый ответ.

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

wohlstad 27.08.2024 17:59

Я чувствую, что этот ответ устраняет необходимость в <iostream> или <print> и основан исключительно на C I/O, который я изначально использовал, но я удалю этот ответ, если он покажется ненужным.

Redstoner824 27.08.2024 18:28

Я уже писал свое мнение по поводу использования printf, но строгих правил против этого нет, так что решать вам. В любом случае спасибо, что приняли мой ответ.

wohlstad 27.08.2024 18:46

Другие вопросы по теме