Первое предложение проекта в приложении SoloLearn гласит:

Теперь давайте создадим метод, который будет отображать пирамиду любой высоты в окне консоли с помощью звездочек (*).

…и меня начинает тошнить…

Я запустил Visual Studio и создал новое консольное приложение под названием StarPyramid. Я стер образец кода в методе Main и смотрю…

Вот мои мысли:

  • Будет цикл, который повторяется в зависимости от количества строк, которые вводит пользователь.
  • Первая строка выводит на экран 1 звезду, а затем каждая последующая строка берет количество звезд из предыдущей строки и добавляет 1.
  • Как только количество запусков цикла превысит исходное введенное число, программа остановится.
  • Методу Main потребуется вызвать другой метод, чтобы сделать все вышеперечисленное.

Итак, давайте сначала создадим основы метода:

static void printStarRows(int n) {
}

Таким образом, создается метод с именем printStarRows и готовится принять переменную с именем n, которая имеет тип данных integer. Я собираюсь перейти к методу Main и попросить пользователя ввести данные, например:

static void Main(string[] args) {
     Console.Write(“How many rows?”);
     int n = Console.ReadLine();
     printStarRows(n);
}

Я также добавил Console.WriteLine(n); к методу printStarRows, чтобы проверить, будут ли принятие и отправка от количества строк работает.

Окно Ошибка уже говорит: Невозможно неявно преобразовать тип "string" в "int".

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

…после некоторых исследований…

…Я нашел на веб-сайте Universal Class статью под названием Реализация пользовательского ввода в программировании на C#. В посте автор написал:

Пользовательский ввод всегда является строкой…

В этом случае я заменю int n = console.ReadLine(); на int n = Convert.ToInt32(Console.Readline());

Хорошо, значит работает! Хорошо. Затем давайте создадим цикл for, который будет выполняться до тех пор, пока не будет напечатано столько строк, сколько будет введено пользователем. Я сделаю это так:

for(int i = n; i <= n, i++) {
     Console.WriteLine(i);
}

Я уже пробовал это, и это не сработало. То есть я ожидал, что он выведет на экран 5, 4, 3, 2, 1.

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

  • Переменная с именем i создается с типом данных integer, и ее значение устанавливается таким же, как n, поэтому i = 5.
  • Затем он проверяет, меньше или равно ли i n. В этом случае 5 меньше или равно 5?
  • Это так, поэтому текущее значение i, равное 5, выводится на экран.

ОК, пока я вижу одну проблему: увеличение приведет к тому, что следующее значение i будет равно 6, и когда он проверит, меньше ли 6, чем или равно 5, так как это не так, программа завершится. Похоже, мне нужно уменьшить значение, поэтому я изменю код следующим образом:

for(int i = n; i <= n, i--) {
     Console.WriteLine(i);
}

Таким образом, хотя этот вывел 5 на экран, затем 4, а затем 3, он просто сохранил шли и шли и никогда не останавливались. Это связано с тем, что при уменьшении тест ВСЕГДА обнаружит, что значение i меньше или равно значению n , так что это никогда не остановится.

Я решил изменить проверку, поэтому мой новый код показывает:

for(int i = n; i != 0; i--) {
     Console.WriteLine(i);
}

Другими словами, если значение i не равно 0, вывести значение i на экран. Если оно равно 0, выходим из цикла for. И это сработало! Он выводит 5, 4, 3, 2, 1 на экран. Я полагаю, однако, что в этот момент я должен изменить его так, чтобы наименьшее число печаталось первым. Это будет соответствовать наименьшему количеству звезд, напечатанных первым.

Хм… В таком случае я инициализирую значение i равным 1, а не устанавливаю его равным тому, что ввел пользователь. Я также верну уменьшение на увеличение. Наконец, необходимо проверить, является ли текущее значение i меньше или равным n. Итак, вот обновленный код:

for(int i = 1; int <= n; i++) {
     Console.WriteLine(i);
}

