Конспект лекций (C#)-unlocked. 1 Основные сведения о C# Особенности языка
![]()
|
2.3 Операторы инкремента и декремента При написании программ часто требуется увеличение (уменьшение) значения переменной на 1. В простейшем случае операцию увеличения можно выполнить с помощью конструкции <переменная> = <переменная>+1; Однако в C# (как, впрочем, и в языках-предшественниках) выполнение такой операции упрощено и записывается в виде <переменная>++; или ++<переменная>; Первый оператор называется постфиксным инкрементом, а второй – пре- фиксным инкрементом. При выполнении одиночной операции никаких различий между ними нет. Од- нако при использовании операторов в выражениях: для префиксного инкремента сначала выполняется инкремент, а потом использу- ется переменная в выражении; для постфиксного инкремента сначала используется переменная в выражении, а потом выполняется инкремент. Например, во фрагменте программы int i=1, b, c; b = i++; c = ++i; во второй строке сначала произойдёт присваивание, а потом будет выполнен инкре- мент (после выполнения строки b =1, i =2), а в третье строке сначала выполнится ин- кремент, а потом произойдёт присваивание (после выполнения строки c =3, i =3). Аналогично операторам инкремента работают и операторы декремента <переменная>--; или --<переменная>; Использование операторов инкремента и декремента может приводить к пло- хо читаемому коду, например: int i=1; i = i++ + ++i; // i = 4; 2.4 Операторные скобки {} Операторные скобки {} применяются в случае, когда необходимо объединить несколько операторов в единый сложный оператор. Необходимость в таких дей- 20 ствиях возникает, когда какой-либо оператор может выполнить только один другой оператор, а требуется выполнение нескольких (см., например, оператор if ). Также операторные скобки применяются для обозначения начала и окончания различных блоков программы, например, тела функции. 2.5 Условный оператор if Условный оператор if применяется для реализации разветвления хода выпол- нения программы на два направления в зависимости от некоторого условия. Формальное описание данного оператора имеет вид: if (<логическое значение>) <оператор если истина>; [else <оператор если ложь>;] В качестве <логическое значение> могут выступать логические перемен- ные, логические константы или выражения, дающее логическое значение. Если <логическое значение> даёт результат «Истина», то выполняется оператор <оператор если истина> , иначе: если задан блок else , то выполняется <оператор если ложь> ; если блок else не задан, то никаких действий не происходит. <оператор если истина> и <оператор если ложь> являются одиноч- ными операторами, поэтому если требуется выполнить более одного оператора, то они объединяются с использованием операторных скобок. Пример 1: найти минимум из двух целочисленных переменных a , b и сохра- нить его в переменную min 1 int a, b, min; a = ???; b = ???; if (a < b) min = a; else min = b; Пример 2: найти результат деления c b a и сохранить его в переменную res При этом, если b+c равно 0, то перед расчётом присвоить b значение 1, а c – значе- ние 0. double a, b, c, res; a = ???; b = ???; c = ???; 1 Здесь и далее приводятся только фрагменты программ, а не программы целиком. В листингах программ бло- ки ??? обозначают некоторые значения, которые присваиваются переменным. Источник получения этих значений неважен. 21 if (b+c == 0) { b = 1; c = 0; } res = a/(b+c); 2.6 Логические операторы «И» и «ИЛИ» Полные и укороченные логические операторы «И» и «ИЛИ» дают один и тот же результат, однако укороченные операторы могут работать быстрее и позволяют реализовывать более простые конструкции. Полные логические операторы выполняют логическое выражение полностью. Например, в выражении a < b & c > d сначала будет вычислен результат a < b , потом c > d и только потом рассчитан результат всего выражения с помощью опе- ратора & . Однако, если выражение a < b даёт результат false , то фактически уже известен конечный результат всего выражения. Укороченные операторы учитывают это обстоятельство и в этом случае не рассчитывают выражение c > d Как правило, полные логические операторы используются в том случае, если второй и последующие операторы сложного выражения меняют значения перемен- ных. Укороченные операторы могут использоваться для гарантированной блокиров- ки выполнения действий, которые могут привести к ошибке. Например, пусть тре- буется определить, делится ли значение переменной n нацело на значение перемен- ной m . Это можно выполнить с помощью условия if (n%m == 0){...} Но в случае равенства m нулю при выполнении проверки возникнет ошибка. Её можно предотвратить используя два оператора if if (m != 0) if (n%m == 0){...} или используя один оператора if с укороченным логическим «И» if (m != 0 && n%m == 0){...} Использование полного логического «И» недопустимо, т.к. в этом случае при m=0 выражение n%m == 0 все равно будет вычисляться и в нем произойдёт ошибка. 2.7 Условный оператор ? : Если для расчёта значения некоторой переменной требуется применение условного оператора if в виде if (a) r = b; else r = c; , то целесообразно 22 применять условный оператор ? : , так как при этом упрощается запись кода и его результат можно применять в качестве операнда более сложных выражений. Структура условного оператора имеет вид: <логическое значение> ? <выражение если истина> : <выражение если ложь>; В качестве <логическое значение> могут выступать логические перемен- ные, логические константы или выражения, дающее логическое значение. <выражение если истина> и <выражение если ложь> должны давать одинаковый тип результата. Результат работы оператора должен быть присвоен некоторой переменной или являться частью более сложного выражения. Пример 1: найти минимум из двух целочисленных переменных a , b и сохра- нить его в переменную min min = a < b ? a : b; // Это аналог if (a < b) min = a; else min = b; Пример 2: найти максимум из двух целочисленных переменных a , b и сохра- нить его удвоенное значение в переменную max max = 2*(a > b ? a : b); // Это аналог if (a > b) max = 2*a; else max = 2*b; 2.8 Оператор выбора switch и оператор прерывания break Если требуется выполнить разветвление выполнения программы более чем на два направления, то возможно применение либо нескольких вложенных операторов if , либо оператора выбора switch Формальное описание оператора switch имеет вид: switch (<значение switch>) { case <значение 1>: <операторы 1> break; [case <значение 2>: <операторы 2> break; ...] [default: <операторы default> break;] } <значение switch> должно быть переменной или выражением целого, строкового, символьного, перечисляемого, логического типа. <значение N> долж- ны быть значениями такого же типа. <значение N> должны быть уникальными. 23 Пример: int n; string s; n = ???; switch (n) { case 1: s = "n=1"; break; case 2: s = "n=2"; break; default: s = "n<1 или n>2"; break; } При выполнении оператора ищется <значение N> , равное <значение switch> . Если такое значение найдено, то выполняется соответствующий блок case . Если значение не найдено, то: при наличии блока default выполняется этот блок; при отсутствии блока default никаких действий не производится. Каждый блок case и блок default должны заканчиваться оператором break , которые прерывает дальнейшее выполнение оператора switch . Исключением явля- ется ситуация, когда блок case не имеет операторов. Такое решение применяется, когда требуется, чтобы для нескольких значений выполнялись одни и те же дей- ствия, например: int n; string s; n = ???; switch (n) { case 1: case 2: s = "n=1 или n=2"; break; default: s = "n<1 или n>2"; break; } Вместо оператора break может располагаться оператор goto case , позволяющий перейти к блоку со значением Пример: рассчитать процент скидки, если при покупке одного товара скидки нет, при покупке двух товаров – скидка 2%, трёх – 5%, четырёх и более – 10%. int n; // Количество товаров int c; // Процент скидки 24 n = ???; switch (n) { case 1: c = 0; break; case 2: c = 2; break; case 3: c = 5; break; default: c = 10; break; } 2.9 Оператор цикла for Предназначен для реализации итерационных алгоритмов. Формальная струк- тура оператора имеет вид: for ([<инициализация>]; [<условие>]; [<итерация>]) [<оператор>]; <инициализация> представляет собой операторы, подготавливающие цикл к работе. Они выполняются один раз до начала работы цикла. Как правило в этих опе- раторах задаются начальные значения «параметров цикла». <условие> определяет условие выхода из цикла и его результатом должно быть логическое значение. <условие> проверяется перед каждой итерацией цикла, поэтому тело цикла может не выполниться ни разу. Выход из цикла производится, если <условие> имеет значение false. Как правило, <условие> должно зависеть от «параметра цикла». <итерация> определяет действия, выполняемые после каждой итерации цик- ла. Как правило, в них производится изменение «параметров цикла», причём изме- нение может осуществляться произвольным образом как в сторону увеличения, так и в сторону уменьшения. <оператор> представляет собой одиночный оператор, выполняемый на каж- дой итерации цикла. Если в цикле необходимо выполнять несколько операторов, то используются операторные скобки. Пример: рассчитать факториал числа n. int n; n = ???; int f = 1; for (int i=2; i<=n; i++) f *= i; 25 <инициализация> и <итерация> могут выполнять более одного оператора. В этом случае операторы разделяются запятой. Предыдущий пример может быть за- писан следующим образом: int n,i,f; n = ???; for (i=2, f=1; i<=n; f *= i, i++); Приведённый выше фрагмент показывает, что тело цикла может быть пустым. Также пустыми могут быть <инициализация> , <условие> , <итерация> . Напри- мер, предыдущий пример может быть записан так: int n; n = ???; int f = 1; int i = 2; for (; i<=n; ) f *= i++; Несмотря на то, что в блоках <инициализация> и <итерация> имеется воз- можность выполнять несколько операторов, при этом оставляя тело цикла пустым, злоупотреблять этим не следует. 2.10 Оператор цикла while Оператор цикла while фактически представляет собой оператор цикла for , у которого не заданы <инициализация> и <итерация> . Формальная структура дан- ного оператора имеет вид: while (<условие>) <оператор>; Как и в цикле for , <условие> определяет условие выхода из цикла и его ре- зультатом должно быть логическое значение. <условие> проверяется перед каждой итерацией цикла, поэтому тело цикла может не выполниться ни разу. Выход из цик- ла производится, если <условие> имеет значение false. <оператор> представляет собой одиночный оператор, выполняемый на каж- дой итерации цикла. Если в цикле необходимо выполнять несколько операторов, то используются операторные скобки. Пример: рассчитать факториал числа n. int n; n = ???; int i = 1; int f = 1; while (++i <= n) f *= i; 26 2.11 Оператор цикла do...while Формальная структура данного оператора имеет вид: do <оператор> while (<условие>); Как и в предыдущих операторах цикла, <условие> определяет условие выхо- да из цикла и его результатом должно быть логическое значение. Однако, <условие> проверяется после каждой итерации цикла, поэтому тело цикла выпол- няется как минимум один раз. Выход из цикла производится, если <условие> имеет значение false. <оператор> представляет собой одиночный оператор, выполняемый на каж- дой итерации цикла. Если в цикле необходимо выполнять несколько операторов, то используются операторные скобки. Пример: рассчитать факториал числа n. int n; n = ???; int i = 1; int f = 1; do f *= i++; while (i <= n); 2.12 Операторы прерываний break (для циклов) и continue Оператор break , используемый в операторе switch , также может применять- ся в циклах для их немедленного прерывания. При его использовании управление передаются оператору, следующему за циклом. При этом, если имеется ряд вложен- ных циклов, то оператор break прерывает только тот цикл, в теле которого он находится. Пример: найти наименьший делитель числа n, больший 1: int n; n = ???; int i; for (i=2; i<=n; i++) if (n%i == 0) break; Оператор continue используется для прерывания текущей итерации цикла и перехода к следующей (применяется довольно редко, т.к. как правило имеются бо- лее удобные способы написания требуемого кода). При использовании в теле оператора for управление передаётся в блок <итерация> , после чего цикл продолжает работать по обычной схеме. 27 При использовании в теле операторов while и do...while управление пере- даётся в блок <условие> , после чего циклы продолжает работать по обычной схеме. 2.13 Оператор new Оператор new используется для создания объектов и вызова конструкторов. При создании объектов для них выделяется память, а также вызывается конструктор по умолчанию 1 , который инициализирует члены объектов значением по умолчанию. Например, две ниже приведённые строки приводят к одному результату – созданию переменной i со значением 0, т.к. конструктор по умолчанию типа int присваивает объекту значение 0: int i=0; int i = new int(); Значения по умолчанию для всех числовых типов имеют значение 0, для сим- волов – пустой символ, для строки – null , для логического типа – false 2.14 Массивы Массив представляет собой совокупность переменных одного типа с общим для обращения к ним именем. В языке С# массивы могут быть как одномерными, так и многомерными, хотя чаще всего применяются одномерные массивы. Массивы служат самым разным целям, поскольку они предоставляют удобные средства объ- единения связанных вместе переменных. Главное преимущество массива – в организации данных таким образом, чтобы ими было проще манипулировать. Как правило, обработка массива реализуется пу- тём циклического обращения к его элементам. При создании массива, всем его элементам присваивается значение 0. 2.14.1 Одномерные массивы Для того чтобы воспользоваться массивом в программе, требуется двухэтап- ная процедура, поскольку в С# массивы реализованы в виде объектов. Во-первых, необходимо объявить переменную, которая может обращаться к массиву. И во- вторых, нужно создать экземпляр массива, используя оператор new . Для объявления одномерного массива обычно применяется следующая общая форма: <тип>[] <идентификатор> = new <тип>[<размер>]; 1 Если при создании объекта указываются дополнительные параметры, то вызывается соответствующий им конструктор. 28 хотя возможно разделение данной строки на две части 1 : <тип>[] <идентификатор>; <идентификатор> = new <тип>[<размер>]; Пример обычного объявления целочисленного массива, состоящего из 10 эле- ментов: int[] mas = new int[10]; Нумерация элементов массива всегда начинается с нуля, поэтому в приведён- ном выше примере доступны элементы массива с индексами в диапазоне 0÷9. Для обращения к элементу массива требуется указать идентификатор массива, после которого в квадратных скобках указать индекс требуемого элемента, напри- мер, присвоение последнему элементу массива mas из приведённого выше примера значения 25 будет записано как: mas[9] = 25; При объявлении массива возможна его инициализация. В этом случае, в ко- манде объявления массива не требуется указания размера массива, так как он вы- числяется по количеству введённых значений инициализации. Формально строка объявления с инициализацией имеет вид: <тип>[] <идентификатор> = {<значение 1> [, <значение 2> ...]}; <значение 1> [, <значение 2> ... должны быть совместимы с <тип> Пример: int[] mas = {7,12,3,14,65}; Также допустимым (хотя и излишним) является использование при инициали- зации оператора new, например: int[] mas = new int[5] {7,12,3,14,65}; Однако в этом случае размер массива должен совпадать с количеством значений инициализации. 2.14.2 Многомерные массивы Многомерные массивы отличаются использованием более одной размерности во всех операциях. При этом, размерности отделяются друг от друга запятой. Фор- мальное описание многомерного массива может быть задано строкой 1 Такое разделение во многих случаях бессмысленно, т.к. до указания размера воспользоваться переменной не будет возможности, а объявить переменную можно в любом месте программы. 29 <тип>[,[, ...]] <идентификатор> = new <тип>[<размер 1>,<размер 2>[,<размер 3> ...]]; например, приведённый ниже фрагмент создаёт трёхмерный массив и присваивает одному из элементов значение 999 int[,,] mas = new int[3,4,5]; mas[1,2,3] = 999; Количество элементов в многомерном массиве, созданном таким способом, определяется как произведение количеств элементов в каждой размерности (для приведённого выше примера: 3*4*5 → 60). Многомерные массивы также могут быть инициализированы при создании. При этом, значения инициализации для каждой размерности заключаются в фигур- ные скобки. Например, строка int[,,] mas = {{{1,2},{3,4},{5,6}},{{7,8},{9,10},{11,12}}}; инициализирует трёхмерный массив, имеющий размер размерностей 2,3,2. 1>1> |