Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование на языке C# Консольные и оконные приложения. Лабораторный практикум. Учебное пособие

.pdf
Скачиваний:
1
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
Динамическое выделение памяти
Конструкции, приведенные выше, являются аналогами описания статических массивов с других языках программирования
13
, в том числе и C++. Особенность не только в простоте
описания, но и в том, что всю работу по организации выделения и высвобождения необхо­димой памяти на себя берет компилятор. Поэтому и необходимо в качестве размера указы­вать константы – компилятор знает о массиве (или матрице) всё и может прописать необхо­димые машинные коды.
В программах со сложными алгоритмами часто количество данных, т. е. длина масси­ва, неизвестно на стадии разработки. Тогда используют методы динамического выделения памяти14.
В языке C# для выделения памяти с объемом, рассчитанным во время исполнения про­граммы, используют тот же оператор new. Общий вид записи этого оператора следующий:
<тип>[] <имя> = new <тип> [<количество>];
Отличие лишь в том, что <количество> может быть как константой, так и перемен­ной и даже выражением целого типа.
Другими словами, в отличие от языка C++, для выделения памяти под массивы с заранее известными размерами или известными только в ходе работы используется единый формат оператора.
То же самое касается и двумерных массивов.
В стандарте языка ANSI C и в объектно-расширенном языке C++ при выделении памяти динамически, необходимо её и освобождать в программе. Такой же принцип и в других язы­ках программирования.
В языке C# описание массивов очень сходно с языком C++. Но здесь переменные типа массивов не просто указатели ячейки памяти, а на объекты из библиотеки Framework .NET. Это несколько иные и принципы, и технологии15. Поэтому в программах C# не требуется специально заботиться об освобождении памяти. Программа опирается на технологию .NET, а в ней вопросами контроля за памятью занимается «сборщик мусора». Но при желании это можно сделать специальными операторами.
По тем же причинам из-за технологии .NET, в C# у переменных-массивов можно спро­сить размер – количество элементов16. Этот опрос можно выполнить оператором
<имя>.Length
Например, можно напечатать размер массива
Console.WriteLine(“Длина {0}”, mass.Length);
Для многомерных массивов через этот оператор можно узнать общее количество эле­ментов в агрегированной переменной, а длину по каждой из размерностей (координате) можно узнать через оператор
<имя>.GetLength(<индекс>)
где <индекс> – номер размерности: 0 – количество строк, 1 – количество столбцов.
Листинг 1. Пример типового использования в программе массива с динамическим выделением памяти:
double[] y;
int n, i;
… // выполняются какие-то действия в программе
13
Аналогом скрытого процесса автоматического выделения памяти под статичные массивы, в момент описа-
ния, в языке C# является явное использование оператора new.
14
В широком смысле под динамическими массивами понимают и массивы с размерами, определяемыми в ходе
работы программы, и массивы, чьи размеры меняются в ходе выполнения кода.
15
И техника работы с объектами, в частности массивами, в программе.
16
В других языках размер массива можно узнать только через те переменные или константы, через которые они
и задавались при описании или выделении памяти.
31
n = выражение;
… // выполняются какие-то действия в программе
y = new double [n];
… // выполняются какие-то действия в программе
for (i = 0; i < n; i++)
Console.Write (“{0} “, y [i]);
… // выполняются какие-то действия в программе
В данном примере показан вариант, когда описание переменной типа массива и выде­ление памяти под этот массив в коде программы разнесены.
Контрольные вопросы
1. Как описать переменную типа «одномерный массив»?
2. Как описать переменную типа «двумерный массив»?
3. Как использовать циклы для обработки двумерных массивов?
4. Как вывести значения элементов одномерного или двумерного массива?
Варианты задания
Для практического закрепления навыков использования массивов разработайте про­грамму для решения задачи из соответствующего варианта.
Вариант 1
,, ,
Дано натуральное число n, целые числа
aa a
01
. Среди чисел имеется группа из
n
отрицательных чисел, расположенных подряд. Переписать эту группу в отдельный массив. Если группы нет, то выдать сообщение об этом. Если таких групп несколько, выдать послед­нюю группу.
Вариант 2
,, ,
Дано натуральное число n, целые числа
aa a
01
. В новый массив включить числа,
n
которые расположены после последнего нулевого элемента при условии, что они кратны числу 3. Если нулевых элементов нет, то выдать сообщение об этом.
Вариант 3
,, ,
Дано натуральное число n, целые числа
aa a
01
. Массив чисел представлен группами
n
одинаковых элементов, идущих подряд. Кроме этого имеется группа из возрастающих элемен­тов, также расположенных подряд. Переписать эту группу в отдельный массив. Если группы нет, то выдать сообщение об этом. Если таких групп несколько, выдать первую группу.
32
Лабораторная работа № 8
Проектирование и разработка программ с использованием функций
Цель работы: получить практические навыки реализации программ в MS VS C#, ис- пользующих функции для обработки данных.
Глоссарий
Подпрограмма (англ. – subroutine) – поименованная или иным образом идентифи-
цированная часть компьютерной программы, содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы.
Функция – это подпрограмма специального вида, которая кроме получения пара-
метров, для выполнения действий и передачи результатов работы через параметры имеет ещё одну особенность – она должна возвращать результат через заголовок. Но в языке C++ все виды подпрограмм реализуются через функции.
Формальные параметры – в заголовке подпрограмме указывают, с аргументами
какого вида следует обращаться к этой подпрограмме (количество аргументов, их последова­тельность, типы). Они задаются в заголовке подпрограммы в виде списка.
Фактические параметры – при вызове подпрограммы список переменных и выра-
жений, значения которых необходимо передать в подпрограмму; и/или переменные вызыва­ющей программы, в которые необходимо поместить результат.
Процедура – это независимая именованная часть программы, которую после одно-
кратного описания можно многократно вызвать по имени из последующих частей програм­мы для выполнения определенных действий. Получает данные и возвращает результаты только через параметры.
Методические указания
При усложнении алгоритма решения задач текст программ приходится разбивать на большие логические блоки, в частности на блоки, используемые часто или повторно. В этих случаях прибегают к разбиению программы на подпрограммы.
В языке C# используется только один тип подпрограмм – функция. Такая подпрограмма через входные параметры принимает некоторые значения и возвращает результаты своей ра­боты через имя функции и, если необходимо, через выходные параметры.
Функции с простыми параметрами
Функция описывается заголовком и телом. Заголовок содержит:
имя функции;
тип возвращаемого результата;
типы и имена формальных параметров, заключенные в круглые скобки и разделен-
ные запятыми.
Телом функции является составной оператор, объединяющий описание внутренних пе- ременных функции (или локальные переменные), и операторы, реализующие функцию
static <тип результата> <имя функции>(<список формальных параметров>)
{
<тело функции>
}
Здесь ключевое слово static определяет тип метода в структуре класса. В простейших случаях лучше использовать именно тип static. Пример описания функции на языке C#:
static double linefunc (double x, double a, double b)
{
return a*x + b;
}
В данном примере результат вычисления значения линейной функции возвращается через имя функции. Следует обратить внимание и твердо запомнить, что функция должна
33
завершаться оператором возврата return, с указанием значения (в виде переменной или выражения) которое функция должна вернуть через имя.
Структура программы, написанной на языке C# (в .NET), несколько сложнее, чем про­граммы на языке C++. Структура программы на C++ – это набор подпрограмм (функций), одна из которых главная – main( ). Программа на C# является классом, состоящим из набора
методов, возможно только лишь из одного – Main(string[] args). Но если есть и другие методы, то они описываются после или до метода Main, и их вызов может выполняться как из главной функции, так и из других, для лучшего структурирования кода. Такая функция
может использоваться (вызываться) следующим образом17:
double z = 15.2 + linefunc (2.3, 4.5, 6.7);
Для организации передачи результатов через список параметров (а не через заголовок; или в дополнение к результату, возвращаемому через заголовок) используется описание с использованием ключевого слова ref или out. Тогда при вызове такой подпрограммы в ка­честве фактического параметра передается не значение, а адрес требуемой переменной18. В теле такой функции этому формальному параметру должно быть присвоено значение хотя бы один раз. Это значение и будет возвращено подпрограммой через этот формальный пара­метр (уложено значение в эту фактическую переменную).
Листинг 1. Пример описания и использования функции, возвращающей результат через формальный параметр:
static void subproc (double a, double b, ref double c)
{
c = a + b; // вычисление выражения;
// результат вернуть через формальный параметр 'c'
return;
}
static void Main(string[] args)
… // здесь может быть предшествующий код
{
Console.WriteLine("Стартуем:");
double x = 5.0, y = 1.0, answ = 0.0;
subproc(x, y, ref answ);
Console.WriteLine("Исходные: {0}, {1}", x, y);
Console.WriteLine("Результат = {0}", answ);
… // здесь может быть последующий код
}
Необходимо помнить, что при вызове функции в качестве фактического параметра, за­даваемого на позиции формального параметра со словом ref, может использоваться только переменная. Здесь компилятор должен подставить адрес, по которому можно укладывать значение; ни константа, ни выражение не имеют адреса и принять значение на сохранение не может. В данном примере вызов
subproc (5.0, 1.0, ref answ);
функции можно выполнить так:
Обратите внимание, что при вызове подпрограммы третий фактический параметр (пе­ременная) предваряется тоже ключевым словом ref. И более того, хоть мы и уверены, что переменная answ будет использоваться только для получения значения, но она заранее должна быть инициирована.
Итак, функция может возвращать значения:
через заголовок функции;
через формальные параметры;
через заголовок функции и формальные параметры.
Помимо этого, необходимо помнить, что параметр с ключевым словом ref может ис­пользовать как входной и выходной одновременно – при вызове в нем размещается значение, полезное для работы функции, а при завершении через него передается новое значение.
17
Совершенно аналогично вызовам в ANSI C и C++.
18
При вызове такой функции в качестве фактического параметра указывается именно переменная, а не констан-
та или выражение.
34
Ключевое слово out имеет отличие в использовании. Если при описании функции применено ключевое слово out, то и при вызове требуется указывать это же слово. А вот выходная фактическая переменная не обязана инициироваться предварительно. При упо­треблении ключевого слова out, формальная переменная является исключительно выход­ной19. В теле функции ей необходимо присвоить значение. Но после того как значение было
присвоено, эта переменная может быть использована в правой части выражения, для вычис­ления значения какой-то переменной, например локальной.
Функции обработки массивов
Функции могут обрабатывать не только простые переменные, но и массивы и структу­ры. В простейшем случае функция может разрабатываться для обработки одномерного мас­сива (или двумерного) фиксированного размера.
При разработке функций естественно добиваться определенной универсальности. Поэтому функции обработки одномерных массивов, как правило, пишут для обработки мас- сивов произвольной длины. Тогда в качестве дополнительного формального параметра необ­ходимо указать целочисленную простую переменную, через которую будет задаваться раз-
мер этого массива.
Листинг 2. Суммирование элементов массива произвольной длины:
public double summ(double[] m, int n)
{
double s;
s = 0;
for (int i = 0; i < n; i++)
{
s += m[i];
}
return s;
}
Такая функция будет суммировать массив любой длины, но только с элементами
double.
В MS VS C# второй формальный параметр можно не указывать, т. к. размер массива можно узнать непосредственно у массива, через параметр Length.
Для описания формального параметра в виде массива, который является выходным (изменяются значения элементов массива), используется такая же форма.
Но в теле функции
отдельные операторы присваивают значения элементам массива.
Функции обработки двумерных массивов
Универсальным способом для обработки двумерных массивов является использование в формальных параметрах описания матрицы с указанием типа ячеек и размеров такого массива.
Листинг 3. Описание и использование функции для обработки двумерного динамического массива:
static void print_mNM(double[,] m, int dim1, int dim2)
{
for (int i = 0; i < dim1; i++)
{
for (int j = 0; j < dim2; j++)
Console.Write("{0} ", m[i, j]);
Console.WriteLine();
}
//return; может не писаться, если через заголовок
не возвращаются значения
}
19
Она не имеет входного значения, через нее нельзя вычислить какую-то другую переменную.
35
static void Main(string[] args)
{
…
// описание и инициализация матрицы, например, 56
…
print_mNM(matr, 5, 6);
…
}
Этот пример показывает, как можно обрабатывать созданную матрицу, используя функцию. Как и в случае одномерного массива два последних формальных параметра могут описываться в заголовке функции. В теле функции можно опросить размеры матрицы.
Контрольные вопросы
1. Как описать функцию в языке C#?
2. Как вызвать функцию в языке C#?
3. Как описать формальный параметр, чтобы через него вернуть некое значение?
4. Как описывается функция, если она не возвращает значение через заголовок, а толь-
ко через формальные параметры?
5. Как описать функцию, которая обрабатывает массив одномерный или двумерный?
Варианты заданий
Для практического закрепления навыков создания функций для обработки массивов напишите короткую программу и одну или несколько подпрограмм.
Вариант 1
1. Найти сумму S положительных элементов массива
, , , аа а
12 20
и поместить ее на
место минимального элемента массива.
Вариант 2
2. В массиве чисел
, , ...,bb b
12 14
найти сумму положительных и сумму отрицательных
элементов. Заменить минимальный элемент массива величиной, равной сумме положитель­ных элементов массива.
Вариант 3
3. Дан массив
, , ., аа а
12 12
Вычислить сумму элементов этого массива до первого
элемента, равного 0, и сумму оставшихся элементов.
36
Лабораторная работа № 9
Разработка простейшего оконного приложения в среде MS VS C#
Цель работы: приобрести практические навыки в использовании компонентов Label, TextBox, Button при разработке событийно ориентированных программ с оконным
интерфейсом.
Методические указания
В качестве простой программы на C# может быть реализован проект вычисления по формуле. После запуска программы открывается окно, в котором есть несколько полей для ввода исходных данных (параметров для вычисления формулы) и поле для вывода результата. Пример окна такой программы приведен на рисунке.
Рис. Пример интерфейса приложения, предназначенного для вычислений по формулам
Окно программы содержит простейшие компоненты – поля для ввода текста
(TextBox); метки (Label), поясняющие назначение полей; кнопки (Button) для активации
действий, заложенных в программу. Более сложные программы представлены несколькими взаимодействующими окнами и содержат компоненты других типов.
Основные свойства компонента Label
Компонент представляет собой статический текст. Применяется для отображения ин-
формации, задания заголовков
Text (AppearanceLocation (Layout), X, Y – координаты левого верхнего компонента по отношению к
другим компонентам. Наиболее часто используемые свойства:
20
) – строка текста, отображаемая на форме, в поле метки;
рабочей области формы;
Size (Layout), Width, Height – размеры: ширина и высота поля; Autosize (Layout) – определяет, автоматически или вручную задаются размеры.
Когда размеры задаются вручную, то текст переносится по словам по ширине поля.
Основные свойства компонента TextBox
Компонент TextBox отображает прямоугольную область для ввода и редактирования одиночной строки информации на форме. Начальное содержимое области редактирования определяет строка, являющаяся значением свойства Text. Основные поля компонента:
Text (Appearance) – текст компонента в поле редактирования. Это свойство пред-
ставляет собой стандартную строку на языке C# типа string;
BorderStyle (Appearance) – стиль обрамления поля редактора;
20
В скобках указаны разделы размещения данного поля.
37
ChararacterCasing (Behavior) – при вводе преобразовывать автоматически сим-
волы в верхний (Upper) или нижний (Lower) регистр или нет (Normal);
MaxLength (Behavior) – максимальная длина текста;
ReadOnly (Behavior) – запрещает возможность редактирования, т. е. окно только
отображает текст, передаваемый из программы;
WordWrap (Behavior) – определяет возможность переноса слов по ширине поля, ес-
ли текст выходит за границу.
Обработчики событий и методы:
обработчик событий TextChanged – событие, позволяющее отслеживать измене-
ния в окне редактора (вкладка Events). Используется, если программа должна выполнять ка­кие-либо действия по ходу набора текста в окне редактирования;
метод Clear – очищает весь текст в окне редактора.
Основные свойства компонента Button
Компонент Button отображает прямоугольную область – анимированную кнопку для активизации некоторых действий, исполняемых программой. Основные поля компонента:
Text (Appearance) – надпись на кнопке;
Location (Layout), X, Y – координаты левого верхнего компонента по отношению к
рабочей области формы;
Size (Layout), Width, Height – размеры: ширина и высота поля;
Autosize (Layout) – определяет, автоматически или вручную задаются размеры.
Когда размеры задаются вручную, то текст переносится по словам по ширине поля.
Обработчик событий Click – событие, позволяющее отслеживать, что по кнопке щелкнули мышью, и выполнять соответствующие действия (вкладка Events).
Конечно, здесь приведены не все поля-свойства и обработчики событий для этих ком­понент. Другие свойства используются значительно реже и могут быть легко освоены по ме­ре усложнения интерфейсной части программы.
Тип строк string
В MS VS C# реализован класс-строка – string, или String. При объявлении пере­менные типа string инициализируются, как это принято в C#, например пустой строкой21.
Часто при работе со строками приходится выполнять их сравнение. Переменные такого типа в C# имеют два метода для сравнения своего собственного текста22 с другим текстом. Для переменной типа string определена функция сравнения текста, хранящегося в ней, с другим текстом на равенство (эквивалентность) – Equals. Она возвращает булевское значе­ние. Помимо этого, можно сравнить и на неравенство помощью функции CompareTo, кото­рая возвращает целое значение –1, 0 или +1, в зависимости от соотношения текстов. Сравни­ваются коды символов, начиная с первого, и, если очередные символы не одинаковы, строка, содержащая символ с меньшим кодом, считается меньше. Если все символы совпали, но од­на строка длиннее и в ней имеются еще символы, то она считается больше, чем более корот­кая23. Примеры использования:
String ggg = "Старое", hhh = "Новое";
if (ggg.Equals(hhh)) <оператор 1>;
else <оператор 2>;
int how = ggg.CompareTo(hhh);
При таких значениях строк в операторе if отработает ветвь else. А переменной how присвоится значение 1.
21
Это важно, когда в следующий раз эта переменная в коде уже упоминается как читаемая, например, в правой
части оператора присваивания или в условии оператора if.
22
Необходимо помнить, что основное содержимое переменной класса string – строка текста. Длина текста и
другие параметры хранятся в такой сложной переменной, но играют вспомогательную роль.
23
Осторожно! Тщательно не выверялось. Проверить самостоятельно при использовании, когда одна строка
считается меньше другой.
38
Для string определены операции присваивания =, += и операция склеивания строк (конкатенации) +.
Определена также операция индексации []. Индексы начинаются с 0. Например, если S1 = "Привет", то Sl[0] вернет 'П', Sl[1] – 'р' и т. д. Класс string имеет множество и других
методов.
Тип string используется для ряда свойств компонентов C#, например для таких, как свойства Text окон редактирования, меток и разделов меню и т. д. Таким образом, постоянно имея дело с этими свойствами, вы постоянно работаете со string.
Функции преобразования строк типа String
Вычислительные задачи часто требуют преобразования численных значений веще­ственного типа или целого в строку текста и обратно.
Поскольку переменные вещественного и целого типа в языке C# – тоже объекты, то их преобразование в строку можно выполнить методом ToString( ). Аналогично, можно ре­зультат вычислений арифметического выражения «на ходу» преобразовать в текст, например:
textBox1.Text =(Math.Sin(x) + Math.Cos (y)).ToString();
Обратите внимание, что стандартные функции являются методами класса Math. Назва­ния функций совпадает с названиями стандартных функций из библиотеки C++, но здесь имена пишутся с большой буквы. Полный список функций из класса Math можно посмотреть в приложении.
Переменная типа string не имеет собственных методов преобразования в другие типы, в том числе и числовые. Для такого преобразования можно воспользоваться классом Convert и его методами, т. е. не создавать переменную, а вызывать методы, обращаясь непосредствен­но к классу. Это можно сделать, например, следующими операторами:
String ggg = "15e-2", hhh = "123";
double dVal = Convert.ToDouble(ggg);
int iVal = Convert.ToInt32(hhh);
Следует обратить внимание, что функций преобразований в целый формат несколько и применение той или иной зависит от того, целое значение какой длины мы хотим получить (от 16 до 64 бит).
Вещественное число, написанное здесь в тексте, не имеет знака отделения дробной части. Дело в том, что этот знак зависит от настроек Windows,
и его надо выбирать в зависимости от того,
на каком компьютере разрабатывается программа, на каком компьютере ее будут запускать.
Другой способ преобразовать строку в число – это обратиться к функции (методу)
Parse класса Double (или Int соответственно), например:
double fff2 = Double.Parse(textBox1.Text);
Здесь текст из окошка на форме преобразуется в вещественную переменную.
Но путаница со знаком разделения дробной части и то, что текст набирает человек (пользователь программы), приводят к тому, что есть высокая вероятность того, что такой текст программа не сможет воспринять (расшифровать) как число. И программа вылетит по ошибке с системным сообщением, малопонятным пользователю. Поэтому хорошо бы писать безопасный код, т. е. такую ситуацию взять под контроль программы. Для этого есть не­сколько способов. Простым подходом является использование функции TryParse. Отличие
в том, что такая функция (метод класса double/Double или Int32 и т. п.) пытается преобразовать текст в число, а через
заголовок она возвращает булевское значение, которое можно интерпретировать как сигнал − удалось ей это или нет. И в случае успеха значение числа функция заносит в соответствующую числовую переменную, т. е. вместо предыдущего примера лучше использовать примерно следующий код:
double fff2; bool res = Double.TryParse(textBox1.Text, out fff2);
39
Далее в коде программы можно проверить значение переменной res. И если оно true, то это гарантирует, что в fff2 то значение, которое написано в тексте окошка. При этом программа работает штатно.
Тип string здесь приведён из-за того, что поля-свойства компонентов, в частности Text, имеют такой тип. Поэтому если для решения задачи по обработке текстовых данных удобнее использовать тип StringBuilder, показанный в предыдущих лабораторных, то для вывода на интерфейс этот тип придётся преобразовывать в srting.
Контрольные вопросы
1. Для чего нужны компоненты на форме?
2. Как формируется имя процедуры-обработчика для кнопок Button?
3. В каких целях можно использовать элемент Label?
4. В каких целях можно использовать элемент TextBox?
5. Что делает процедура Close(), используемая в одной из кнопок Button?
6. Как формируется имя обработчика события Click() для кнопок Button?
7. Как присвоить переменной значение, соответствующее тексту из окна TextBox?
Варианты заданий
Создать однооконное приложение. На форме разместить поля ввода для переменных, использованных для вычисления по формуле. К одной из кнопок подключить обработчик Click(), в котором организовать передачу и преобразование данных во внутренние пере­менные, вычисление и передачу результата на форму. Вычисления проводить непосред-
ственно по указанной формуле. Не упрощать выражение.
При желании на форму можно добавить третью кнопку и вычислить результат по упрощенной формуле.
Вариант 1
i
sin tg .
yxtek 
k
3
7
q
Вариант 2
1
7tg2 .
yi n a
 
3||
u
te
w
Вариант 3
q
i
yxwh

sin tg .
3, 7
k
3
e
h
40
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]