Хорошо, это сработало, и теперь он считает от 1 до 5. Моя следующая мысль заключается в том, что мне нужен дополнительный цикл for, который будет печатать звезды столько раз, сколько раз равно текущему значению i. Итак, внутри цикла for я добавил следующее:

for (int i = 1; int <= n; i++) {
     for (int x = 0; x <= i; x++) {
          Console.Write(i);
     }
}

Обратите внимание, что я также изменил Console.WriteLine(i); на Console.Write(i);, благодаря чему каждое число будет выводиться на экран в одной строке. Однако при запуске этот код выдал следующее:

11222333344444555555

Похоже, что каждое число печатается на 1 раз больше, чем его значение. Кроме того, каждое число находится в одной строке. Я добавил следующее вне внутреннего цикла for, например:

for (int i = 1; int <= n; i++) {
     for (int x = 0; x <= i; x++) {
          Console.Write(i);
     }
     Console.WriteLine();
}

Дополнительный Console.WriteLine(); вызывает возврат каретки после каждого прохождения через внутренний цикл for, что приводит к следующему результату:

11

222

3333

44444

555555

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

Поскольку я начинаю переменную x с 0, у нее есть ДВЕ возможности, чтобы проверка вернулась как истина:

  • Когда x равно 0, проверка на 0 меньше или равна 1, возвращается как true, и выводит на экран значение i (которое равно 1), а затем
  • Когда x равно 1, проверка на 1 меньше или равна 1, возвращается как true, и выводит значение i на экран (которое по-прежнему равно 1) снова!!

Я изменил начальное значение x с 0 на 1, и когда код запускается, получается следующее:

1

22

333

4444

55555

ИЗОБРАЖЕНИЕ

Последним шагом является печать «*» вместо числа, поэтому я изменил самый внутренний цикл for, и теперь весь метод printStarRows выглядит следующим образом:

static void printStarRows(int n) {
     for (int i = 1; i < n; i++) {
          for (int x = 1; x <= i: x++) {
               Console.Write(“*”);
          }
          Console.WriteLine();
     }
     Console.Read();
}

При запуске со значением 5 он напечатал следующий результат:

*

**

***

****

*****

Это хорошо, НО… задача состоит в том, чтобы главная звезда оказалась в центре. Другая проблема заключается в том, что в каждой строке всегда должно быть напечатано нечетное количество звездочек, одна из которых всегда находится в центре. Другими словами, вторая строка печатает 3 звезды, а не 2!

Хотя до этого момента я очень мало смотрел на приложение SoloLearn, я смотрю на него сейчас, и оно показывает проверку в цикле for, который печатает звезды, как x ‹= 2 * i, а этого я не понимаю.

…после некоторых исследований…

Я нашел на YouTube видео от We The Computer Guys под названием Практические программы на C и задания — Печать шаблонов 8, в котором конкретно говорилось об этой формуле. Однако сначала он изложил образец в виде такой таблицы:

Затем он описал количество звездочек в строке, которое связано с номером строки, и что формула, которую можно использовать для получения количества звездочек, состоит в том, чтобы взять номер строки, умножить на 2, а затем вычтите 1(или (row*2)-1). Это НЕ пришло бы мне в голову, но он прав:

  • (1 * 2) — 1 = 1
  • (2 * 2) — 1 = 3
  • (3 * 2) — 1 = 5
  • (4 * 2) — 1 = 7
  • (5 * 2) — 1 = 9

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

static void printStarRows(int numOfRows) {
     for (int row = 1; row <= numOfRows; row++) {
          for (int star = 1; star <= row; star++) {
               Console.Write(“*”);
          }
          Console.WriteLine();
     }
     Console.Read();
}
static void Main(string[] args) {
     Console.Write(“How many rows?”);
     int numOfRows = Convert.ToInt32(Console.ReadLine());
     printStarRows(numOfRows);
}

