Песочные часы в C ++ с добавлением аргументов - PullRequest
2 голосов
/ 06 января 2020

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

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

Мне также нужно добавить аргументы в этот код, но я действительно не знаю, как Так что, если вы могли бы помочь мне, вы сделаете мне одолжение.

Вот код, который я сделал (не работает должным образом):

#include <iostream>
#include <string>

using namespace std;

int main()
{

    int height, base, distance, jeg, backup1, backup2, backup3;

    base = 2 * height - 1;
    distance = 1;
    jeg = base - 2;

    cout << "write the height";
    cin >> height;

    while (backup1 > 0)
    {
        cout << "0";
        backup1 = backup1--;
    }
    cout << "\n";
    height = height - 1;

    while (height > 1)
    {
        backup1 = distance;
        while (backup1 > 0)
        {
            cout << " ";
            backup1 = backup1--;
        }
        backup2 = jeg;
        while (backup2 > 0)
        {
            cout << "#";
            backup3 = backup3--;
        }
        cout << "\n";

        height = height--;
        distance = distance++;
        jeg = jeg - 2;
    }

    backup1 = distance;
    while (backup1 > 0)
    {
        cout << " ";
        backup1 = backup1--;
    }
    cout << "#\n";

    height = backup2 - 1;
    distance = distance--;
    jeg = jeg + 2;

    while (height > 1)
    {
        backup1 = distance;
        while (backup1 > 0)
        {
            cout << " ";
            backup1 = backup1--;
        }
        backup2 = jeg;
        while (backup2 > 0)
        {
            cout << "#";
            backup3 = backup3--;
        }
        height = height--;
        distance = distance--;
        jeg = jeg + 2;
    }

    backup1 = base;

    while (backup1 > 0)
    {
        cout << "#";
        backup1 = backup1--;
    }
    cout << "\n";

}

Редактировать # 1: извините за непонятность. Я ожидал что-то подобное в конце пробега:

#############
 ###########
  #########
   #######
    #####
     ###
      #
     ###
    #####
   #######
  #########
 ###########
#############

Ответы [ 4 ]

3 голосов
/ 06 января 2020

Сначала следующий блок выполняется до инициализации height, и вам нужно переместить его после cin>> height:

base = 2 * height - 1;
distance = 1;
jeg = base - 2;

Следующая существенная проблема заключается в том, что вы * l oop на backup1, который не инициализирован. Хуже : даже если вы инициализируете его, следующее утверждение является реальной проблемой :

backup1 = backup1--;    // OUCH !!!

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

backup1--;             // alternative 1
backup1 = backup1 -1;  // alternative 2
backup1 -= 1;          // alternative 3

И вам нужно удалить все подобные конструкции для backup2 и backup3, height и distance (также с distance++)

Наконец, у вас есть бесконечное число l oop:

while(backup2>0) {   // you loop on backup2
   cout << "#";  
   backup3--;      // but it doesn't change since you decrement the wrong variable
}

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

Демо онлайн


Важно знать:

Наличие двух побочных эффектов для одной и той же переменной в одной и той же переменной выражение является неопределенным поведением в соответствии с [intro.execution]/10 в пункте 6.8.1 стандарта:

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

В вашем случае это немного отличается, так как в соответствии с [expr.ass]/1 в пункте 8.5.18:

Во всех случаях присваивание секвенируется после вычисления значения правого и левого операндов и перед вычислением значения выражения присваивания.

Так что в вашем случае это не UB, а просто то, что ваше утверждение гарантирует, что уменьшение игнорируется из-за постфикса.

1 голос
/ 07 января 2020

Там много неправильно с вашим кодом. Для начала:

int ..., backup1, ...;

while(backup1 > 0) {
    cout << "0";
    backup1 = backup1--;
}

Какое там значение backup1? Ответ фигня! Это неопределенное поведение, поэтому значение в backup1 может быть любым целым числом !! Поэтому неудивительно, что вы видите целую кучу 0!

Но если предположить, что мы это исправим, то, возможно, что-то вроде int backup1 = 5;, backup = backup--; также будет неопределенным поведением !!

