Таблица 1

Операция

Назначение

Пример

+

*

/

%

++

– –

Сложение

Вычитание

Умножение

Деление

Деление по модулю

Инкремент

Декремент

X = X + y;

X = x – y;

Z = x * y;

Z = x / y;

Z = t % e;

Z++;

Z – – ;

Смысл и суть операций сложения, вычитания и умножения пояснений не требует. Эти операции возможны и с целыми, и с вещественными числами. А вот операция деления имеет особенность. Результат этой операции зависит от типа используемых данных. При делении вещественных чисел – результат вещественный. Если же делятся целые, то и результатом будет целое число.

Например:

int a = 15, b = 6, c;

double d = 15.0, e = 6.0, f;

c = a / b; // c = 2

f = d / e; // f = 2.5;

Деление по модулю возможно только для целых чисел. Результат операции – это остаток от деления первого операнда на второй. Например:

int a = 15, b = 6, c;

c = a % b; // c = 3

Используя совместно операции / и %, можно получать целую часть при делении и остаток от деления.

Существует сокращенная форма записи оператора присваивания при использовании арифметических операций. Арифметические операции можно объединять вместе с операцией присваивания, записывая две операции в виде одной. Например:

обычная запись: a = a + Stoim;

сокращенная форма: a += Stoim;

Сокращенная форма записи пришла в C# из C++. Также по наследству достались языку C# и две следующие операции – инкремент и декремент. Инкремент увеличивает значение переменной на 1, а декремент уменьшает значение на 1. Фактически эти операции являются сокращенной формой записи для выражений типа i = i + 1 и i = i – 1. Например, вместо a = a + 1 можно записать a++.

НЕ нашли? Не то? Что вы ищете?

Различают два варианта записи этих операций – постфиксный и префиксный. В первом варианте знак операции ставится после переменной, во втором – перед ней. Когда эти варианты используются в выражении, то при постфиксном варианте значение переменной сначала используется, а потом изменяется на 1. При префиксном, наоборот, сначала изменяется, а потом используется. Например:

t = 5; // t = 5

n = 4 * t++; // n = 20, t = 6

k = ++n / 3; // n = 21, k = 7

b = --k / t; // k = 6, b = 1

4.5. ПОРАЗРЯДНЫЕ ОПЕРАЦИИ

В C# имеются операции, пригодные для обработки отдельных битов памяти (например, в видеопамяти графического дисплея). Такие операции называются поразрядными (операции с битами). Они позволяют изменять, считывать и сдвигать разряды в переменных. При этом переменная рассматривается не как число, а как комбинация двоичных разрядов, т. е. как логический код. Операция выполняется отдельно над каждым разрядом значения переменной. В качестве операндов могут использоваться только целые числа. Операции приведены в табл. 2.

Таблица 2

Операция

Назначение

Пример

&

|

^

~

<< 

>> 

Поразрядное И

Поразрядное ИЛИ

Поразрядное Исключающее ИЛИ

Поразрядное НЕ

Поразрядный сдвиг влево

Поразрядный сдвиг вправо

i & 16

i | 12

k ^ 10

~a

<< 2

>> 2

Пример 1

int k = 26; // двоичное представление

k & 15 // 15 – это

// результат двоичное , т. е. десятичное 10

k | 15 // результат двоичное , т. е. десятичное 31

k ^ 15 // результат двоичное , т. е. десятичное 21

k << 2 // результат двоичное , т. е. десятичное 104

k >> 2 // результат двоичное , т. е. десятичное 6

Пример 2. Необходимо выделить значение пятого бита в байте B, а остальные обнулить. Учитывая, что биты нумеруются слева направо, начиная с 0, то следующий оператор оставляет без изменения значение пятого бита в самом правом (младшем) байте целого числа:

В = (B & 4);

4.6. ПРЕОБРАЗОВАНИЕ ТИПОВ