Чего здесь нет (и почему, когда мы запускаем этот код сейчас, все звездочки выровнены по левому краю), так это пробелов. Нам нужен цикл for для выполнения пробелов сразу после первого цикла for метода. Опять же, я не уверен, что это было бы естественным для меня, но формула для определения количества пробелов состоит в том, чтобы взять количество строк и вычесть номер строки. Формула такова: colSpace = numOfRows - row, поэтому для каждого из наших значений вот результат:

  • 5–1 = 4
  • 5–2 = 3
  • 5–3 = 2
  • 5–4 = 1
  • 5–5 = 0

Код для этого выглядит следующим образом:

static void printStarRows(int numOfRows) {
     for (int row = 1; row <= numOfRows; row++) {
     for (int colSpace = numOfRows — row; colSpace >= 1; colSpace — )
     {
     Console.Write(“ “);
}

Точнее, вот что происходит каждый раз в этом цикле:

  • В первый раз в цикле мы имеем дело с номером строки 1, и у нас всегда будет число, которое пользователь ввел изначально, то есть 5. Итак, снова в первый раз в цикле переменная colSpace инициализируется как numOfRows - row, что преобразуется в colSpace = 5 - 1 > или colSpace = 4.
  • Теперь на экран выводится пробел, а курсор остается на той же строке. Кроме того, значение colSpace уменьшается с 4 до 3.
  • Во второй раз в цикле проверяется, является ли colSpace больше или равным 1 или colSpace ›= 1, что означает, что равно 3 больше или равно 1?
  • Поскольку это так, теперь на экран выводится пробел, а курсор остается на той же строке. Имейте в виду, что это печатное пространство находится рядом с печатным пространством, которое появилось в результате последнего прохождения цикла. Кроме того, значение colSpace уменьшается с 3 до 2.
  • В третий раз в цикле проверяется, является ли colSpace больше или равным 1 или colSpace ›= 1, что означает равно 2 больше или равно 1?
  • Поскольку это так, пробел теперь печатается на экране, а курсор остается в той же строке. Теперь рядом друг с другом есть 3 пробела. Кроме того, значение colSpace уменьшается с 2 до 1.
  • В четвертый раз в цикле проверяется, является ли colSpace больше или равным 1 или colSpace ›= 1, что переводится как равно 1 больше или равно 1?
  • Поскольку это так, пробел теперь печатается на экране, а курсор остается в той же строке. Теперь рядом друг с другом 4 пробела. Кроме того, значение colSpace уменьшается с 1 до 0.
  • В пятый раз в цикле проверяется, является ли colSpace больше или равным 1 или colSpace ›=1, что преобразуется в равно 0 больше или равно 1?
  • Поскольку это не так, мы вырвемся из цикла.

Затем мы нажимаем цикл for, который создает звезды. Чтобы звезды печатали только нечетные числа (например, 1, 3, 5 и т. д.), нам нужно использовать формулу, которую мы видели первой, которая берет строку, в которой мы находимся, и умножает ее. на2, а затем вычитает 1. Затем мы хотим увеличивать количество звездочек на1 каждый раз в цикле. Итак, «звездное создание» цикла for теперь выглядит так:

for (star = 1; star <= (row * 2) — 1; star++) {
      Console.Write(“*”);
}

Точнее, вот что происходит каждый раз в этом цикле:

  • В первый раз звездочка инициализируется равной 1.
  • Затем проверяется, меньше ли звездочка, чем (row * 2) - 1, что означает (1 * 2) - 1, что преобразуется в (2) - 1, что равно 1. Другими словами, 1 меньше или равно 1?
  • Поскольку это так, после 4 пробелов, сгенерированных предыдущим циклом, на экран выводится звездочка.
  • Звездочка, которая в настоящее время равна 1, увеличивается на 1 и теперь равна 2.
  • Во второй раз звездочка теперь равна 2, поэтому выполняется проверка, меньше ли звездочка (строка * 2) - 1, что переводится как (2 * 2) - 1, что переводится как (4) - 1, что равно 3. Другими словами, 3 меньше или равно 2?
  • Поскольку это не так, мы вырываемся из цикла, поэтому печать звездочек больше нет.
  • Затем мы возвращаемся к началу первого цикла в методе, непосредственно перед которым значение row увеличивается с 1 до 2.
  • Затем мы возвращаемся к циклу colSpace, где переменная colSpace инициализируется как numOfRows - row, что переводит в colSpace = 5 - 2 или colSpace = 3
  • Затем проверяется, является ли наше значение colSpace больше или равным 1. Другими словами, 3 больше или равно 1?
  • Поскольку это так, будет напечатан пробел, а курсор останется на той же строке. Затем colSpace будет уменьшен с 3 до 2.
  • Во второй раз в этом цикле проверяется, является ли colSpace больше или равным 1. Другими словами, 2 больше или равно 1?
  • Поскольку это так, пробел теперь печатается на экране, а курсор остается в той же строке. Теперь рядом друг с другом 2 пробела. Затем colSpace уменьшается с 2 до 1.
  • В третий раз в этом цикле проверяется, является ли colSpace больше или равным 1. Другими словами, 1 больше или равно 1?
  • Поскольку это так, на экран выводится пробел, а курсор остается в той же строке. Теперь рядом друг с другом 3 пробела. Затем colSpace уменьшается с 1 до 0.
  • В четвертый раз в этом цикле выполняется проверка, является ли colSpace больше или равным 1. Другими словами, 0 больше или равно 1?
  • Так как это не так, мы выходим из цикла, таким образом печатая больше никаких пробелов.
  • Затем будет выполнен цикл star, в результате чего на экран будут выведены 3 звезды.
  • Значение row увеличивается с 2 до 3, а затем выполняется цикл spaces, что приводит к 2 пробела выводятся на экран.
  • Затем выполняется цикл star, в результате чего на экран выводятся 5 звезд.
  • Значение row увеличивается с 3 до 4, а затем выполняется цикл spaces, в результате чего 1 пробел выводится на экран.
  • Затем выполняется цикл star, в результате чего на экран выводятся 7 звезд.
  • Значение row увеличивается с 4 до 5, и выполняется проверка, соответствует ли row число меньше или равно значению numOfRows. Другими словами, 5 меньше или равно 5?
  • Поскольку это так, выполняется цикл spaces. Однако в этот момент colSpace равно numOfRows - row, что переводится как colSpace = 5 - 5, что переводится как colSpace = 0.
  • Существует проверка, чтобы убедиться, что colSpace больше или равен 1, что означает является ли colSpace ›= 1 или является ли 0 ›= 1?
  • Поскольку это не так, мы выходим из цикла, и на экран не выводятся пробелы.
  • Затем выполняется цикл звездочка, в результате чего на экран выводятся 9 звездочек.
  • Значение row теперь увеличивается с 5 до 6, а также выполняется проверка, меньше ли номер строки или равно значению numOfRows. Другими словами, 6 меньше или равно 5?
  • Поскольку это не так, мы выходим из цикла, и программа завершается.

В одном из комментариев, сделанных в SoloApp, было очень конкретно сказано, что первая часть кода (colSpace = numOfRows - row) инициализирует значение colSpaceПРОСТО ОДИН РАЗ. Мне было очень важно помнить об этом. Кроме того, мне приходилось постоянно напоминать себе, что цикл звездочка НЕ находился внутри цикла пробелов. Это происходит после цикла spaces.

Это было ОЧЕНЬ тяжело. Мне потребовался целый день, чтобы по-настоящему понять, что происходит, и, как я уже сказал, эти две формулы НЕ пришли бы мне в голову естественным образом. Тем не менее, я понимаю, что происходило во время выполнения программы, так что это хорошо. Кроме того, я сейчас истощен.

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

Вот ссылка на предыдущую статью Изучение кода — часть 5c: перегрузка методов и рекурсия.