Небольшие ошибки, подобные этим, повсюду в вашем коде ( @ Christophe хорошо объясняет их в своем ответе). Поэтому я настоятельно рекомендую вам удалить это и переписать. Позвольте мне дать вам несколько советов, чтобы вам было легче ...


У вас хорошее начало, вы поняли, что верх и низ песочных часов будут 2 * height - 1. Это хорошо. Мой первый совет для вас - перестать пытаться печатать по одному резкому за раз. Вы можете очень легко создать строку с некоторым количеством одинаковых символов, используйте это!

Например, поскольку вы знаете, сколько острых предметов в первом ряду, вы можете вывести ее с помощью:

int num_sharps = 2*height - 1;
int num_spaces = 0;
std::cout << std::string(num_spaces, ' ')
          << std::string(num_sharps, '#')
          << std::endl

Это выведет num_spaces количество пробелов, затем num_sharps количество острых предметов и затем новую строку. Viola!

И теперь следующая строка, которую нужно напечатать, будет иметь на два резких резца меньше этого и еще один пробел, поэтому обновите эти значения соответствующим образом и снова запустите выходную строку!

С этим, Вы должны быть в состоянии очень легко и чисто изготовить свои песочные часы (хотя вам может понадобиться второй l oop для другой половины!).

И в качестве бонуса просто для удовольствия, вот полный решение всего за несколько строк, чтобы показать, что с достаточным количеством математики возможно все: D

0 голосов
/ 07 января 2020

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

#include <iostream>

using namespace std;

int main()
{
    int height, spaces = 0, nextLayer;
    do
    {
        cout << "Insert the height of the hourglass: ";
        cin >> height;
    }while(height > 0 && height%2 == 0); //Loop into asking a valid height

    nextLayer = height; //First layer has the same number of # as there are number of layers, aka height

    //First loop for the top part of the hourglass
    for(int c = 0; c < height/2 + 1; c++)
    {
        for(int k = 0; k < spaces; k++)
        {
            cout << " ";
        }
        for(int k = 0; k < nextLayer; k++)
        {
            cout << "#";
        }
        cout << endl; //end the line
        nextLayer = nextLayer - 2; //Decrease the number of #
        spaces++; //Augment the indentation
    }

    /*
    ** Since we are now going to make the bottom specular part
    ** let's "come back" by two loops
    */
    nextLayer = nextLayer + 4;
    spaces = spaces - 2;

    //Second loop for the bottom part of the hourglass
    for(int c = 0; c < height/2; c++)
    {
        for(int k = 0; k < spaces; k++)
        {
            cout << " ";
        }
        for(int k = 0; k < nextLayer; k++)
        {
            cout << "#";
        }
        cout << endl;
        nextLayer = nextLayer + 2;
        spaces--;
    }
}

0 голосов
/ 06 января 2020

Вы должны получить предупреждение здесь:

int height, base, distance, jeg, backup1, backup2, backup3;

base = 2 * height - 1;
distance = 1;
jeg = base - 2;

за использование height, когда оно не инициализировано. Вы должны сначала принять пользовательский ввод, а затем использовать значение, а не наоборот. После этого все может случиться. Использование base здесь и далее в коде вызывает неопределенное поведение. Также backup1 = backup1--; определенно не делает то, что вы думаете, что делает.

Для печати определенного символа, например, '#', n - вы можете использовать

std::cout << std::string(n,'#');

В al oop вы можете написать:

for (int i=0;i< height*2 + 1; ++i) {
    auto empty = height - std::abs( height - i);
    std::cout << std::string(empty,' ') << "x\n";    
}

получить за height == 6:

x
 x
  x
   x
    x
     x
    x
   x
  x
 x
x

Отсюда всего лишь маленький шаг, чтобы заполнить песочные часы:

#include <iostream>
#include <iomanip>
int main() {
    int height;
    std::cin >> height;

    for (int i=0;i< height*2 + 1; ++i) {
        auto empty = height - std::abs( height - i);
        auto fill = 2*(height-empty)+1;
        std::cout << std::string(empty,' ') << std::string(fill,'x') << "\n";    
    }
}
...