При выполнении различных операций среда программирования контролирует правильность описания операций с данными. Как правило, допускаются операции с однотипными данными. Например, при сложении целого и вещественного числа необходимо оба числа представить в виде чисел одного типа: или целого, или вещественного – в зависимости от требуемого результата. Значит, перед операцией сложения у одного из чисел надо изменить тип, т. е. формат представления (вспомним, что целые числа представлены обычным двоичным кодом, а вещественные – в логарифмическом формате).

Для изменения типа можно использовать операцию приведение к типу, применяемую для преобразования значения одного типа в значение другого типа. Это так называемое явное преобразование типов. Операция задается указанием имени типа в круглых скобках. Рассмотрим пример.

int n = 10;

double z;

z = n;

n = (int) z;

В данном примере объявлены две переменные, причем целочисленной уже присвоено значение. После присваивания значением z будет число 10.0 – такое преобразование выполнится неявно автоматически (неявное преобразование типов), и несогласования типов не будет. А вот обратное преобразование надо задавать явно.

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

В разделе 4.3 мы видели, как введенные с клавиатуры строковые значения преобразуются в численные или символьные значения с помощью методов класса Convert. Те же методы можно использовать для преобразования не только введенных, но и любых строковых значений. Есть определенная сложность преобразования арифметических типов в строки, потому что не существует явного или неявного преобразования арифметических типов в строки, т. е. операция «приведение к типу» здесь невозможна. Однако в классе Object имеется метод ToString. Так как все арифметические типы данных считаются потомками (наследниками) класса Object, то для них предусмотрена соответствующая реализация этого метода. Следовательно, метод ToString можно использовать, когда некоторое арифметическое значение надо преобразовать в строку. Например:

string s;

int n = 2014;

s = ”Год “+ToString(n); // результат: Год 2014

5. ПРОСТЕЙШИЕ ОПЕРАТОРЫ ЯЗЫКА C#

5.1. ОПЕРАТОР ПРИСВАИВАНИЯ

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

Переменная-объект = Выражение;

Например, полную поверхность цилиндра можно вычислить с помощью оператора:

Volume = Math. Atan(1.0) * 8 * Radius * (Radius + Vysota);

В качестве переменной может выступать идентификатор любого типа, предварительно объявленный в программе как переменная (идентификатор может иметь и другой смысл, например, быть именем функции). Выражение может быть составлено с помощью различных операций (в примере использованы знаки + и *), явно заданных чисел (в примере – число 8), других идентификаторов переменных (в примере – Radius и Vysota), вызовов методов (в примере – Math.Atan). Обязательно только одно: типы переменной и выражения должны быть согласованы. В нашем примере это значит, что переменная Volume должна быть объявлена как переменная типа double. Оператор присваивания обязательно заканчивается знаком «точка с запятой».

Одно замечание по согласованию типов. Число 8 задано как целое. Оно умножается на вещественный результат выполнения функции arctg(1). Такая запись будет принята компилятором, который сам приведет тип числа 8 к вещественному типу (неявное преобразование типа). Отметим также, что значения в переменных Radius и Vysota могут быть и вещественными, и целыми. В последнем случае также будет выполнено неявное преобразование.

5.2. ВЫЗОВ МЕТОДА

И этот оператор мы уже использовали в предыдущих разделах. Структура вызова метода описывается так:

Область_нахождения_метода. имя метода

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

System.Console.ReadLine()

Вспомним, что имя класса Console можно опускать, потому что в начале программы обычно указывается директива using System;

Вызов метода для исполнения может использоваться в программе в двух смыслах. Если вызов записан в составе выражения, то вызов метода выступает в виде операнда, а сам метод по своей сути является функцией, дающей некоторый результат (подробнее о функциях – в разделе 13). Результат выполнения метода сразу же используется при вычислении выражения. Если же метод выполняет какие-либо действия, но не формирует непосредственно используемого результата, то он, по сути, является процедурой и описывается в виде оператора. Такая запись завершается знаком «точка с запятой». Например:

S = System.Console.ReadLine(); // вызов используется как операнд при // присваивании

Console.WriteLine(“Привет волку!”); // вызов записан как оператор

5.3. СОСТАВНОЙ ОПЕРАТОР

Составной оператор (другое название – блок) воспринимается компилятором как один оператор. Используется там, где по смыслу должен быть именно единичный оператор. Блок описывается с помощью фигурных скобок. Один или несколько любых операторов можно заключить в фигурные скобки – получится составной оператор. Структура этого оператора:

{

оператор_1

...

оператор_N

}

Обратите внимание: составной оператор не заканчивается знаком «точка с запятой». В состав одного блока могут включаться другие блоки. Пример записи блока:

{

int i, j;

string s;

s = Console. ReadLine();

}

Есть один нюанс, связанный с объявлением переменных. Те переменные, которые объявлены в блоке, можно использовать только в этом блоке. За пределами блока они не существуют. Например:

{int k;

k = 10; // законный оператор

}

k = 12; // незаконный оператор

6.  ОПЕРАТОРЫ ВЕТВЛЕНИЯ

Выполнение операторов ветвления основано на использовании двух групп операций: операций отношения и логических операций. Рассмотрим их по порядку.

6.1. ОПЕРАЦИИ ОТНОШЕНИЯ

Эти операции используются для сравнения значений переменных или выражений. Результатом операций является значение булевого типа: ИСТИНА (true) или ЛОЖЬ (false). Численных эквивалентов для этих значений в языке C# не существует. Перечень операций приведен в табл. 3. Все операции бинарные, т. е. имеют два операнда.

Таблица 3

Операция

Назначение

Пример

= =

! =

>=

<=

Равно

Не равно

Больше, чем

Меньше, чем

Больше или равно

Меньше или равно

I = = 0

K!= 15

Z > 15.2

Tab < -132.654

Z11 >= 0

Y2 <= 10

При выполнении операций сравнения следует помнить одну специфическую особенность. Точное сравнение вещественных чисел возможно только с нулем. Сравнение ненулевых вещественных чисел, полученных путем вычислений, возможно только с определенной точностью. Это связано с формой представления вещественных чисел (логарифмический формат). А вот числа типа Decimal (см. [1]) можно сравнивать между собой на равно.

6.2. ЛОГИЧЕСКИЕ ОПЕРАЦИИ

Логические операции нужны для составления логических (булевых) выражений. Значением булевого выражения может быть ИСТИНА и ЛОЖЬ. В булевом выражении в качестве операнда может использоваться или булева переменная, или выражение со знаком операции сравнения. Перечень операций приведен в табл. 4.

Таблица 4

Операция

Назначение

Пример

&&

||

!

Логическое И

Логическое ИЛИ Логическое НЕ

( R > 2 ) && ( R < 20 )

( L= = 12 ) || ( L > 15 )

! Tab

6.3. ОПЕРАТОР if

Оператор if используется для описания ветвлений алгоритма в зависимости от полученного результата. Оператор обеспечивает ветвление по одному из двух направлений. Синтаксис оператора:

if (выражение_1) оператор_1

else оператор_2

Выражение в круглых скобках должно быть булевого типа, т. е. может быть составлено с помощью операций сравнения и логических операций. Точнее, при вычислении выражения должны получаться значения true или false. Оператор может иметь две ветви: ветвь if (если) и ветвь else (иначе). Каждая ветвь содержит один оператор. Каждый из операторов (оператор_1 и оператор_2) может быть любым оператором (присваивания, составной оператор, другой оператор ветвления и др.). Какая именно ветвь (то есть какой из операторов) будет исполняться, зависит от значения выражения в круглых скобках (выражение_1). Выполняется ветвь if, если значение выражения есть true. Наоборот, если значение выражения есть false, то выполняется ветвь else. Пример записи оператора:

if (k % 7 == 0)

{Console.WriteLine("Число делится на 7 нацело"); m = 1;}

