Содержание
Задача: с клавиатуры ввести двумерный массив размером n
на n
элементов. Распечатать массив. Вывести на печать только оси массива так, чтобы получился прямой крест и косой крест на экране. Вывести максимум каждой строки массива.
Анализ задачи
Вначале попробуем провести анализ всех вводных задачи и попытаемся определить наиболее «скользкие» места. Итак, первое условие задачи:
с клавиатуры ввести двумерный массив размеромn
наn
элементов
Говоря на языке линейной алгебры, нас просят ввести с клавиатуры квадратную матрицу размером NxN элементов. При этом, задача не ограничивает нас величиной n
, то есть мы можем с одинаковым успехом создать как матрицу 2х2 элемента, так и 1000х1000. Но, если посмотреть на третье условие задачи:
Вывести на печать только оси массива так, чтобы получился прямой крест и косой крест на экране
то становится, как минимум, понятно, что у матрицы 2х2 мы красивого креста ни прямого, ни косого не получим — мы будем постоянно «рисовать» на экране саму матрицу. Отсюда мы получаем первое условие, которое мы должны предусмотреть в нашем приложении — размер массива должен быть не менее, чем 3х3. При меньших размерах — 1х1 и 2х2 мы будем просто выводить всегда весь массив на экран.
Теперь разберемся с крестами, которые нам необходимо нарисовать в консоли. По сути, для рисования косого креста нам необходимо определить элементы массива, лежащие на диагоналях матрицы. Чтобы было понятно, о чем идет речь, попробуем изобразить косой крест, используя матрицы различных размеров.

Желтым цветом залиты ячейки с числами, которые должны образовать в консоли косой крест.



