Лекция
15
22.0. Массивы в
Windows Forms Application
Массивы – это структура данных,
представляющая собой набор переменных
одинакового типа, имеющих общее имя.
Каждый
элемент массива однозначно определяется
именем и индексом (номером элемента в
массиве). Индексы массива принадлежат
целочисленному типу.
Все
элементы массива имеют одинаковый тип.
Используются
при работе с таблицами и списками.
Массив
может быть:
—
одномерным,
—
двумерным /многомерным.
Массивы
различают:
-
статические
и -
динамические.
В статическом массиве размеры
массива (верхний индекс элементов)
задаются при объявлении массива (размеры
известны до компиляции программы).
Формат
объявления одномерного массива в C#:
тип[
] ИмяМассива = new
тип [размер];
Формат
объявления двумерного массива в C#:
тип
[ , ] ИмяМассива = new
тип [количество строк, количество
столбцов];
Если массив объявлен с инициализацией
глобально в программе, то начальные
значения элементов массива будут
использоваться во всех процедурах и
обработчиках событий. Пример объявления
массива:
// using – раздел
объявления модулей;
using
System.Windows.Forms;
namespace
WindowsFormsApplication1 //пространство
имен приложения
{
public
partial class Form1 : Form // объявление
класса
{
public Form1()
// объявление формы1
{
InitializeComponent();
// объявление компонент на форме
}
// глобальное объявление массивов
int[] А = new int[5]; // одномерный массив
А из 5 целых чисел
double[,] M = new double[2, 3]; // двумерный массив
M[2х3]
string[ ] Team = {«Zenith»,
«Dynamo», «Sparta», «Rotor», «CSK»};
//строковый
double[] F = { 1.5, 2.1, 3.65, 4.7, 5.14, 6.36 }; // F[6]
из 6 вещественных чисел
int[,] D = { { 0, 2, 4, 6 }, { 2, 9, 6, 3 }, { 4, 7, 5, 8 }, { 1, 6,
5, 7 } }; // массив M [4х4]
}
}
// обработчики событий
Элементы
массива, объявленного глобально
можно инициализировать в процедуре
обработчика события, во время работы
программы, например, для массива A из 5
эл.:
private void
button1_Click(object sender, EventArgs e)
{
// инициализация элементов массива
A, объявленного глобально
A[1] = 5;
A[2] = 6; A[3] = 0; A[4] = -5; A[5]
= -10;
}
Локальный массив объявляется в
процедуре обработчика события, и тогда
его как правило инициализируют во время
исполнения этого события. Значения
элементов, как и сам массив известен
только в этой процедуре. При необходимости
работы с массивом его надо заново
объявлять в другом обработчике события
и производить его инициализацию.
Например:
private
void button2_Click(object sender, EventArgs e)
{
int[] B =
new int[10];
// массив B объявлен
локально
for (int k
= 0; k <= 4; k++)
// с инициализацией элементов
B[k] = k;
}
При обращении к элементам массива
заданного локально в другом обработчике
событий, будет выдано сообщение об
ошибке:
В динамическом массиве при объявлении
указывается имя массива, тип его
элементов, а размер массива определяется
при выполнении программы и задается
некой переменной. Значение переменной
можно ввести в процессе диалога программы
с пользователем или используя свойство
length, содержащее количество элементов,
которое может хранить массив. Например:
private void button1_Click(object sender, EventArgs e)
{
int size = int.Parse(textBox1.Text);
//Задание верхней
границы массива
int []
H = new int[size];
………
}
22.1 Операции с массивами в Windows-приложениях
Типовые операции:
-
вывод/ввод
массива; -
поиск
максимального или минимального элемента
массива; -
поиск
заданного элемента массива; -
сортировка
массива.
Ввод-Вывод
массивов в Windows-приложениях
Поскольку эти приложения позволяют
создать дружелюбный интерфейс
пользователя, то это облегчает работу
по вводу и выводу массивов.
Пример. Форма разделена условно на две
части – для ввода и вывода массива.
Пользователь в текстовое окно число
элементов массива и нажимает командную
кнопку «Создать массив», обработчик
которой создает массив заданной
размерности, если корректно задан
размер, в противном случае выдается
сообщение об ошибки.
Затем пользователь переходит к вводу
элементов массива. Элемент вводится в
текстовое окно, а командная кнопка
«Ввести элемент» обеспечивает передачу
значения в массив. Корректность ввода
контролируется и на этом этапе.
Для облегчения ввода пользователю
выводится подсказка, какой именно
элемент надо ввести. После ввода элементов
массива окно ввода становится недоступным
для ввода элементов.
В нижней части отображается введенный
массив в форме, удобной для восприятия
пользователя. Для этого пригодны
элементы: ListBox, CheckedListBox,
ComboBox. Как только вводится
очередной элемент, он немедленно
отображается во всех объектах.
ComboBox11
label1
label2
label3
label4
label5
label6
label7
listBox1-
список
checkedListBox1
comboBox1-
комбинированный список
textBox1
button1
textBox2
button2
panel1
panel2
Три объекта вывода элементов массива
приведены для демонстрации, реально их
всех отображать не нужно. Компонент
выбирается по желанию пользователя.
using System;
using
System.Collections.Generic;
using
System.ComponentModel;
using System.Data;
using System.Drawing;
using
System.Linq;
using System.Text;
using
System.Windows.Forms;
namespace
WindowsFormsApplication1
{
public partial
class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
double [] mas;
int i=0;
private void
button1_Click(object sender, EventArgs e)
{
try //охраняемый блок
{
int n = int.Parse(textBox1.Text);
mas =
new double[n];
label4.Text = «mas[ » + 0 + » ]»;
textBox2.ReadOnly = false;
listBox1.Items.Clear();
checkedListBox1.Items.Clear();
comboBox1.Items.Clear();
i = 0;
}
catch //перехватчик исключения и
формирование ошибки
{
MessageBox.Show(«Надо вводить цифры «,
«Ошибочный ввод данных»,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void
button2_Click(object sender, EventArgs e)
{
int n =
int.Parse(textBox1.Text);
mas = new
double[n];
// задание размера массива
mas[i] = double.Parse(textBox2.Text);
label4.Text = «mas[ » + i + » ]»;
listBox1.Items.Add(mas[i]);
checkedListBox1.Items.Add(mas[i]);
comboBox1.Items.Add(mas[i]);
i++;
textBox2.Text = » «;
label6.Text = «ОК»;
if (i == n)
{
label3.Text = » «;
label4.Text = » «;
label6.Text = «Ввод
не доступен
«;
textBox2.Text = » «;
textBox2.ReadOnly = true;
}
}
}
}
Последовательность чисел удобно вводить
в строку таблицы с помощью компонента
DataGridView (данные строкового
вида).
DataGridView – это таблица,
ячейки которой содержат строки символов.
Столбец
Таблица
Строка
Ячейка
Свойства
DataGridView определяют:
Columns
колонки таблицы
Rows
строки таблицы
Cells ячейки
ColumnCount количество
столбцов таблицы
RowCount количество
строк таблицы
Rows[n].Cells[k]
ячейка, лежащая на пересечении n
— го ряда row и k-ой
столбца
Задача1, 2. Ввести
элементы одномерного
массива и вычислить:
Задача1: суммарное, среднеарифметическое,
Задача2: максимальное и минимальное
значения элементов этого массива.
using System;
using
System.Collections.Generic;
using
System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using
System.Windows.Forms;
namespace
WindowsFormsApplication1
{
public partial
class Form1 : Form
{
public Form1()
{
InitializeComponent();
// объявление компонентов на
Form1
}
double[] K =
new double[5]; // объявление
массива
private void
button1_Click(object sender, EventArgs e) // Задача1
{
double avr = 0;
//среднее значение
double summ = 0; //сумма элементов
int n
= 0;
// количество введенных
элементов
try //охраняемый блок
{
for
(int
i
= 0; i
< 5; i++)
//преобразование данных, вводимых в
1 строку
{
// с клавиатуры в цифровой
эквивалент
K[i]
= System.Convert.ToDouble(dataGridView1.Rows[0].Cells[i].Value);
summ
= summ + K[i];
n= n
+ 1;
}
avr =
summ / n;
label1.Text
= «Сумма
элементов:
» + String.Format(«{0,6:f}», summ);
label2.Text
= «Среднее
арифмет.
значение:
» + String.Format(«{0,6:f3}», avr);
}
catch //перехватчик исключения и
формирование ошибки
{
MessageBox.Show(«Надо вводить цифры «,
«Ошибочный ввод данных»,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void
button2_Click(object sender, EventArgs e) // Задача2
{
double Kmax
= 0;
double Kmin
= 0;
int Nmx =
0;
int Nmn =
0;
try
//охраняемый
блок
{
for
(int
i
= 0; i
< 5; i++)
//преобразование данных, вводимых в
первую строку
{
//с клавиатуры в цифровой эквивалент
K[i]
= System.Convert.ToDouble(dataGridView1.Rows[0].Cells[i].Value);
}
Kmax =
K[0]; // предположение
Nmx =
0;
for
(int i = 1;
i < 5; i++)
{
if (K[i] > Kmax)
{
Kmax
= K[i]; // выявление
max
Nmx = i;
}
}
Kmin =
K[0]; // предположение
Nmn =
0;
for
(int i =1;
i < 5; i++)
{
if
(K[i] < Kmin)
{
Kmin
= K[i]; // выявление
min
Nmn = i;
}
}
label3.Text
= «Максимальное
значение:
» + String.Format(«{0,6:f1}», Kmax) + «, его
номер:
» + Nmx.ToString();
label4.Text
= «Минимальное
значение:
» + String.Format(«{0,6:f1}», Kmin) + «, его
номер:
» + Nmn.ToString();
}
catch //перехватчик исключения и
формирование ошибки
{
MessageBox.Show(«Надо вводить цифры «,
«Ошибочный ввод данных»,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
0
1 2 3 4
Двумерную
таблицу можно представить как совокупность
одномерных массивов.
Задача
3. Обработать результаты спортивных
соревнований олимпиады.
Программа
должна вычислять общее количество
медалей каждой страны и соответствующее
количество баллов, по правилу:
— за
золотую медаль – 7 баллов,
— за
серебряную медаль – 6 баллов,
— за
бронзовую медаль – 5 баллов,
Устанавливаем на
форму объекты dataGridView1
и button1. Используя свойство
Colomns, создаем коллекцию
столбцов с полями: Страна, Золотых,
Серебряных, Бронзовых, Всего, Баллов
dataGridView
Изменив свойство Name,
переименуем dataGridView в
Tabl.
Количество строк в компоненте
по умолчанию dataGridView
= 1 и для увеличения их численности
необходимо при инициализации элементов
добавить нужное их число через метод
dataGridView.Rows.Add();
public
Form1()
{
InitializeComponent();
Tabl.Rows.Add(8);
//добавление
строк
в
таблицу
}
Заполнение ячеек организовано через
процедуру обработки события Activate,
которое происходит при активизации
формы.
Запуск приложения
При нажатии на кнопку «Итоги» происходит
расчет показателей:
using System;
using
System.Windows.Forms;
namespace
WindowsFormsApplication1
{
public partial
class Form1 : Form
{
public Form1()
{
InitializeComponent();
Tabl.Rows.Add(8);
//добавление
строк
в
таблицу
}
private void
Form1_Activated(object sender, EventArgs e) //при
активизации
формы
{
string[]
Ctrana
= new
string[8]
{ «Австрия», «Великобритания»,
«Германия», «Италия»,
«Россия», «США»,
«Франция», «Япония» };
int[]
Zoloto
= new
int[8]
{ 16, 11, 14, 13, 32, 39, 13, 5 };
int[]
Serebro = new int[8] { 25, 10, 17, 8, 28, 25, 14, 8 };
int[]
Bronza = new int[8] { 17, 7, 28, 13, 28, 33, 11, 5 };
for (int i
= 0; i < 8; i++)
{
Tabl.Rows[i].Cells[0].Value
= Ctrana[i]; // заполнение
элементами
0 столбца
Tabl.Rows[i].Cells[1].Value
= Zoloto[i]; // заполнение
элементами
1 столбца
Tabl.Rows[i].Cells[2].Value
= Serebro[i]; // заполнение
элементами
2 столбца
Tabl.Rows[i].Cells[3].Value
= Bronza[i]; // заполнение
элементами
3 столбца
}
}
private void
button1_Click(object sender, EventArgs e) //кнопка
Итоги
{
int c,r; //номер
колонки и строки Tabl
int s=0; //всего медалей у команды
int b=0; //всего баллов у команды
for (r = 0; r < 8; r++)
//цикл по строкам
{
//вычисление
общего количества медалей
for (c
= 1; c <= 3; c++)
s =
s + System.Convert.ToInt16(Tabl.Rows[r].Cells[c].Value);
//вычисление
общего
количества
баллов
b = 7 *
System.Convert.ToInt16(Tabl.Rows[r].Cells[1].Value) +
6
* System.Convert.ToInt16(Tabl.Rows[r].Cells[2].Value) +
5
* System.Convert.ToInt16(Tabl.Rows[r].Cells[3].Value);
Tabl.Rows[r].Cells[4].Value
= s.ToString(); // всего
медалей
для
каждой
страны
Tabl.Rows[r].Cells[5].Value
= b.ToString(); // всего
баллов
для
каждой
страны
}
}
}
}
Соседние файлы в папке ЛК
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
Потому что код срабатывает при условии, что
Тоесть, вы проверяете существует ли CheckBox1 или нет.
У чекбокса есть свойство Checked, которое возвращает true или false, в зависимости от того, поставили галку или нет. Используй это свойство.
А чтобы найти минимальное положительное значение в массиве, нужно организовать цикл так:
Если элемент отрицательный, переходим к следующему элементу
Нужно до цикла объявить временную переменную и присвоить ей значение максимального элемента массива. Проверить, не является ли максимальный элемент отрицательным (В таком случае в массиве нет положительных чисел)А в цикле сравнивать ее с каждым положительным элементом. Если элемент меньше, перезаписать значение временной переменной.
Добавлено через 22 минуты
В итоге должно получится так:
C# | ||
|
Добавлено через 18 минут
Вот рабочий вариант:
Кликните здесь для просмотра всего текста
C# | ||
|
Продолжим распутывать хитрости C++ и Windows Forms? Попробуйте создать массив типа, например, double в visual studio внутри класса Form самым обычным для языков программирования образом:
static double arr[20];
Вас ждет интересная неожиданность, точнее, ошибка компиляции:
error C4368: не удается определить «arr» как член управляемого «project:: Form1»: смешанные типы не поддерживаются
Что же делать? Неужели создавать отдельные переменные? Нет, конечно. Можно вынести создание массива за пределы класса Windows Forms – и все будет в порядке. Но, некоторым преподавателям очень не нравятся глобальные переменные, так что попробуем найти другой способ. Вот он:
static array<double> ^arr = gcnew array<double>(20);
Что мы делаем? По сути мы создаем (и сразу инициализируем) тот же массив того же формата double, но с помощью базового класса Array для всех массивов в среде CLR, в котором есть методы для создания, изменения, поиска и сортировки массивов.
Автор этого материала — я — Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML — то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.
заметки, Visual Studio, си плюс плюс, массивы, Windows Forms
Массивы массивов
Еще одним видом массивов C# являются массивы массивов, называемые также изрезанными массивами (jagged arrays). Такой массив массивов можно рассматривать как одномерный массив, его элементы являются массивами, элементы которых, в свою очередь снова могут быть массивами, и так может продолжаться до некоторого уровня вложенности.
В каких ситуациях может возникать необходимость в таких структурах данных? Эти массивы могут применяться для представления деревьев, у которых узлы могут иметь произвольное число потомков. Таковым может быть, например, генеалогическое дерево. Вершины первого уровня — Fathers, представляющие отцов, могут задаваться одномерным массивом, так что Fathers[i] — это i-й отец. Вершины второго уровня представляются массивом массивов — Children, так что Children[i] — это массив детей i-го отца, а Children[i][j] — это j-й ребенок i-го отца. Для представления внуков понадобится третий уровень, так что GrandChildren [i][j][k] будет представлять к-го внука j-го ребенка i-го отца.
Есть некоторые особенности в объявлении и инициализации таких массивов. Если при объявлении типа многомерных массивов для указания размерности использовались запятые, то для изрезанных массивов применяется более ясная символика — совокупности пар квадратных скобок; например, int[][] задает массив, элементы которого — одномерные массивы элементов типа int.
Сложнее с созданием самих массивов и их инициализацией. Здесь нельзя вызвать конструктор new int[3][5], поскольку он не задает изрезанный массив. Фактически нужно вызывать конструктор для каждого массива на самом нижнем уровне. В этом и состоит сложность объявления таких массивов. Начну с формального примера:
//массив массивов - формальный пример //объявление и инициализация int[][] jagger = new int[3][] { new int[] {5,7,9,11}, new int[] {2,8}, new int[] {6,12,4} };
Массив jagger имеет всего два уровня. Можно считать, что у него три элемента, каждый из которых является массивом. Для каждого такого массива необходимо вызвать конструктор new, чтобы создать внутренний массив. В данном примере элементы внутренних массивов получают значение, будучи явно инициализированы константными массивами. Конечно, допустимо и такое объявление:
int[][] jagger1 = new int[3][] { new int[4], new int[2], new int[3] };
В этом случае элементы массива получат при инициализации нулевые значения. Реальную инициализацию нужно будет выполнять программным путем. Стоит заметить, что в конструкторе верхнего уровня константу 3 можно опустить и писать просто new int[][]. Самое забавное, что вызов этого конструктора можно вообще опустить, он будет подразумеваться:
int[][] jagger2 = { new int[4], new int[2], new int[3] };
Но вот конструкторы нижнего уровня необходимы. Еще одно важное замечание — динамические массивы возможны и здесь. В общем случае, границы на любом уровне могут быть выражениями, зависящими от переменных. Более того, допустимо, чтобы массивы на нижнем уровне были многомерными. Но это уже «от лукавого», вряд ли стоит пользоваться такими сложными структурами данных, ведь с ними предстоит еще и работать.
Приведу теперь чуть более реальный пример, описывающий простое генеалогическое дерево, которое условно назову «отцы и дети»:
/// <summary> /// массив массивов -"Отцы и дети" /// </summary> public void GenTree() { int Fcount = 3; string[] Fathers = new string[Fcount]; Fathers[0] = "Николай"; Fathers[1] = "Сергей"; Fathers[2] = "Петр"; string[][] Children = new string[Fcount][]; Children[0] = new string[] {"Ольга", "Федор"}; Children[1] = new string[] {"Сергей", "Валентина", "Ира", "Дмитрий"}; Children[2] = new string[] {"Мария", "Ирина", "Надежда"}; Arrs.PrintAr3(Fathers, Children); }
Здесь отцов описывает обычный динамический одномерный массив Fathers. Для описания детей этих отцов необходим уже массив массивов, который также является динамическим на верхнем уровне, поскольку число его элементов совпадает с числом элементов массива Fathers. Здесь показан еще один способ создания таких массивов. Вначале конструируется массив верхнего уровня, содержащий ссылки со значением void. А затем на нижнем уровне конструктор создает настоящие массивы в динамической памяти, с которыми и связываются ссылки.
Я не буду демонстрировать работу с генеалогическим деревом, ограничусь лишь печатью этого массива. Здесь есть несколько поучительных моментов. В классе Arrs для печати массива создан специальный метод PrintAr3, которому в качестве аргументов передаются массивы Fathers и Children. Вот текст данной процедуры:
/// <summary> /// Печать дерева "Отцы и дети", /// заданного массивами Fathers и Children /// </summary> /// <param name="Fathers">массив отцов</param> /// <param name="Children"> массив массивов детей</param> public static void PrintAr3(string[] Fathers, string[][] Children) { for (int i = 0; i < Fathers.Length; i++) { Console.WriteLine("Отец : {0}; Его дети:", Fathers[i]); for (int j = 0; j < Children[i].Length; j++) Console.Write(Children[i][j] + " "); Console.WriteLine(); } }//PrintAr3
Приведу некоторые комментарии к этой процедуре.
- Внешний цикл по i организован по числу элементов массива Fathers. Заметьте, здесь используется свойство Length, в отличие от ранее применяемого метода GetLength.
- В этом цикле с тем же успехом можно было бы использовать и имя массива Children. Свойство Length для него возвращает число элементов верхнего уровня, совпадающее, как уже говорилось, с числом элементов массива Fathers.
- Во внутреннем цикле свойство Length вызывается для каждого элемента Children[i], который является массивом.
- Остальные детали, надеюсь, понятны.
Приведу вывод, полученный в результате работы процедуры PrintAr3.
Рис.
6.3.
Дерево «Отцы и дети»
Процедуры и массивы
В наших примерах массивы неоднократно передавались процедурам в качестве входных аргументов и возвращались в качестве результатов. Остается подчеркнуть только некоторые детали.
- В процедуру достаточно передавать только сам объект — массив. Все его характеристики (размерность, границы) можно определить, используя свойства и методы этого объекта.
- Когда массив является выходным аргументом процедуры, как аргумент C в процедуре MultMatr, выходной аргумент совсем не обязательно снабжать ключевым словом ref или out (хотя и допустимо). Передача аргумента по значению в таких ситуациях так же хороша, как и передача по ссылке. В результате вычислений меняется сам массив в динамической памяти, а ссылка на него остается постоянной. Процедура и ее вызов без ключевых слов выглядит проще, поэтому обычно они опускаются. Заметьте, в процедуре GetSizes, где определялись границы массива, ключевое слово out, сопровождающее аргументы, совершенно необходимо.
- Функция может возвращать массив в качестве результата.
Алгоритмы и задачи
Алгоритмы и задачи, рассматриваемые в этой главе, являются частью фундамента, на котором строится образование программиста. Нет ни одной проблемной области, в задачах которой не требовались бы массивы. Поэтому задачи, требующие использования массивов, появлялись уже в предыдущих главах, появятся они и в последующих. Но здесь мы будем заниматься ими целенаправленно.
Последовательность элементов — — одна из любимых структур в математике. Последовательность можно рассматривать как функцию , которая по заданному значению индекса элемента возвращает его значение. Эта функция задает отображение , где — это тип элементов последовательности. В программировании последовательности это одномерные массивы, но от этого они не перестают быть менее любимыми.
Определение. Массив — это упорядоченная последовательность элементов одного типа. Порядок элементов задается с помощью индексов.
В отличие от математики, где последовательность может быть бесконечной, массивы всегда имеют конечное число элементов. Для программистов важно то, как массивы хранятся в памяти. Массивы занимают непрерывную область памяти, поэтому, зная адрес начального элемента массива, зная, сколько байтов памяти требуется для хранения одного элемента, и зная индекс (индексы) некоторого элемента, нетрудно вычислить его адрес, а значит, и хранимое по этому адресу значение элемента. На этом основана адресная арифметика в языках C и C++, где адрес элемента a(i) задается адресным выражением a+i, в котором имя массива a воспринимается как адрес первого элемента. При вычислении адреса i-го элемента индекс i умножается на длину слова, требуемого для хранения элементов типа T. Адресная арифметика использует 0-базируемость элементов массива, полагая индекс первого элемента равным нулю, поскольку первому элементу соответствует адресное выражение а+0.
Язык C# сохранил 0-базируемость массивов. Индексы элементов массива в языке C# изменяются в плотном интервале значений от нижней границы, всегда равной 0, до верхней границы, которая задана динамически вычисляемым выражением, возможно, зависящим от переменных. Массивы C# являются 0-базируемыми динамическими массивами. Это важно понимать с самого начала.
Не менее важно понимать и то, что массивы C# относятся к ссылочным типам.
Ввод-вывод массивов
Как у массивов появляются значения, как они изменяются? Возможны три основных способа:
- вычисление значений в программе;
- значения вводит пользователь;
- связывание с источником данных.
В задачах этого раздела ограничимся пока рассмотрением первых двух способов. Первый способ более или менее понятен. Простые примеры его применения приводились неоднократно. Стоит только отметить, что в классе, работающем с массивами, всегда полезно иметь метод FillArray, позволяющий заполнять массив случайными числами. В примерах использование возможностей класса Random для моделирования элементов массива встречалось неоднократно.
Приведу некоторые рекомендации по вводу и выводу массивов, ориентированные на работу с конечным пользователем.
Для консольных приложений ввод массива обычно проходит несколько этапов:
- ввод размеров массива;
- создание массива;
- организация цикла по числу элементов массива, в теле которого выполняется:
- приглашение к вводу очередного элемента;
- ввод элемента;
- проверка корректности введенного значения.
Вначале у пользователя запрашиваются размеры массива, затем создается массив заданного размера. В цикле по числу элементов организуется ввод значений. Вводу каждого значения предшествует приглашение к вводу с указанием типа вводимого значения, а при необходимости — и диапазона, в котором должно находиться требуемое значение. Поскольку ввод значений — это ответственная операция, а на пользователя никогда нельзя положиться, после ввода часто организуется проверка корректности введенного значения. При некорректном задании значения элемента ввод повторяется, пока не будет достигнут желаемый результат.
При выводе массива на консоль обычно вначале выводится имя массива, а затем его элементы в виде пары: <имя> = <значение> (например, f[5] = 77,7). Задача осложняется для многомерных массивов, когда пользователю важно видеть не только значения, но и структуру массива, располагая строку массива в строке экрана.
Как организовать контроль ввода? Наиболее разумно использовать для этих целей конструкцию охраняемых блоков — try — catch блоков. Это общий подход, когда все опасные действия, связанные с работой пользователя, внешних устройств, внешних источников данных, размещаются в охраняемых блоках.
Как правило, для ввода-вывода массивов пишутся специальные процедуры, вызываемые в нужный момент.
Ввод-вывод массивов в Windows-приложениях
Приложения Windows позволяют построить дружелюбный интерфейс пользователя, облегчающий работу по вводу и выводу массивов. И здесь, когда данные задаются пользователем, заполнение массива проходит через те же этапы, что рассматривались для консольных приложений. Но выглядит все это более красиво, наглядно и понятно. Пример подобного интерфейса, обеспечивающего работу по вводу и выводу одномерного массива, показан на
рис.
6.4.
Рис.
6.4.
Форма для ввода-вывода одномерного массива
Пользователь вводит в текстовое окно число элементов массива и нажимает командную кнопку «Создать массив», обработчик которой создает массив заданной размерности, если корректно задан размер массива, в противном случае выдает сообщение об ошибке и ждет корректного ввода.
В случае успешного создания массива пользователь может переходить к следующему этапу — вводу элементов массива. Очередной элемент массива вводится в текстовое окно, а обработчик командной кнопки «Ввести элемент» обеспечивает передачу значения в массив. Корректность ввода контролируется и на этом этапе, проверяя значение введенного элемента и выводя в специальное окно сообщение в случае его некорректности, добиваясь, в конечном итоге, получения от пользователя корректного ввода.
Для облегчения работы пользователя выводится подсказка, какой именно элемент должен вводить пользователь. После того, как все элементы массива введены, окно ввода становится недоступным для ввода элементов. Интерфейс формы позволяет многократно создавать новый массив, повторяя весь процесс.
На
рис.
6.4 форма разделена на две части — для ввода и вывода массива. Крайне важно уметь организовать ввод массива, принимая данные от пользователя. Не менее важно уметь отображать существующий массив в форме, удобной для восприятия пользователя. На рисунке показаны три различных элемента управления, пригодные для этих целей, — ListBox, CheckedListBox и ComboBox. Как только вводится очередной элемент, он немедленно отображается во всех трех списках.
В реальности отображать массив в трех списках, конечно, не нужно, это сделано только в целях демонстрации возможностей различных элементов управления. Для целей вывода подходит любой из них, выбор зависит от контекста и предпочтений пользователя. Элемент ComboBox имеет дополнительное текстовое окно, в которое пользователь может вводить значение. Элемент CheckedListBox обладает дополнительными свойствами в сравнении с элементом ListBox, позволяя отмечать некоторые элементы списка (массива). Отмеченные пользователем элементы составляют специальную коллекцию. Эта коллекция доступна, с ней можно работать, что иногда весьма полезно. Чаще всего для вывода массива используется элемент ListBox.
Посмотрим, как это все организовано программно. Начну с полей формы OneDimArrayForm, показанной на
рис.
6.4:
//fields int n = 0; double[] mas; int currentindex = 0; double ditem = 0; const string SIZE = "Корректно задайте размер массива!"; const string INVITE = "Введите число в формате m[,n]"; const string EMPTY = "Массив пуст!"; const string ITEMB = "mas["; const string ITEME = "] = "; const string FULL = "Ввод недоступен!"; const string OK = "Корректный ввод!"; const string ERR = "Ошибка ввода числа! Повторите ввод!";
Полями этого класса является одномерный массив, его размер, текущий индекс и константы, используемые в процессе диалога с пользователем. Обработчик события Click командной кнопки, отвечающей за создание массива, имеет вид:
private void buttonCreateArray_Click(object sender, EventArgs e) { try { n = Convert.ToInt32(textBoxN.Text); mas = new double[n]; labelInvite.Text = INVITE; labelItem.Text = ITEMB + "0" + ITEME; labelResult.Text = EMPTY; textBoxItem.ReadOnly = false; listBox1.Items.Clear(); comboBox1.Items.Clear(); checkedListBox1.Items.Clear(); comboBox1.Items.Clear(); currentindex = 0; } catch (Exception) { labelResult.Text = SIZE; } }
Первым делом принимается размер массива, введенный пользователем. Преобразование к типу int введенного значения помещено в охраняемый блок, поэтому ошибки некорректного ввода будут перехвачены с выдачей соответствующего сообщения. Если же массив успешно создан, то инициализируются начальными значениями все элементы интерфейса, участвующие в вводе элементов массива. Рассмотрим, как устроен ввод элементов.
private void buttonAddItem_Click(object sender, EventArgs e) { //Заполнение массива элементами if (GetItem()) { mas[currentindex] = ditem; listBox1.Items.Add(mas[currentindex]); checkedListBox1.Items.Add(mas[currentindex]); comboBox1.Items.Add(mas[currentindex]); currentindex++; labelItem.Text = ITEMB + currentindex + ITEME; textBoxItem.Text = ""; labelResult.Text = OK; if (currentindex == n) { labelInvite.Text = ""; labelItem.Text = ""; labelResult.Text = FULL; textBoxItem.Text = ""; textBoxItem.ReadOnly = true; } } }
Функция GetItem вводит значение очередного элемента. Если пользователь корректно задал его значение, то элемент добавляется в массив, а заодно и в списки, отображающие текущее состояние массива. Создается подсказка для ввода следующего элемента массива, а если массив полностью определен, то форма переходит в состояние окончания ввода.
/// <summary> /// Ввод с контролем текущего элемента массива /// </summary> /// <returns>true в случае корректного ввода значения</returns> bool GetItem() { string item = textBoxItem.Text; bool res = false; if (item == "") labelResult.Text = INVITE; else { try { ditem = Convert.ToDouble(item); res = true; } catch(Exception) { labelResult.Text = ERR; } } return res; }
Форму OneDimArrayForm можно рассматривать как некоторый шаблон, полезный при организации ввода и вывода одномерных массивов.
Is it possible to create an array of controls? Is there a way to get the index of a control if more than one of the controls in the array share the same event handler?
asked Jan 30, 2010 at 15:29
KevinKevin
3,53410 gold badges38 silver badges43 bronze badges
4
This is certainly possible to do. Sharing the event handler is fairly easy to do in this case because the Button
which raised the event is sent as part of the event args. It will be the sender
value and can be cast back to a Button
Here is some sample code
class Form1 : Form {
private Button[] _buttons;
public Form1(int count) {
_buttons = new Button[count];
for ( int i = 0; i < count; i++ ) {
var b = new Button();
b.Text = "Button" + i.ToString()
b.Click += new EventHandler(OnButtonClick);
_buttons[i] = b;
}
}
private void OnButtonClick(object sender, EventArgs e) {
var whichButton = (Button)sender;
...
}
}
answered Jan 30, 2010 at 16:59
JaredParJaredPar
722k147 gold badges1226 silver badges1448 bronze badges
1
Based on Kevins comment:
foreach(Button b in MyForm.Controls.OfType<Button>())
{
b.Click += Button_Click;
}
void Button_Click(object sender, EventArgs e)
{
Button clickedButton = sender as Button;
}
answered Jan 30, 2010 at 15:47
Jan JongboomJan Jongboom
26.3k9 gold badges82 silver badges120 bronze badges
Дата изменения: 7 сентября 2022
Лабораторные работы си шарп. Массивы»
Приложения для Windows forms
Лабораторная работа 10
Выполнить: Создайте проект для подсчета суммы и среднего арифметического значения элементов одномерного массива.
Пример выполнения:
Рис. Форма «Массивы»
[Название проекта: Lab10
, название файла Lab10.cs
]
Выполнение:
- Создайте новый проект. Расположите элементы управления на новой форме (см. рисунок).
- Задайте свойству Multiline для текстового окна txtArray значение равное true (для того, чтобы в текстовом окне можно было выводить текст в несколько строк).
- Далее необходимо запрограммировать кнопку Вычислить (btnCalc) так, чтобы в текстовое окно выводились элементы массива, их сумма, а затем их среднее арифметическое. Для этого в процедуре, описывающей событие щелчка мыши по кнопке Вычислить, опишем переменные, которые мы будем использовать при решении поставленной задачи:
- Для среднего арифметического специальную переменную описывать не надо, потому что оно вычисляется по формуле sum разделить на 10.
- Для того чтобы задать значения элементов массива, воспользуемся циклом. Для генерации случайных чисел будем использовать переменную — экземпляр объекта
Random
: - Добавьте в цикл вычисление суммы элементов массива:
- Теперь осталось вывести элементы массива, сумму и среднее арифметическое в текстовое окно.
- Сначала выведите слово Массив:
- Теперь в цикле необходимо вывести элементы массива:
- Самостоятельно добавьте вывод в текстовое окно среднего арифметического.
- Запустите и отладьте программу.
private void btnCalc_Click(object sender, EventArgs e) { int[] arr = new int[10]; int sum=0; }
Random rand = new Random(); for(int i=0;i<arr.Length;i++) { arr[i] = rand.Next(20); //... }
txtArray.Text = "Массив: ";
for (int i = 0; i < arr.Length; i++) { txtArray.Text += arr[i].ToString()+" "; }
Дополнительное задание:
Контрольное задание:
Вопросы для самоконтроля:
- Как объявляется массив в VC#?
- Сколько элементов будет содержать массив, который описан с помощью следующего оператора:
- С помощью какого ключевого слова можно описать массив, который будет доступен всем модулям приложения?
Одной из наиболее часто используемых структур данных является массив. О том как работать с массивами в C# вы узнаете в этом уроке.
- Объявление массивов и инициализация массивов
- Объявление массивов
- Инициализация массивов
- Неявная типизация
- Доступ к элементам массива. Обход элементов массива.
- Передача массива в метод
- Многомерные массивы
- Прямоугольные массивы
- Зубчатые массивы
- Класс System.Array
Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.
Объявление массивов и инициализация массивов
Объявление массивов
Массив – это структура данных для хранения элементом определенного типа, имеющая фиксированный размер. Доступ к элементам массива производится по числовому индексу.
Для объявления массива, после указания типа его элементов, ставятся квадратные скобки:
int[] a1; // массив типа int
Перед использованием, массив обязательно нужно проинициализировать, это можно сделать сразу, при его объявлении:
int[] na2 = new int[5]; // массив из пяти элементов типа int
Либо после объявления:
int[] na3; na3 = new int[5]; // массив из пяти элементов типа int
Для доступа к элементам массива используются числовые индексы. Значения элементов массива будут равны значению по умолчанию для типа, массив которого был создан.
Например, для указанного выше a3 – это будут нули, так как для типа int значение по умолчанию: 0;
Console.WriteLine(na3[0]); // значение: 0 Console.WriteLine(na3[1]); // значение: 0
Если попытаться вывести элементы массива na1:
Console.WriteLine(na1[0]); // ошибка компиляции
то приложение не будет собрано, т.к. массив предварительно нужно проинициализировать.
Инициализация массивов
Рассмотрим различные варианты инициализации массива. Как уже было сказано, можно просто указать количество элементов в массиве, при этом его элементам будут присвоены значения по умолчанию:
bool[] ba1 = new bool[3]; Console.WriteLine("ba1[0]: " + ba1[0].ToString());
После объявления массива значения элементам присваиваются через индекс:
string[] sa1 = new string[3]; sa1[0] = "abc"; sa1[1] = "def"; sa1[2] = "ghi"; Console.WriteLine($"sa1: {sa1[0]}, {sa1[1]}, {sa1[2]}");
Есть возможность задать конкретные значения в момент объявления с использованием ключевого слова new и указанием типа:
double[] da1 = new double[3] {0.1, 0.2, 0.3}; Console.WriteLine($"da1: {da1[0]}, {da1[1]}, {da1[2]}");
Либо без ключевого слова new:
double[] da2 = {0.4, 0.5, 0.6}; Console.WriteLine($"da2: {da2[0]}, {da2[1]}, {da2[2]}");
Неявная типизация
При объявлении массива можно воспользоваться ключевым словом var. При этом тип элементов массива следует задать явно в правой части объявления:
var va2 = new string[3]; va2[0] = "John"; va2[1] = "Mary"; va2[2] = "Mike"; Console.WriteLine($"va2: {va2[0]}, {va2[1]}, {va2[2]}");
Либо предоставить возможность “поработать” системе вывода типов:
var va1 = new[] {1, 2, 3}; Console.WriteLine($"va1: {va1[0]}, {va1[1]}, {va1[2]}");
Доступ к элементам массива. Обход элементов массива.
Как уже было сказано выше, за доступ к элементам массива отвечают числовые индексы:
int[] na4 = {1, 2, 3, 4, 5}; Console.WriteLine($"na4[0]: {na4[0]}");
При этом, если вы укажете индекс больше, чем максимально возможный, то будет выброшено исключение:
Console.WriteLine($"na4[10]: {na4[10]}");
Приведенная выше строка приведет к выбросу следующего исключения:
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
Обход элементов массива можно производить с помощью циклов for, foreach и while, последний самый неудобный для работы с массивами, его мы рассматривать не будем. Если вы работаете с циклом for, то для указания верхней границы инкрементируемой переменной можно воспользоваться свойством Length у массива:
for(int i = 0; i < na4.Length; i++) { Console.Write(na4[i].ToString() + " "); } // 1 2 3 4 5
Более удобным для обхода элементов будет foreach:
foreach(var v in na4) { Console.Write(v.ToString() + " "); } // 1 2 3 4 5
Преимущество цикла for состоит в том, что в нем вы можете модифицировать элементы массива:
for(int i = 0; i < na4.Length; i++) { na4[i] = (na4[i] + 3) * 10; Console.Write(na4[i].ToString() + " "); } // 40 50 60 70 80
Передача массива в метод
Массивы являются ссылочным типом данных, это означает, что их значения хранятся в куче, а имя переменной массива является ссылкой на соответствующую область памяти. При передаче массива в качестве аргумента в метод, происходит присваивание значения переменной массива переменной определяющей аргумент, а так как имя массива – это ссылка, то фактически происходит передача ссылки на значение в куче. Поэтому, если вы передали массив в функцию и внутри этой функции произошла модификация этого массива, то исходный массив тоже изменится.
Создадим метода WorkWithArray, который изменяет содержимое массива:
public static void WorkWithArray(int[] arr) { arr[0] = 123; }
Вызовем его в методе Main:
int[] na5 = {1, 2, 3, 4, 5}; foreach(var v in na5) // 1 2 3 4 5 Console.Write(v + " "); Console.WriteLine(); WorkWithArray(na5); foreach(var v in na5) // 123 2 3 4 5 Console.Write(v + " ");
Ниже приведена иллюстрация того, как массив и ссылки на него располагаются в памяти.
Переменные na5 в методе Main и arr в методе WorkWithArray ссылаются на одну и ту же область памяти в куче, поэтому изменение массива через переменную arr отражается на переменной na5.
Многомерные массивы
Массивы имеющее более одного измерения называются многомерными. До этого мы работали с одномерными массивами. В C# предлагается к использованию два вида многомерных массивов: прямоугольные и зубчатые, которые иногда называются массивы массивов.
Прямоугольные массивы
Прямоугольные массивы могут содержать несколько измерений (два и более), при этом количество элементов в каждом подизмерении (в каждой строке) одинаково.
Рассмотрим на примерах работу с такими массивами:
double[,] dm1 = new double[3, 3]; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) dm1[i, j] = i + j; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) Console.Write($"{dm1[i, j]} "); Console.WriteLine(); } Console.WriteLine(); double[,] dm2 = { { 1, 2, 3 }, { 4, 5, 6 } }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) Console.Write($"{dm2[i, j]} "); Console.WriteLine(); } Console.WriteLine();
Зубчатые массивы
В зубчатых массивах элементами верхнего уровня являются другие массивы, это позволяет создавать многомерные структуры, у которых строки имеют разную длину:
int[][] nm1 = new int[3][]; for(int i = 0; i < nm1.Length; i++) nm1[i] = new int[i+1]; for(int i = 0; i < nm1.Length; i++) { for(int j = 0; j < nm1[i].Length; j++) Console.Write($"{nm1[i][j]} "); Console.WriteLine(); }
Класс System.Array
Класс System.Array является базовым для всех массивов, это позволяет использовать свойства и методы данного класса при работе с массивом. Ниже в таблицах приведены некоторые полезные свойства и методы из System.Array, более полную информацию вы можете найти в официальной документации Microsoft (https://docs.microsoft.com/ru-ru/dotnet/api/system.array).
Свойства класса System.Array
Имя свойства |
Назначение |
Length |
Число элементов в массиве. Учитываются все измерения. |
Rank |
Ранг массива – число измерений. |
int[] na6 = {1, 2, 3, 4, 5, 6, 7}; int[,] nm2 = { {1, 2, 3}, {4, 5, 6}}; int[][] nm3 = new int[3][]; for(int i = 0; i < nm3.Length; i++) nm3[i] = new int[i+1]; Console.WriteLine($"na6: Length={na6.Length}, Rank={na6.Rank}"); // na6: Length=7, Rank=1 Console.WriteLine($"nm2: Length={nm2.Length}, Rank={nm2.Rank}"); // nm2: Length=6, Rank=2 Console.WriteLine($"nm3: Length={nm3.Length}, Rank={nm3.Rank}"); // nm3: Length=3, Rank=1
Методы класса System.Array
Символ * после названия метода означает, что он имеет более одной сигнатуры, за дополнительной информацией обращайтесь к официальной документации.
Имя метода |
Назначение |
BinarySearch(Array, Object)* |
Выполняет поиск элемента в массиве. |
Clear(Array, Int32, Int32) |
Присваивает значение по умолчанию определенному количеству элементов массива начиная с заданного индекса. |
Clone() |
Создает копию массива (неполную). |
Copy(Array, Array, Int32)* |
Копирует данные из одного массива в другой в заданном количестве. |
CopyTo(Array, Int32)* |
Копирует элементы из текущего массива в заданный, начиная с указанного индекса. |
Exists<T>(T[], Predicate<T>) |
Определяет наличие элемента удовлетворяющему предикату. |
GetValue(Int32)* |
Возвращает значение по указанному индексу. |
IndexOf(Array, Object)* |
Возвращает индекс первого вхождения элемента в массиве. |
Reverse(Array)* |
Задает обратный порядок для элементов в массиве. |
Sort(Array)* |
Сортирует элементы массива. |
Для вывода содержимого массива в консоль создадим метод PrintArray:
public static void PrintArray<T>(string txt, T[] arr) { Console.Write($"{txt}: "); foreach(var v in arr) { Console.Write($"{v} "); } }
Ниже приведены примеры использования представленных выше методов и свойств класса System.Array:
int[] na6 = {1, 2, 3, 4, 5, 6, 7}; int[,] nm2 = { {1, 2, 3}, {4, 5, 6}}; int[][] nm3 = new int[3][]; for(int i = 0; i < nm3.Length; i++) nm3[i] = new int[i+1]; Console.WriteLine($"na6: Length={na6.Length}, Rank={na6.Rank}"); // na6: Length=7, Rank=1 Console.WriteLine($"nm2: Length={nm2.Length}, Rank={nm2.Rank}"); // nm2: Length=6, Rank=2 Console.WriteLine($"nm3: Length={nm3.Length}, Rank={nm3.Rank}"); // nm3: Length=3, Rank=1 Console.WriteLine("BinarySearch result: " + Array.BinarySearch(na6, 5).ToString()); // BinarySearch result: 4 var na7 = (int[])na6.Clone(); Array.Clear(na7, 2, 2); PrintArray<int>("na6", na6); // na6: 1 2 3 4 5 6 7 PrintArray<int>("na7", na7); // na7: 1 2 0 0 5 6 7 Array.Copy(na7, na6, 4); PrintArray<int>("na6 after copy", na6); // na6 after copy: 1 2 0 0 5 6 7 (new int[]{1, 2, 3, 4}).CopyTo(na6, 0); PrintArray<int>("na6", na6); // na6: 1 2 3 4 5 6 7 var ans = Array.Exists<int>(na6, v => (v % 2) == 0); Console.WriteLine($"Is even number exists in na6? Answer: {ans}"); Array.Fill<int>(na7, 7); PrintArray<int>("na7", na7); // na7: 7 7 7 7 7 7 7 Console.WriteLine($"Value at 3 index in na6: {na6.GetValue(3)}"); Console.WriteLine($"Index of value=5 in na6: {Array.IndexOf(na6, 5)}"); Array.Reverse(na6); PrintArray<int>("na6", na6); // na6: 7 6 5 4 3 2 1 Array.Sort(na6); PrintArray<int>("na6", na6); // na6: 1 2 3 4 5 6 7
Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.