else Console.WriteLine("Число не делится на 7");

В данном примере ветвь if содержит составной оператор, ветвь else – опреатор вывода на экран. Если число в переменной k при делении на 7 дает в остатке 0 (т. е. делится на 7 нацело), то выполняется составной оператор. В противном случае – оператор вывода.

Разрешается не описывать ветвь else, т. е. использовать только ветвь if.

6.4. ОПЕРАТОР switch

Часто бывают ситуации, когда алгоритм разветвляется не на два варианта, а на три и более. Такие ветвления обычно определяются значением некоторого выражения, а само выражение может принимать различные значения в зависимости от исполнения программы. Такую ситуацию можно описать с помощью нескольких операторов if, записанных подряд, но тогда выражение придется повторять в каждом условии. Да и читать (а тем более понимать) такой текст будет некомфортно. Более наглядным будет описание, если вместо if использовать оператор switch (переключатель), предназначенный именно для таких случаев. Оператор имеет следующий вид:

switch (выражение)

{

case константа_1: операторы_1 оператор_перехода_1

...

case константа_K: операторы_K оператор_перехода_K

default: операторы_N оператор_перехода_N

}

При использовании оператора надо помнить, что константы в каждой ветви case (вариант) должны иметь тот же тип, что и значение выражения в круглых скобках. Допускается использовать целочисленный и символьный тип.

Оператор выполняется следующим образом. Сначала вычисляется значение выражения в круглых скобках. Это значение поочередно в порядке следования case сравнивается на совпадение с константами. Выполняются операторы той ветви case, константа которой совпадает с вычисленным значением. Поскольку последний оператор этой последовательности является оператором перехода (чаще всего это оператор break, см. раздел 8), то обычно он завершает выполнение оператора switch. Если вычисленное значение выражения не совпадает ни с одной константой, то выполняется последовательность операторов ветви default (в противном случае – по умолчанию).

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

Ниже приведен пример, в котором оператор switch используется для организации выдачи на экран нескольких сообщений в зависимости от значения вычисленного выражения. Значением выражения является последняя цифра в целом числе. В зависимости от значения этой цифры на экран выдается ее текстовое название.

switch (m % 10)

{ case 0: Console. WriteLine(”ноль”); break;

case 1: Console. WriteLine(”один”); break;

case 2: Console. WriteLine(”два”); break;

case 3: Console. WriteLine(”три”); break;

case 4: Console. WriteLine(”четыре”); break;

case 5: Console. WriteLine(”пять”); break;

case 6: Console. WriteLine(”шесть”); break;

case 7: Console. WriteLine(”семь”); break;

case 8: Console. WriteLine(”восемь”); break;

case 9: Console. WriteLine(”девять”); break;

default: break;

}

Ветвь default в этом примере можно было бы не использовать вообще, потому что все возможные значения выражения учтены в ветвях case.

7.  ОПЕРАТОРЫ ОРГАНИЗАЦИИ ЦИКЛА

Операторы организации цикла обеспечивают запись тех участков программного кода, где реализуются циклические алгоритмы. К таким операторам относятся операторы общего назначения for и while, а также оператор foreach, ориентированный на циклический перебор элементов массива. Оператор foreach рассмотрен в разделе 10.

7.1. ОПЕРАТОР for

Данный оператор чаще всего используют при описании цикла. Его достоинство в том, что его заголовок содержит полное описание характеристик цикла.

Синтаксис оператора:

for (инициализаторы; условие; список_выражений)

оператор

Оператор, стоящий после круглой закрывающей скобки, задает тело цикла. В большинстве случаев телом цикла является блок (составной оператор), но может быть и любой одиночный оператор. Сколько раз будет выполняться тело цикла, зависит от трех управляющих элементов, заданных в круглых скобках. Инициализаторы задают начальное значение одной или нескольких переменных, часто называемых счетчиками или просто переменными цикла. В большинстве случаев цикл for имеет один счетчик, но иногда бывает полезно иметь несколько счетчиков. Значение условия определяет: должен продолжаться цикл или должен завершиться. Если значение условия true, то цикл продолжается (то есть выполняется оператор тела цикла). Если false, то цикл завершается. Список_выражений, записанных через запятую, показывает, как меняются счетчики цикла на каждом шаге выполнения.