Можно продолжать так рисовать матрицы до бесконечности, однако и по этим четырем вариантам прослеживается то, что для массивов с нечетным количеством элементов по строкам и столбцам крест получается красивее, а, в случае, если количество элементов четное, то в середине креста образуется квадрат из четырех элементов. Это мелочь, но, тем не менее. Немного хуже будет обстоять дело с прямым крестом для массивов с чётным количеством элементов. По сути, нас просят определить в массиве центральную строку и столбец и вывести их на экран. Возьмем всё тот же массив 6х6 и попытаемся изобразить прямой крест и здесь мы столкнемся с несколькими возможными вариантами, например, мы можем изобразить вот такой крест:
а можем — вот такой
Об варианта имеют право на существование и, более того, мы могли бы взять, например, за вертикальную линию третий столбец, а за горизонтальную — четвертую строку. В случае же, если количество элементов массива нечетное. таких дилемм не возникает — прямой крест однозначно определяется и выглядит ровно:
Опять же, чисто технически, задача решается с матрицами любой размерности, но на будущее, когда будем заниматься разными улучшениями нашей программы, учтем момент с четным и нечетным количеством элементов массива.
Отдельный момент касается предельной размерности массива и значений чисел, которые мы будем вводить. В условиях задачи про это ничего не говориться, но, думаю, что, если при решении этой лабораторной работы вы решите задать размерность массива 1000х1000 и проверить работу программы, то вряд ли вы дойдете до этапа «рисования» крестов. Поэтому сразу договоримся, что предельный размер массива мы ограничим десятью элементами по горизонтали и вертикали. То есть максимум, что попросит от нас программа — ввести 100 чисел. Что касается типа элементов и их максимальных значений. Здесь мы будем использовать только целые числа (int
), а максимальное значение, которое сможет ввести пользователь ограничим значением от 0 до 99, чтобы при «рисовании» крестов в консоли они выглядели более-менее презентабельно.
Итак, подведем промежуточный итог к чему мы пришли:
- Ограничение №1: пользователь должен задать размерность массива не менее, чем 3х3
- Ограничение №2: пользователь должен задать размерность массива не более, чем 10х10
- Ограничение №3: пользователь должен задавать числа от 0 до 99.
Теперь приступим непосредственно к программированию.
Решение лабораторной работы
Создадим новое консольное приложение в Visual Studio. «Скелет» приложения сразу после создания проекта должен быть таким:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Hello, World!"); } } }
Условно, решение лабораторной работы можно разделить на следующие части
- Пользователь должен указать количество элементов в строках и столбцах массива, а мы должны создать массив необходимой размерности
- Пользователь должен последовательно ввести значения элементов массива
- Приложение должно вывести исходный массив в консоль
- Приложение должно вывести в консоль прямой крест
- Приложение должно вывести в консоль косой крест
- Приложение должно вывести в консоль максимальные значения из каждой строки массива
По сути, все эти пункты можно реализовать непосредственно в методе Main()
нашего приложения, но тогда мы получим такой код, а можем реализовать каждую часть как отдельный метод, что будет более правильно.
Создание двумерного массива
По условиям задачи пользователь должен указать количество элементов в строках и столбцах массива не менее трех. При этом, чтобы приложение работало стабильно, так как мы не можем ограничить пользователя вводить в консоли только числа, то стоит учесть обработку ошибок ввода пользователя. Например, чтобы программа могла сообщить пользователю, что он ввел не число или, что заданное число неверное. Напишем для этого отдельный метод:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { } static int GetCount() { bool isCorrect = false; int count = 0; while (isCorrect == false) { Console.Write("n = "); isCorrect = int.TryParse(Console.ReadLine(), out count); if (isCorrect == false) Console.WriteLine("Вводите только целые числа"); else { if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; } } } return count; } } }
Метод GetCount()
действует следующим образом: запускается цикл while
, который работает до тех пор, пока переменная isCorrect
не примет значение true
. Посмотрим на тело цикла:
Console.Write("n = "); isCorrect = int.TryParse(Console.ReadLine(), out count); if (isCorrect == false) Console.WriteLine("Вводите только целые числа"); else { if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; } }
Первая строка — приглашение пользователю ввести что-либо в консоль (мы, конечно, ожидаем ввод целого числа, но пользователь может ввести всё, что угодно). Далее мы пытаемся преобразовать то, что ввел пользователь в целое число:
isCorrect = int.TryParse(Console.ReadLine(), out count);
здесь мы считываем ввод из консоли и, используя метод TryParse()
пробуем получить значение, которое должно быть записано в переменную count
. Метод TryParse()
возвращает нам либо true
, если преобразование прошло успешно, либо false
, если пользователь ввел не целое число. И здесь мы сталкиваемся с первым ограничением, которое мы определили для нашего приложения. Если пользователь ввел НЕ целое число, то приложение просто выводит в консоль сообщение:
Console.WriteLine("Вводите только целые числа");
при этом, переменная isCorrect
будет содержать значение false
и цикл начнется заново.
Если же пользователь введет целое число и преобразование пройдет успешно, то мы должны проверить значение этого числа и, если оно меньше трех, то попросить пользователя ввести число ещё раз. Именно это мы и делаем вот в этой части тела цикла:
if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; }
Чтобы цикл продолжился мы обязательно присваиваем переменной isCorrect
значение false
так как на предыдущем шаге (при вызове метода TryParse()
) ей было присвоено значение true
. Если же пользователь ввел корректное значение, то мы выходим из цикла и возвращаем количество элементов в строках и столбцах цикла:
return count;
Теперь воспользуемся этим методом в нашем приложении в метод Main()
static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; }
здесь мы получаем с помощью метода GetCount()
количество элементов:
int count = GetCount();
и создаем двумерный массив:
int[,] matrix = new int[count, count];
На этом шаге весь код вашего приложения должен выглядеть следующим образом:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; } static int GetCount() { bool isCorrect = false; int count = 0; while (isCorrect == false) { Console.Write("n = "); isCorrect = int.TryParse(Console.ReadLine(), out count); if (isCorrect == false) Console.WriteLine("Вводите только целые числа"); else { if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; } } } return count; } } }
Итак, массив готов. Теперь его необходимо заполнить значениями, который нам предоставит пользователь.
Заполнение двумерного массива на основании ввода пользователя
Заполнить двумерный массив можно самыми разными способами. Например, мы можем попросить пользователя последовательно вводить по одному числу в консоль и передавать это число в определенный элемент массива, а можем пойти другим путем — попросить пользователя вводить числа построчно, заранее определившись с разделителем, который будет использоваться в строке, чтобы отделить одно число от другого. Именно этот вариант мы и реализуем в своем приложении. Опять же, нам необходимо предусмотреть ошибки ввода. Чтобы не уходить далеко в дебри обработки ошибок ввода, сделаем работу приложения следующим образом:
- пользователь вводит строку, которая должна содержать определенное количество целых чисел от 0 до 99 (см. наши ограничения)
- приложение разбивает эту строку на массив элементов по заданному нами разделителю, например, пусть разделителем будет пробел
- приложение пытается преобразовать каждый элемент из полученного массива строк в целое число и проверить это число на вхождение в заданный диапазон (0-99)
- если хотя бы один элемент был задан неверно, например, пользователь ввел не целое число, а дробное или число оказалось больше 99 и т.д., то программа должна попросить пользователя повторно ввести всю строку значений.
Напишем отдельный метод, который будет заполнять конкретную строку массива. Вот как может выглядеть этот метод:
static void FillMatrixRow(int[,] matrix, int rowNumber, int count) { bool isCorrect = false; while (isCorrect == false) { Console.WriteLine($"Введите {count} чисел от 0 до 99 для {rowNumber+1} строки массива. Числа вводятся через пробел"); string? temp = Console.ReadLine(); if (temp == null ) continue; string[] values = temp.Split(' '); if (values.Length != count) { Console.WriteLine($"Количество введенных значений {values.Length} вместо {count}. Повторите ввод сначала"); continue; } for (int i = 0; i < values.Length; i++) { bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99)); if (canWrite) { matrix[rowNumber, i] = number; } else { Console.WriteLine($"Строка {temp} содержит ошибки (введены числа не входящие в диапазон 0-99 или введены не только целые числа). Повторите ввод сначала"); isCorrect = false; break; } isCorrect = true; } } }
Параметрами этого метода выступают:
int[,] matrix
— непосредственно, сам массив, который мы должны заполнитьint rowNumber
— номер строки в массиве, которая заполняетсяint count
— количество элементов, которые должны быть введены пользователем (этот параметр мы пока используем для наглядности, а впоследствии при улучшении приложения можно его убрать и использовать вместо этого значения один из методов массива)
Этот метод нам ничего не возвращает (только заполняет массив), поэтому тип возвращаемого значения указан как void
. Этот метод выглядит по-сложнее, чем предыдущий, но, на самом деле, не на много. Здесь используются уже два цикла — while
, как в предыдущем методе и вложенный в него цикл for
. То есть, если убрать часть кода, то получим вот такую конструкцию из циклов:
while (isCorrect == false) { //здесь мы что-то делаем в первом цикле for (int i = 0; i < values.Length; i++) { //здесь мы что-то делаем во втором цикле } }
Внешний цикл while
используется так же, как и в случае с чтением числа — он сообщает пользователю, что тот должен ввести и «гоняет» пользователя по кругу до тех пор, пока тот не введет корректные значения в строку. Рассмотрим тело этого цикла вплоть до входа в цикл for
.
Вначале мы приглашаем пользователя ввести значения элементов строки массива:
Console.WriteLine($"Введите {count} чисел от 0 до 99 для {rowNumber+1} строки массива. Числа вводятся через пробел");
здесь мы, используя параметры метода, сообщаем пользователю что и как он должен вводить. То есть, если пользователь определил, что размерность массива 5х5 (count=5
) и нам необходимо заполнить первую строку (rowNumber=0
), то в консоли пользователь увидит:
Далее мы считываем строку, которую ввел пользователь
string? temp = Console.ReadLine(); if (temp == null ) continue;
Так как метод ReadLine()
может в некоторых случаях возвращать значение null
, то тип нашей переменной temp
определен также, как допускающий значение null
string? temp
и, чтобы Visual Studio не выдавала нам предупреждение о том, что переменная может содержать null
в том время как мы путаемся с ней работать, мы проводим проверку:
if (temp == null ) continue;
Чисто технически, мы могли бы обойтись и без этой проверки, в тип переменной указать просто как string
и всё бы прекрасно работало. Но, лучше избегать случаев, когда Visual Studio выдает всякого рода предупреждения — раз в 100 лет и палка стреляет и лучше сделать лишнюю проверку на null
, чем в готовом приложении получить необработанное исключение в самый неожиданный момент.
Далее мы производим первую проверку — убеждаемся что количество элементов в строке не больше и не меньше требуемого:
string[] values = temp.Split(' '); if (values.Length != count) { Console.WriteLine($"Количество введенных значений {values.Length} вместо {count}. Повторите ввод сначала"); continue; }
для этого мы, используя метод Split()
разбиваем исходную строку на массив строк по заданному разделителю (у нас это пробел). Если полученное количество элементов в массиве values
не соответствует тому, которое необходимо было ввести пользователю, то нет смысла идти далее по циклу — пользователь уже допустил ошибку. Поэтому мы выдаем ему сообщение об ошибке и вызываем continue;
, то есть прерываем выполнение этой итерации цикла и начинаем проход тела цикла сначала.
Если же пользователь ввел необходимое количество элементов, томы переходим далее и попадаем во внутренний цикл for
.
for (int i = 0; i < values.Length; i++) { bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99)); if (canWrite) { matrix[rowNumber, i] = number; } else { Console.WriteLine($"Строка {temp} содержит ошибки (введены числа не входящие в диапазон 0-99 или введены не только целые числа). Повторите ввод сначала"); isCorrect = false; break; } isCorrect = true; }
Назначение этого цикла — перебрать каждый элемент строки пользователя (элементы массива values
) и либо записать полученное число в массив, либо выдать пользователю сообщение об ошибке. Опять же, пройдемся по телу цикла. Здесь в первой строке и проверяется очередной элемент на допустимость значений:
bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99));
переменная canWrite
сообщает нам о том можно ли записать значение в массив. Эта переменная получит значение true
только при выполнении следующих условий:
- элемент
values[i]
преобразуется в целое числоnumber
. - И переменная
number
содержит значение от 0 до 99 (((number >= 0) && (number <= 99))
)
для того, чтобы понять в какое место массива мы должны записать полученное число, мы используем параметр метода rowNumber
и порядковый анализируемого элемента строки i
matrix[rowNumber, i] = number;
При этом мы сразу присваиваем переменной isCorrect
значение true, то есть будут выполняться следующие строки тела цикла:
bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99)); if (canWrite) { matrix[rowNumber, i] = number; } isCorrect = true;
Если очередной элемент оказался неверным, то мы должны прервать дальнейший анализ строки и заставить пользователя снова ввести все значения. Это делается вот в этой части кода:
Console.WriteLine($"Строка {temp} содержит ошибки (введены числа не входящие в диапазон 0-99 или введены не только целые числа). Повторите ввод сначала"); isCorrect = false; break;
здесь мы, помимо того, что выводим текст ошибки пользователю, также обязательно присваиваем переменной isCorrect
значение false
. Делается это по следующей причине. Пользователь может ввести первое значение в строке правильное — переменная isCorrect
получит значение true
, а второе значение будет не верным. В этом случае, если не присвоить переменной значение false
, то мы выйдем из цикла for
(вызовется break
), попадем во внешний цикла while
, где переменная isCorrect
будет иметь значение true
и тело внешнего цикла не будет запущено, то есть программа «посчитает», что можно переходить к следующей строке. Мы же здесь заставляем приложение полностью прервать цикл for
и вернуть на выполнение тела цикла while
— заставить пользователя ввести новую строку элементов массива. Таким образом, используя метод FillMatrixRow()
мы заполняем очередную строку исходного двумерного массива. Но так как массив у нас содержит count строк, то этот метод также необходимо вызывать count раз. Сделать это можно в методе Main()
следующим образом:
static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; for (int i = 0; i < count; i++) //заполняем count строк массива { FillMatrixRow(matrix, i, count); //заполняем очередную строку массива } }
На этом шаге весь код приложения должен выглядеть следующим образом:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; for (int i = 0; i < count; i++) { FillMatrixRow(matrix, i, count); } } static void FillMatrixRow(int[,] matrix, int rowNumber, int count) { bool isCorrect = false; while (isCorrect == false) { Console.WriteLine($"Введите {count} чисел от 0 до 99 для {rowNumber+1} строки массива. Числа вводятся через пробел"); string? temp = Console.ReadLine(); if (temp == null ) continue; string[] values = temp.Split(' '); if (values.Length != count) { Console.WriteLine($"Количество введенных значений {values.Length} вместо {count}. Повторите вввод сначала"); continue; } for (int i = 0; i < values.Length; i++) { bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99)); if (canWrite) { matrix[rowNumber, i] = number; } else { Console.WriteLine($"Строка {temp} содержит ошибки (введены числа не входящие в диапазон 0-99 или введены не только целые числа). Повторите ввод сначала"); isCorrect = false; break; } isCorrect = true; } } } static int GetCount() { bool isCorrect = false; int count = 0; while (isCorrect == false) { Console.Write("n = "); isCorrect = int.TryParse(Console.ReadLine(), out count); if (isCorrect == false) Console.WriteLine("Вводите только целые числа"); else { if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; } } } return count; } } }
Переходим к следующей части — печати массива.
Печать исходного массива
В принципе, здесь всё просто и делалось уже в других лабораторных работах. Но нам необходимо сделать так, чтобы массив выглядел красиво, поэтому метод печати массива мы сделаем вот таким:
public static void PrintMatrix(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { Console.Write(string.Format("{0:d2}", matrix[a, b])+" "); } Console.WriteLine(); } }
На входе метод получает массив int[,] matrix
. Далее мы запускам два цикла for
— внешний цикл проходит по строкам массива, а внутренний — по столбцам. Таким образом, внутри второго цикла for мы получаем очередной элемент массива, который выводим в консоль используя форматирование строки:
Console.Write(string.Format("{0:d2}", matrix[a, b])+" ");
формат "{0:d2}"
говорит нам о том, что выводимое на экран число должно содержать две цифры. То есть вместо 1 будет выводиться 01, вместо 6 — 06 и так далее. Таким образом мы получим на экране красивый вывод массива. Например, вот такой:
Если не применять форматирование, то получим вот такой некрасивый вывод
Мы выводим для каждого числа по два символа только по тому, что мы ограничили пользователя числами от 0 до 99. По аналогии, если бы мы допустили ввод чисел до 1000 (четыре символа), то применили бы формат "{0:d4}"
и т.д. В этом методе мы разделяем элементы массива простым пробелом. Теперь нам остается применить этот метод в нашей программе. Дописываем метод Main()
static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; for (int i = 0; i < count; i++) { FillMatrixRow(matrix, i, count); } Console.WriteLine("Исходная матрица"); PrintMatrix(matrix); }
И снова представляем весь исходный код программы на данный момент:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; for (int i = 0; i < count; i++) { FillMatrixRow(matrix, i, count); } Console.WriteLine("Исходная матрица"); PrintMatrix(matrix); } public static void PrintMatrix(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { //Console.Write(string.Format("{0:d2}", matrix[a, b])+" "); Console.Write(matrix[a, b] + " "); } Console.WriteLine(); } } static void FillMatrixRow(int[,] matrix, int rowNumber, int count) { bool isCorrect = false; while (isCorrect == false) { Console.WriteLine($"Введите {count} чисел от 0 до 99 для {rowNumber+1} строки массива. Числа вводятся через пробел"); string? temp = Console.ReadLine(); if (temp == null ) continue; string[] values = temp.Split(' '); if (values.Length != count) { Console.WriteLine($"Количество введенных значений {values.Length} вместо {count}. Повторите вввод сначала"); continue; } for (int i = 0; i < values.Length; i++) { bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99)); if (canWrite) { matrix[rowNumber, i] = number; } else { Console.WriteLine($"Строка {temp} содержит ошибки (введены числа не входящие в диапазон 0-99 или введены не только целые числа). Повторите ввод сначала"); isCorrect = false; break; } isCorrect = true; } } } static int GetCount() { bool isCorrect = false; int count = 0; while (isCorrect == false) { Console.Write("n = "); isCorrect = int.TryParse(Console.ReadLine(), out count); if (isCorrect == false) Console.WriteLine("Вводите только целые числа"); else { if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; } } } return count; } } }
Теперь мы добрались до решения основных задач работы — вывода прямого и косого креста из чисел массива.
Вывод прямого креста чисел (поиск центральных осей массива)
Здесь нам необходимо определить центральную строку и центральный столбец массива (оси) и вывести их на экран. Как было показано в самом начале, при анализе задачи, при чётном значение n
симметричный крест не получится. За основу нового метода мы можем взять метод печати исходного массива, то есть будем так же проходить по строкам и столбцам массива. Ниже представлен код метода:
public static void PrintStraightCross(int[,] matrix) { double target = Math.Floor(matrix.GetLength(0)/2f); for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { if ((a==target)||(b==target)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " "); else Console.Write(" "); } Console.WriteLine(); } }
Рассмотрим работу этого метода. В самой первой строке мы определяем индекс осей массива. Так как мы 100% знаем, что массив двумерный и квадратный, то нет смысла отдельно искать центральную строку и центральный столбец. Расчёт центра делается довольно просто:
double target = Math.Floor(matrix.GetLength(0)/2f);
Метод Math.Floor(x)
— возвращает наибольшее целое число, которое меньше или равно указанному числу. Этот метод используется для округления значения, которое мы получаем выражения:
matrix.GetLength(0)/2f
GetLength()
— метод массива. Возвращает количество элементов массива в измерении c заданным индексом. В нашем случае, мы задали индекс измерения 0 — получаем количество элементов в строке. В итоге, в переменной target
будет содержаться индекс центральных осей массива. Например, если массив будет иметь размерность 5х5, то расчет target будет таким:
target = Math.Floor(5/2) = Math.Floor(2.5) = 2
Далее мы запускаем два вложенных цикла, чтобы перебрать все элементы массива. И здесь стоит обратить внимание на то, как выводится информация в консоль:
if ((a==target)||(b==target)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " "); else Console.Write(" ");
Если текущие индексы строки (a
) и столбца (b
) совпадают c target
, то мы выводим в консоль форматированное значение элемента массива:
if ((a==target)||(b==target)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " ");
здесь важно отметить, что максимально возможное количество символов, которое выводится в консоль за один раз — три символа. Два символа — форматированное значение числа и один символ — пробел.
Если же a
и b
не равны target
, то мы выводим в консоль три пробела. Снова применим этот метод в нашем приложении и здесь уже можно проверить работу программы. Итак, весь код приложения на данный момент должен быть таким:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; for (int i = 0; i < count; i++) { FillMatrixRow(matrix, i, count); } Console.WriteLine("Исходная матрица"); PrintMatrix(matrix); Console.WriteLine("Прямой крест"); PrintStraightCross(matrix); } public static void PrintStraightCross(int[,] matrix) { double target = Math.Floor(matrix.GetLength(0)/2f); for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { if ((a==target)||(b==target)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " "); else Console.Write(" "); } Console.WriteLine(); } } public static void PrintMatrix(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { Console.Write(string.Format("{0:d2}", matrix[a, b])+" "); } Console.WriteLine(); } } static void FillMatrixRow(int[,] matrix, int rowNumber, int count) { bool isCorrect = false; while (isCorrect == false) { Console.WriteLine($"Введите {count} чисел от 0 до 99 для {rowNumber+1} строки массива. Числа вводятся через пробел"); string? temp = Console.ReadLine(); if (temp == null ) continue; string[] values = temp.Split(' '); if (values.Length != count) { Console.WriteLine($"Количество введенных значений {values.Length} вместо {count}. Повторите вввод сначала"); continue; } for (int i = 0; i < values.Length; i++) { bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99)); if (canWrite) { matrix[rowNumber, i] = number; } else { Console.WriteLine($"Строка {temp} содержит ошибки (введены числа не входящие в диапазон 0-99 или введены не только целые числа). Повторите ввод сначала"); isCorrect = false; break; } isCorrect = true; } } } static int GetCount() { bool isCorrect = false; int count = 0; while (isCorrect == false) { Console.Write("n = "); isCorrect = int.TryParse(Console.ReadLine(), out count); if (isCorrect == false) Console.WriteLine("Вводите только целые числа"); else { if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; } } } return count; } } }
Запустим приложение и зададим матрицу размером 5х5. Вот какой результат мы должны получить в итоге:
С прямым крестом разобрались. Теперь нарисуем косой крест.
Вывод косого креста чисел (поиск основной и побочной диагонали матрицы)
Опять же, за основу возьмем метод печати массива — проход в циклах по строкам и столбцам массива. Вначале представим исходный код нового метода:
public static void PrintSkewCross(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { if ((b == matrix.GetLength(1) - a - 1)||(a==b)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " "); else Console.Write(" "); } Console.WriteLine(); } }
Что касается поиска диагоналей матрицы, то самое простое — это найти основную диагональ. У такой диагонали индекс строки и столбца совпадают. То есть, если в цикле выполняется условие (a==b)
, то мы точно находимся на основной диагонали. Что касается побочно диагонали (та, которая идет от нижнего левого угла в верхний правый), то здесь нам необходимо использовать следующее условие: (b == matrix.GetLength(1) - a - 1)
b
— это индекс столбцаmatrix.GetLength(1)
— количество элементов в столбцах
Например, вернемся к нашей матрице 5х5 и попробуем определить положение первого элемента на обратной диагонали. Так как мы будем двигаться в циклах по строкам и затем по столбцам, то программа будет действовать следующим образом:
- Значения переменных в цикле.
a = 0
;b = 0
; проверяем условие0==5-0-1
выражение равноfalse
— пропускаем элемент - Значения переменных в цикле.
a = 0
;b = 1
; проверяем условие1==5-0-1
выражение равноfalse
— пропускаем элемент - Значения переменных в цикле.
a = 0
;b = 2
; проверяем условие2==5-0-1
выражение равноfalse
— пропускаем элемент - Значения переменных в цикле.
a = 0
;b = 3
; проверяем условие3==5-0-1
выражение равноfalse
— пропускаем элемент - Значения переменных в цикле.
a = 0
;b = 4
; проверяем условие4==5-0-1
выражение равноtrue
— печатаем элемент
Визуально этот проход по строке можно представить вот так:
Таким образом, вот это условие в коде метода:
if ((b == matrix.GetLength(1) - a - 1)||(a==b))
Сразу проверяет лежит ли элемента на побочной или основной диагонали матрицы. В остальном, метода работает также как и предыдущим — либо выводим элемент на экран, либо выводим на экран три пробела.
Весь код приложения на данный момент:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; for (int i = 0; i < count; i++) { FillMatrixRow(matrix, i, count); } Console.WriteLine("Исходная матрица"); PrintMatrix(matrix); Console.WriteLine("Прямой крест"); PrintStraightCross(matrix); Console.WriteLine("Косой крест"); PrintSkewCross(matrix); } public static void PrintSkewCross(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { if ((b == matrix.GetLength(1) - a - 1)||(a==b)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " "); else Console.Write(" "); } Console.WriteLine(); } } public static void PrintStraightCross(int[,] matrix) { double target = Math.Floor(matrix.GetLength(0)/2f); for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { if ((a==target)||(b==target)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " "); else Console.Write(" "); } Console.WriteLine(); } } public static void PrintMatrix(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { Console.Write(string.Format("{0:d2}", matrix[a, b])+" "); } Console.WriteLine(); } } static void FillMatrixRow(int[,] matrix, int rowNumber, int count) { bool isCorrect = false; while (isCorrect == false) { Console.WriteLine($"Введите {count} чисел от 0 до 99 для {rowNumber+1} строки массива. Числа вводятся через пробел"); string? temp = Console.ReadLine(); if (temp == null ) continue; string[] values = temp.Split(' '); if (values.Length != count) { Console.WriteLine($"Количество введенных значений {values.Length} вместо {count}. Повторите вввод сначала"); continue; } for (int i = 0; i < values.Length; i++) { bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99)); if (canWrite) { matrix[rowNumber, i] = number; } else { Console.WriteLine($"Строка {temp} содержит ошибки (введены числа не входящие в диапазон 0-99 или введены не только целые числа). Повторите ввод сначала"); isCorrect = false; break; } isCorrect = true; } } } static int GetCount() { bool isCorrect = false; int count = 0; while (isCorrect == false) { Console.Write("n = "); isCorrect = int.TryParse(Console.ReadLine(), out count); if (isCorrect == false) Console.WriteLine("Вводите только целые числа"); else { if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; } } } return count; } } }
Проверим работу приложения
Итак, наше приложение делает уже практически всё, что требуется — создает массив, печатает исходный массив, а также выводит прямой и косой крест в консоль. Осталось дело за малым — определить максимумы в строках массива.
Поиска максимальных значений в строках двумерного массива
Здесь всё просто. Вот как будет выглядеть наш метод для поиска максимумов:
public static void PrintMaximum(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { int max = matrix[a, 0];//считаем, что максимум - это первый элемент строки for (int b = 0; b < matrix.GetLength(1); b++) { if (max< matrix[a, b]) max = matrix[a, b]; } Console.WriteLine($"Максимум в строке {a+1} равен {max}"); } }
Здесь мы сразу выводим максимальное значение на экран. Остается использовать этот метод в приложении и проверить его работу.
Весь исходный код приложения
Ниже представлен весь исходный код приложения
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Введите количество элементов в строках и столбцах массива (не менее 3)"); int count = GetCount(); int[,] matrix = new int[count, count]; for (int i = 0; i < count; i++) { FillMatrixRow(matrix, i, count); } Console.WriteLine("Исходная матрица"); PrintMatrix(matrix); Console.WriteLine("Прямой крест"); PrintStraightCross(matrix); Console.WriteLine("Косой крест"); PrintSkewCross(matrix); Console.WriteLine("Максимумы в строках матрицы"); PrintMaximum(matrix); } public static void PrintMaximum(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { int max = matrix[a, 0];//считаем, что максимум - это первый элемент строки for (int b = 0; b < matrix.GetLength(1); b++) { if (max< matrix[a, b]) max = matrix[a, b]; } Console.WriteLine($"Максимум в строке {a+1} равен {max}"); } } public static void PrintSkewCross(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { if ((b == matrix.GetLength(1) - a - 1)||(a==b)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " "); else Console.Write(" "); } Console.WriteLine(); } } public static void PrintStraightCross(int[,] matrix) { double target = Math.Floor(matrix.GetLength(0)/2f); for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { if ((a==target)||(b==target)) Console.Write(string.Format("{0:d2}", matrix[a, b]) + " "); else Console.Write(" "); } Console.WriteLine(); } } public static void PrintMatrix(int[,] matrix) { for (int a = 0; a < matrix.GetLength(0); a++) { for (int b = 0; b < matrix.GetLength(1); b++) { Console.Write(string.Format("{0:d2}", matrix[a, b])+" "); } Console.WriteLine(); } } static void FillMatrixRow(int[,] matrix, int rowNumber, int count) { bool isCorrect = false; while (isCorrect == false) { Console.WriteLine($"Введите {count} чисел от 0 до 99 для {rowNumber+1} строки массива. Числа вводятся через пробел"); string? temp = Console.ReadLine(); if (temp == null ) continue; string[] values = temp.Split(' '); if (values.Length != count) { Console.WriteLine($"Количество введенных значений {values.Length} вместо {count}. Повторите вввод сначала"); continue; } for (int i = 0; i < values.Length; i++) { bool canWrite = int.TryParse(values[i], out int number) && ((number >= 0) && (number <= 99)); if (canWrite) { matrix[rowNumber, i] = number; } else { Console.WriteLine($"Строка {temp} содержит ошибки (введены числа не входящие в диапазон 0-99 или введены не только целые числа). Повторите ввод сначала"); isCorrect = false; break; } isCorrect = true; } } } static int GetCount() { bool isCorrect = false; int count = 0; while (isCorrect == false) { Console.Write("n = "); isCorrect = int.TryParse(Console.ReadLine(), out count); if (isCorrect == false) Console.WriteLine("Вводите только целые числа"); else { if (count < 3) { Console.WriteLine("Количество элементов должно быть не менее 3"); isCorrect = false; } } } return count; } } }
Запустим приложение и проверим его работу.
Как можно видеть по рисунку, приложение выполняет все задачи.
Итого
В этой лабораторной работе мы, по большому счёту, не использовали ничего сверх того, что можно отнести к основам программирования. Мы ограничились только двумя типами циклов — while
и for
, вспомнили про форматирование текста, а также лишний раз поучились использовать методы в приложениях C#. Каждый метод в нашем приложении выполняет строго одну возложенную на него задачу — заполнить строку массива, напечатать массив, определить максимум в массиве и так далее.