Выполнение оператора начинается с вычислений, описанных в поле инициализаторов. Затем вычисляется условие. Если условие цикла истинно, то один раз выполняется тело цикла – одиночный оператор или составной. После выполнения оператора вычисляются значения выражений из списка выражений и вновь вычисляется значение условия. Если условие истинно, то вновь выполняется оператор. И так далее. Как только условие становится ложным, цикл завершается.

С помощью оператора for описывают циклы с предусловием. Тело цикла может ни разу не выполниться, если условие цикла ложно после инициализации, а может происходить зацикливание (бесконечный цикл), если условие всегда остается истинным. Счетчики цикла часто объявляются непосредственно в инициализаторе и, соответственно, являются переменными, локализованными в цикле, так что после завершения цикла они перестают существовать.

Рассмотрим пример записи оператора – вычисление факториала натурального числа:

for (int i = 1, r = 1; i <= n; i++)

r = r * i;

В этом примере поле инициализации содержит два выражения. Первое является объявлением переменной i с присваиванием ей значения. Эта переменная может использоваться только внутри цикла – за пределами цикла она не существует. Второе выражение присваивает значение переменной r, но эта переменная объявлена где-то до цикла и не локализована в нем, т. е. может использоваться и после цикла. Тело цикла состоит из единичного оператора, который и выполняется, пока истинно условие i<=n. Переменная i является переменной (счетчиком) цикла и увеличивается при исполнении цикла. Переменная n играет роль ограничителя цикла. Как только значение i становится больше n, цикл завершается.

Оператор for можно использовать для организации бесконечного цикла. Для этого поле условия достаточно оставить пустым. Отсутствие условия означает постоянную истину, то есть как будто значением условия является истина. Это и обеспечивает то, что тело цикла выполняется бесконечно. На первый взгляд, такое (бесконечное) исполнение бессмысленно, но это не так. Могут быть случаи, когда в заголовке цикла невозможно явно записать условие продолжения цикла – эти приходится анализировать в теле цикла. Примеры особой организации циклов рассмотрены в разделе 8.

7.2. ОПЕРАТОР while

Цикл while является универсальным оператором цикла, включаемым во все языки программирования. Тело цикла выполняется до тех пор, пока остается истинным выражение, указанное в круглых скобках после имени оператора. В языке C# у этого вида цикла две модификации – с проверкой условия в начале цикла (цикл с предусловием) и в конце цикла (цикл с постусловием).

Первая модификация имеет следующий синтаксис:

while (выражение) оператор

Эта модификация соответствует стратегии: "сначала проверь, а потом делай". В результате проверки может оказаться, что делать ничего не нужно, и в этом смысле оператор похож на оператор for. Тело такого цикла может ни разу не выполниться. В нормальной ситуации каждое выполнение тела цикла – это очередной шаг к завершению цикла. С помощью этого вида цикла пример, рассмотренный в предыдущем разделе, можно записать так:

i = 1; r = 1;

while (i <= n)

{r = r * i; i++;}

Вторая модификация этого оператора соответствует стратегии: "сначала сделай, а потом проверь". Синтаксис этой модификации имеет вид:

do

оператор

while (выражение);

Тело такого цикла выполняется, по меньшей мере, один раз. Пример записи цикла – то же вычисление факториала:

i =1; r = 1;

do {r = r * i; i++;} while (i <=n);

8. ОПЕРАТОРЫ ПЕРЕХОДА

Обычно операторы программы выполняются естественно, т. е. в порядке записи («сверху вниз»). Назначение операторов перехода состоит в том, чтобы изменить естественный порядок выполнения программы. К числу таких операторов относятся:

goto – прямой переход к помеченному оператору (как вверх, так и вниз);

break – прерывание выполнения текущего оператора;

continue – прерывание текущего шага цикла и переход к выполнению следующего шага;

return – завершение выполнения текущей функции и возврат в точку вызова.

Остановимся подробно на трех первых операторах. Оператор return будет рассмотрен в разделе 13.

8.1. ОПЕРАТОР goto

Сразу же следует отметить, что использование этого оператора не рекомендуется. В принципе он допустим, так как достался языку C# в наследство от языка C. Однако его использование не соответствует современному стилю программирования и делает запутанной логику программы.

Оператор goto имеет три варианта записи.

goto метка;

goto case константа;

goto default;

Первый вариант основан на следующем соображении. Все операторы языка C# могут иметь метку – уникальный идентификатор, предшествующий оператору и отделенный от него символом двоеточия. Например:

nachalo: for (i = 0; i <n; i++)

{ … }

Переход к помеченному оператору – это классическое использование оператора. В нашем случае это достигается оператором:

goto nachalo;

Два других варианта используются только внутри оператора switch. В конце ветви case вместо оператора break можно написать goto с указанием константы. В этом случае после завершения текущей ветви case будет выполнена другая ветвь case, в которой указана названная константа. При выполнении оператора

goto default;

произойдет переход на ветвь default.

8.2. ОПЕРАТОРЫ break И continue

Хорошим стилем программирования является стиль, при котором используются переходы вперед (но не назад), позволяющие при выполнении некоторого условия выйти из цикла или из оператора ветвления switch и перейти к выполнению следующего по порядку оператора. Для этой цели можно использовать и оператор goto, но лучше применять специально предназначенные для этих целей операторы break и continue.

Оператор break может стоять в теле цикла или завершать case-ветвь в операторе switch. При выполнении оператора break в теле цикла заканчивается выполнение цикла. Если имеется несколько вложенных циклов (цикл в цикле), то завершается только тот цикл, в теле которого размещен break. Когда организован бесконечный цикл с помощью оператора for, то для его завершения внутрь тела цикла можно включить break. Чаще всего оператор break помещается в одну из ветвей оператора if, проверяющего условие преждевременного завершения цикла. Например:

for (; ;)

{ ...

Сonsole. Write("Завершаем работу? (Y, N)");

temp = Console. ReadLine();

otv = Convert. ToChar (temp);

if (otv == 'Y' || otv == 'y ') break;

}

Оператор continue используется только в теле цикла. В отличие от оператора break, завершающего цикл, continue не прерывает цикл, а осуществляет переход к следующему шагу цикла.

Рассмотрим пример – вычисление значений функции на интервале от -10 до +10:

for (int X = –10; X < 11; X++)

{if (X > – 3 && X < 3) continue;

Y = Math. Sqrt(Math. Pow(X, 2) – 9);

Console. WriteLine(“Y = {0} при значении X = {1}”, Y, X);

}

Здесь для вычисления квадрата числа используется метод Pow из класса Math. Квадратный корень извлекается методом Sqrt. Однако, если значение аргумента принадлежит отрезку [-2, 2], то значение функции не существует. В этом случае работает оператор continue, обеспечивающий завершение текущего шага цикла и переход к следующему шагу.

9. ПОНЯТИЕ ИСКЛЮЧЕНИЯ

В разделе 4.3 мы отметили, что при вводе численных значений с клавиатуры необходимо воспользоваться методами преобразования строки в число. Например, в классе Convert имеется метод ToDouble, позволяющий преобразовать введенную строку цифровых символов в вещественное число. Тем же методом можно воспользоваться, когда требуется сделать аналогичное преобразование для строки, полученной в процессе выполнения программы.

Предположим, что переменная S типа string содержит строковое значение -58.456. Тогда следующий оператор выполнит нужное преобразование (полагаем, что переменная D имеет тип double):

D = Convert.ToDouble(S);

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6