|
Ответы на экзамен по программированию. Алфавит С# включает
С# — объектно-ориентированный язык, поэтому написанная на нем программа представляет собой совокупность взаимодействующих между собой классов. Все тексты на языке пишутся с помощью его алфавита. Например, в русском языке один алфавит (набор символов), а в албанском — другой. В С# используется кодировка символов Unicode. Давайте разберемся, что это такое.
Компьютер умеет работать только с числами, и для того чтобы можно было хранить в его памяти текст, требуется определить, каким числом будет представляться (кодироваться) каждый символ. Соответствие между символами и кодирующими их числами называется кодировкой, или кодовой таблицей (character set).
Существует множество различных кодировок символов. Например, в Windows часто используется кодировка ANSI, а конкретно — СР1251. Каждый символ представляется в ней одним байтом (8 бит), поэтому в этой кодировке можно одновременно задать только 256 символов. В первой половине кодовой таблицы находятся латинские буквы, цифры, знаки арифметических операций и другие распространенные символы. Вторую половину занимают символы русского алфа
Состав языка 23
вита. Если требуется представлять символы другого национального алфавита (например, албанского), необходимо использовать другую кодовую таблицу.
Кодировка Unicode позволяет представить символы всех существующих алфавитов одновременно, что коренным образом улучшает переносимость текстов. Каждому символу соответствует свой уникальный код. Естественно, что при этом для хранения каждого символа требуется больше памяти. Первые 128 Unicode символов соответствуют первой части кодовой таблицы ANSI.
Алфавит С# включает:
• буквы (латинские и национальных алфавитов) и символ подчеркивания (_), который употребляется наряду с буквами;
• цифры;
• специальные символы, например +, *, { и &;
• пробельные символы (пробел и символы табуляции);
• символы перевода строки.
Из символов составляются более крупные строительные блоки: лексемы, директивы препроцессора и комментарии.
Лексема (token1) —это минимальная единица языка, имеющая самостоятельный смысл. Существуют следующие виды лексем:
• имена {идентификаторы);
• ключевые слова;
• знаки операций;
• разделители;
• литералы (константы).
Оператор задает законченное описание некоторого действия, данных или элемента программы. Например:
int а:
Это — оператор описания целочисленной переменной а.
Выражения
Выражение — это правило вычисления значения. В выражении участвуют one ранды, объединенные знаками операций. Операндами простейшего выражение могут быть константы, переменные и вызовы функций. Например, а + 2 — это выражение, в котором + является знаком операции, а а и 2 операндами. Пробелы внутри знака операции, состоящей из нескольких символов, не допускаются.
шые, с которыми работает программа, хранятся в оперативной памяти. Естеенно, что компилятору необходимо точно знать, сколько места они занимают, : именно закодированы и какие действия с ними можно выполнять. Все это ается при описании данных с помощью типа. г данных однозначно определяет:
внутреннее представление данных, а следовательно, и множество их возможных значений; допустимые действия над данными (операции и функции).
пример, целые и вещественные числа, даже если они занимают одинаковый ьем памяти, имеют совершенно разные диапазоны возможных значений; целые ела можно умножать друг на друга, а, например, символы — нельзя.
ждое выражение в программе имеет определенный тип. Величин, не имеющих какого типа, не существует. Компилятор использует информацию о типе при оверке допустимости описанных в программе действий.
программа Z# состоит из классов, внутри которых описывают методы и данные.
//Подключение пространства имен System
using System;
//Объявление пространства имен
namespace ProgramStructure
{
//Объявление класса
class Program
{
//Главный метод программы
static void Main(string[] args)
{
//Вывод строки
Console.WriteLine("Hello World!");
//Вспомогательный оператор
Console.ReadKey();
объявление пространства имен (своего рода контейнера);
объявление класса (основная сущность программы);
методы класса (подпрограммы), как минимум метод Main;
операторы и выражения;
комментарии.
2) Тип данных характеризует одновременно:
Типы данных - однозначно определяет:
внутреннее представление данных, а следовательно, и множество их возможных значений;
Типы можно разделить на простые и структурированные.
По своему «создателю» типы можно разделить на встроенные
(стандартные) и определяемые программистом (рис. 2.1). Для данных статического типа память выделяется в момент объявления, при этом ее требуемый объем известен. Для данных динамического типа размер данных в момент объявления может быть неизвестен, и память под них выделяется по запросу в процессе выполнения программы.
Встроенные типы Встроенные типы не требуют предварительного определения. Для каждого типа существует ключевое слово, которое используется при описании переменных, констант и т. д. Если же программист определяет собственный тип данных, он описывает его характеристики и сам дает ему имя, которое затем применяется точно так же, как имена стандартных типов.
множество допустимых значений, которые могут принимать данные, принадлежащие к этому типу;
набор операций, которые можно осуществлять над данными, принадлежащими к этому типу.
Целочисленные типы
Целочисленные типы содержат в себе значения, интерпретируемые как числа (знаковые и беззнаковые).
Логические, или булевы значения (по фамилии их изобретателя — Буля), могут иметь лишь одно из двух состояний — «истина» или «ложь». В разных языках обозначаются bool, BOOL, или boolean. «Истина» может обозначаться как true, TRUE или #T. «Ложь», соответственно, false, FALSE или #F
Символьный тип (Сhar) — простой тип данных, предназначенный для хранения одного символа (управляющего или печатного) в определённой кодировке. Может являться как однобайтовым (для стандартной таблицы символов), так и многобайтовым (к примеру, для Юникода). Основным применением является обращение к отдельным знакам строки.
Число с плавающей запятой (или число с плавающей точкой) — форма представления вещественных (действительных) чисел, в которой число хранится в форме мантиссы и показателя степени. При этом число с плавающей запятой имеет фиксированную относительную точность и изменяющуюся абсолютную. Используемое наиболее часто представление утверждено в стандарте IEEE 754. Реализация математических операций с числами с плавающей запятой в вычислительных системах может быть как аппаратная, так и программная.
3) Литералами, или константами, называют неизменяемые величины. В С# есть логические, целые, вещественные, символьные и строковые константы, а также константа null. Компилятор, выделив константу в качестве лексемы, относит ее к одному из типов данных по ее внешнему виду. Программист может задать тип константы и самостоятельно1.
Выражение — это правило вычисления значения.
Переменная — это именованная область памяти, предназначенная для хранения данных определенного типа. Во время выполнения программы значение переменной можно изменять. Все переменные, используемые в программе, дол быть описаны явным образом. При описании для каждой переменной задается ее имя и тип. переменной выбирается, исходя из диапазона и требуемой точности предвления данных.
Пример описания целой переменной с именем а и вещественной перемени
int а; float х;
Имя переменной служит для обращения к области памяти, в которой хранится значение переменной.
«Переменные, описанные внутри метода класса, называются локальными переменш. Их инициализация возлагается на программиста.
Так называемая область действия переменной, то есть область программы, г, можно использовать переменную, начинается в точке ее описания и длит< до конца блока, внутри которого она описана. Блок — это код, заключеннь в фигурные скобки. Основное назначение блока — группировка операторо В С# любая переменная описана внутри какого-либо блока: класса, метода ш блока внутри метода.
Имя переменной должно быть уникальным в области ее действия. Область де ствия распространяется на вложенные в метод блоки, из этого следует, что i вложенном блоке нельзя объявить переменную с таким же именем, что и в охв тывающем его, например:
Именованные константы
Можно запретить изменять значение переменной, задав при ее описании ключевое слово const, например:
const int b = 1; const float x = 0:1, у = 0.If: // const распространяется на обе переменные
Consol е. Writel_ine( i ) Consolе.WriteLine( у ) Console.Writel_ine( d ) Console.Writel_ine( s )
42 Глава 3. Переменные, операции и выражен!
Такие величины называют именованными константами, или просто констаь тами. Они применяются для того, чтобы вместо значений констант можно был использовать в программе их имена. Это делает программу более понятной и об легчает внесение в нее изменений, поскольку изменить значение достаточн только в одном месте программы.
ПРИМЕЧАНИЕ Улучшение читабельности происходит только при осмысленном выборе имен кон стант. В хорошо написанной программе вообще не должно встречаться иных 4ncej кроме 0 и 1, все остальные числа должны задаваться именованными константам] с именами, отражающими их назначение.
Именованные константы должны обязательно инициализироваться при описа нии. При инициализации можно использовать не только константу, но и выра жение — главное, чтобы оно было вычисляемым на этапе компиляции, например
const int b = 1. а = 100: const int х = b * а + 25:
В выражении участвуют oneранды, объединенные знаками операций. Операндами простейшего выражение могут быть константы, переменные и вызовы функций. Например, а + 2 — это выражение, в котором + является знаком операции, а а и 2 операндами. Пробелы внутри знака операции, состоящей из нескольких символов, не допускаются. По количеству участвующих в одной операции операндов операции делятся на унарные, бинарные и тернарную. Операции С#
Операции в выражении выполняются в определенном порядке в соответств] с приоритетами, как и в математике. В табл. 3.1 операции расположены по уб; ванию приоритетов, уровни приоритетов разделены в таблице горизонтальны? линиями.
Результат вычисления выражения характеризуется значением и типом. Напр мер, пусть а и b — переменные целого типа и описаны так:
int а = 2, b = 5;
Тогда выражение а + b имеет значение 7 и тип i nt, а выражение а = b имеет знач ние, равное помещенному в переменную а (в данному случае — 5), и тип, совп дающий с типом этой переменной.
Если в одном выражении соседствуют несколько операций одинакового пр оритета, операции присваивания и условная операция выполняются спра налево, остальные — слева направо. Для изменения порядка выполнения on раций используются круглые скобки, уровень их вложенности практически ограничен.
Например, а + b + с означает (а + Ь) + с, а а = b = с означает а = (Ь = с). То ее сначала вычисляется выражение b = с, а затем его результат становится правь операндом для операции присваивания переменной а.
Поразрядные логические операции Поразрядные логические операции (&, |, Л) применяются к целочисленным операндам и работают с их двоичными представлениями. При выполнении операций операнды сопоставляются побитно (первый бит первого операнда с первым битом второго, второй бит первого операнда со вторым битом второго и т. д.). Стандартные операции определены для типов int, ui nt, long и ulong.
При поразрядной конъюнкции, или поразрядном И (операция обозначается &), бит результата равен 1 только тогда, когда соответствующие биты обоих операндов равны 1.
При поразрядной дизъюнкции, или поразрядном ИЛИ (операция обозначается |), бит результата равен 1 тогда, когда соответствующий бит хотя бы одного из операндов равен 1. При поразрядном исключающем ИЛИ (операция обозначается А) бит результата равен 1 только тогда, когда соответствующий бит только одного из операндов равен 1.
Пример применения поразрядных логических операций представлен в листинге 3.6.
Условные логические операции Условные логические операции И (&&) и ИЛИ (11) чаще всего используются с oпeрандами логического типа. Результатом логической операции является true шп false. Операции вычисляются по сокращенной схеме.
Результат операции логическое И имеет значение true, только если оба операнд; имеют значение true. Результат операции логическое ИЛИ имеет значение true если хотя бы один из операндов имеет значение true.
Операции отношения (<, <=, >, >=, ==, !=) сравнивают первый операнд со вторым Операнды должны быть арифметического типа. Результат операции — логической типа, равен true или false.
Если в одном выражении соседствуют несколько операций одинакового приоритета, операции присваивания и условная операция выполняются спра налево, остальные — слева направо.
4) Оператор задает законченное описание некоторого действия, данных или элемента программы. Например:
Операции присваивания (=, +=, -=, *- и т. д.) задают новое значение переменной2.
Эти операции могут использоваться в программе как законченные операторы.
Формат операции простого присваивания (=):
переменная = выражение
Механизм выполнения операции присваивания такой: вычисляется выражение
и его результат заносится в память по адресу, который определяется именем переменной,
находящейся слева от знака операции. То, что ранее хранилось в этой области
памяти, естественно, теряется. Схематично это полезно представить себе так:
Переменная <- Выражение
Операторы ветвления Операторы ветвления if и switch применяются для тою чтобы в зависимости от конкретных значений исходных данных обеспечить выполнение разных последовательностей операторов. Оператор if обеспечивает передачу управления на одну из двух ветвей вычислений, а оператор switch — на одну из произвольного числа ветвей.
Условный оператор if Условный оператор if используется для разветвления процесса вычислений па два направления.
в какой-либо ветви требуется выполнить несколько операторов, их необходимо заключить в блок, иначе компилятор не сможет понять, где заканчивается ветвление. Блок может содержать любые операторы, в том числе описания и другие словные операторы (но не может состоять из одних описаний). Необходимо учитывать, что переменная, описанная в блоке, вне блока не существует.
Примеры условных операторов:
а < 0 ) b = 1: ,7 1 а < b && ( а > d 11 а == 0 ) ) b++: else { b *= а: а = 0: } // 2 а < b ) if ( а < с ) m = a: else т = с: if ( b < с ) m = b: else m = с: /.' 3 - b > a ) max = b: else max - a: // 4
} примере 1 отсутствует ветвь else. Подобная конструкция реализует пропуск ператора, поскольку присваивание либо выполняется, либо пропускается в заиснмости от выполнения условия.
Если требуется проверить несколько условий, их объединяют знаками логичеких условных операций
Оператор выбора switch Оператор switch (переключатель) предназначен для разветвления процесса вычислений на несколько направлений
Выполнение оператора начинается с вычисления выражения. Тип выражент чаще всего целочисленный (включая char) или строковый1. Затем управлетп перелается первому оператору из списка, помеченному константным выражением, значение которого совпало с вычисленным.
Все константные выражения должны быть неявно приводимы к типу выражен] в скобках. Если совпадения не произошло, выполняются операторы, расположе ные после слова default (а при его отсутствии управление передается следующе? за switch оператору)
Операторы цикла
Операторы цикла используются для вычислений, повторяющихся многократно. В С# имеется четыре вида циклов: цикл с предусловием whi 1е, цикл с постусловием repeat, цикл с параметром for и цикл перебора foreach. Каждый из них состоит из определенной последовательности операторов.
Блок, ради выполнения которого и организуется цикл, называется телам цикла. Остальные операторы служат для управления процессом повторения вычислений: это начальные установки, проверка условия продолжения цикла и модн• фикация параметра цикла (рис, 4.4). Один проход цикла называется итерацией.
Начальные установки служат для того, чтобы до входа в цикл задать значения переменных, которые в нем используются.
Проверка условия продолжения цикла выполняется на каждой итерации либо до ^ела цикла (тогда говорят о цикле с предусловием, схема которого показана на : пс. 4.4, а), либо после тела цикла (цикл с постусловием, рис. 4.4, 6). Разница между ними состоит в том. что тело цикла с постусловием всегда выполняется хотя бы один раз, после чего проверяется, надо ли его выполнять еще раз. Проверка необходимости выполнения цикла с предусловием делается до тела цикла, поэтому возможно, что он не выполнится ни разу.
Цикл с предусловием while
Формат оператора прост:
while ( выражение ) оператор
Выражение должно быть логического типа. Например, это может быть операция отношения или просто логическая переменная. Если результат вычисления выражения равен true, выполняется простой или составной оператор (блок). Эти действия повторяются до того момента, пока результатом выражения не станет значение fa 1 se. После окончания цикла управление передается на следующий за ним оператор
Цикл с параметром for Цикл с параметром имеет следующий формат:
for ( инициализация; выражение; модификации ) оператор;
Инициализация служит для объявления величин, используемых в цикле, и присвоения им начальных значений. В этой части можно записать несколько операторов, разделенных запятой, например: Областью действия переменных, объявленных в части инициализации цикла, является цикл. Инициализация выполняется один раз в начале исполнения цикла.
Выражение типа bool определяет условие выполнения цикла: если его результат равен true, цикл выполняется. Цикл с параметром реализован как цикл с предусловием.
Модификации выполняются после каждой итерации цикла и служат обычно для изменения параметров цикла. В части модификаций можно записать несколько операторов через запятую, например:
-:г ( int i = 0, j = 20; i < 5 && j > 10; i++, j-- ) ...
Простой или составной оператор представляет собой тело цикла. Любая из частей оператора for может быть опущена (но точки с запятой надо оставить на своих местах!)
Оператор break
Оператор break используется внутри операторов цикла или выбора для перехода в точку программы, находящуюся непосредственно за оператором, внутри которого находится оператор break.
Введение в исключения При вычислении выражений могут возникнуть ошибки, например, переполнение, исчезновение порядка или деление на ноль. В С# есть механизм, который позволяет обрабатывать подобные ошибки и таким образом избегать аварийного завершения программы. Он так и называется: механизм обработки исключительных ситуаций (исключений). Если в процессе вычислений возникла ошибка, система сигнализирует об этом с помощью специального действия, называемого выбрасыванием (генерированием) исключения. Каждому типу ошибки соответствует свое исключение. Поскольку С# — язык объектно-ориентированный, исключения являются классами, которые имеют общего предка — класс Excepti on, определенный в пространстве имен System. Например, при делении на ноль будет выброшено (сгенерировано) исключение с длинным, но понятным именем DivideByZeroException, при недостатке памяти — исключение OutOfMemoryException, при переполнении — исключение OverflowException
Массивы 'i До настоящего момента мы использовали в программах простые переменные. При ^ этом каждой области памяти, выделенной для хранения одной величины, соответствует свое имя. Если переменных много, программа, предназначенная для их '* обработки, получается длинной и однообразной. Поэтому в любом процедурном $ языке есть понятие массива — ограниченной совокупности однотипных величин.
Элементы массива имеют одно и то же имя, а различаются порядковым номером 5 (индексом). Это позволяет компактно записывать множество операций с помощью циклов.
| Массив относится к ссылочным типам данных, то есть располагается в динамической области памяти, поэтому создание массива начинается с выделения памяти под его элементы. Элементами массива могут быть величины как значимых, так и ссылочных типов (в том числе массивы). Массив значимых типов хранит значения, массив ссылочных типов — ссылки на элементы. Всем элементам при создании массива присваиваются значения по умолчанию: нули для значимых типов и null — для ссылочных
Количество элементов в массиве (размерность) не является частью его типа, это количество задается при выделении памяти и не может быть изменено впоследствии. Размерность может задаваться не только константой, но и выражением. Результат вычисления этого выражения должен быть неотрицательным, а его тип должен иметь неявное преобразование к int, ui nt, long или /long.
Пример размерности массива, заданной выражением:
short п = ...; string[] z = new string[n + 1];
Элементы массива нумеруются с нуля, поэтому максимальный номер элемента всегда на единицу меньше размерности (например, в описанном выше массиве w элементы имеют индексы от 0 до 9). Для обращения к элементу массива после имени массива указывается номер элемента в квадратных скобках, например:
44] z[i]
С элементом массива можно делать все, что допустимо для переменных того же типа. При работе с массивом автоматически выполняется контроль выхода за его границы: если значение индекса выходит за границы массива, генерируется исключение IndexOutOfRangeException
Помимо зап111111олнения массива элемент за элементом (как показано в предыдущем примере), можно также заполнять его с использованием специального синтаксиса инициализации массивов. Для этого необходимо перечислить включаемые в массив элементы в фигурных скобках { }. Такой синтаксис удобен при создании массива известного размера, когда нужно быстро задать его начальные значения:
Массив представляет собой совокупность переменных одного типа с общим для обращения к ним именем. В C# массивы могут быть как одномерными, так и многомерными. Массивы служат самым разным целям, поскольку они предоставляют удобные средства для объединения связанных вместе переменных.
Структура — это агрегатный тип данных, так как может содержать в себе разнотипные элементы.
Отличия от классов обусловливают область применения структур: типы данных имеющие небольшое количество полей, с которыми удобнее работать как со значениями, а не как со ссылками. Накладные расходы на динамическое выделен! памяти для небольших объектов могут весьма значительно снизить быстродейств! программы, поэтому их эффективнее описывать как структуры, а не как класс!
ПРИМЕЧАНИЕ С другой стороны, передача структуры в метод по значению требует и дополю тельного времени, и дополнительной памяти.
Синтаксис структуры:
[ атрибуты ] [ спецификаторы ] struct имяструктуры [ : интерфейсы ] тело_структуры [ ; ]
Спецификаторы структуры имеют такой же смысл, как и для класса, причем у спецификаторов доступа допускаются только public, internal и private (после; ний — только для вложенных структур).
Интерфейсы, реализуемые структурой, перечисляются через запятую. Тело струк туры может состоять из констант, полей, методов, свойств, событий, индексатс ров, операций, конструкторов и вложенных типов. Правила их описания и ис пользования аналогичны соответствующим элементам классов, за исключение: некоторых отличий, вытекающих из упомянутых ранее:
• поскольку структуры не могут участвовать в иерархиях, для их элементов н могут'использоваться спецификаторы protected и protected internal;
• структуры не могут быть абстрактными (abstract), к тому же по умолчанш они бесплодны (sealed);
Структуры 213
• методы структур не могут быть абстрактными и виртуальными;
• переопределяться (то есть описываться со спецификатором override) могут только методы, унаследованные от базового класса object;
• параметр this интерпретируется как значение, поэтому его можно использовать для ссылок, но не для присваивания; • при описании структуры нельзя задавать значения полей по умолчанию1 — это будет сделано в конструкторе по умолчанию, создаваемом автоматически (конструктор присваивает значимым полям структуры нули, а ссылочным — значение nul 1).
В листинге 9.8 приведен пример описания структуры, представляющей комплексное число. Для экономии места из всех операций приведено только описание сложения. Обратите внимание на перегруженный метод ToString: он позволяет выводить экземпляры структуры на консоль, поскольку неявно вызывается в методе Console.WriteLine. Использованные в методе спецификаторы формата описаны в приложении.
При выводе экземпляра структуры на консоль выполняется упаковка, то есть неявное преобразование в ссылочный тип. Упаковка (это понятие было введено в разделе «Упаковка и распаковка», см. с. 36) применяется и в других случаях, когда структурный тип используется там, где ожидается ссылочный, например, при преобразовании экземпляра структуры к типу реализуемого ею интерфейса. При обратном преобразовании — из ссылочного типа в структурный — выполняется распаковка.
Присваивание структур имеет, что естественно, значимую семантику, то есть при присваивании создается копия значений полей. То же самое происходит и при передаче структур в качестве параметров по значению. Для экономии ресурсов ничто не мешает передавать структуры в методы по ссылке с помощью ключевых слов ref или out.
Особенно значительный выигрыш в эффективности можно получить, используя массивы структур вместо массивов классов. Например, для массива из 100 экземпляров класса создается 101 объект, а для массива структур — один объект. Пример работы с массивом структур, описанных в предыдущем листинге
Строки типа string
Тип string, предназначенный для работы со строками символов в кодировке Unicode, является встроенным типом С#. Ему соответствует базовый класс System.String библиотеки .NET. И ВСЯ 143 СТРАНИЦА
ючем, иногда эту работу делает за программиста компилятор, это зависит от нахождения описания переменной. Как вы помните из главы 1, программа Z# состоит из классов, внутри которых описывают методы и данные. Переные, описанные непосредственно внутри класса, называются полями класса. автоматически присваивается так называемое «значение по умолчанию» — правило, это 0 соответствующего типа.
«менные, описанные внутри метода класса, называются локальными переменш. Их инициализация возлагается на программиста.
1МЕЧАНИЕ В этой главе рассматриваются только локальные переменные простых встроенных типов данных.
40 Глава 3. Переменные, операции и выражен
Так называемая область действия переменной, то есть область программы, г, можно использовать переменную, начинается в точке ее описания и длит< до конца блока, внутри которого она описана. Блок — это код, заключеннь в фигурные скобки. Основное назначение блока — группировка операторо В С# любая переменная описана внутри какого-либо блока: класса, метода ш блока внутри метода.
Имя переменной должно быть уникальным в области ее действия. Область де ствия распространяется на вложенные в метод блоки, из этого следует, что i вложенном блоке нельзя объявить переменную с таким же именем, что и в охв тывающем его, например:
Глобальные переменные (синтаксис Crystal) Глобальные переменные используют один и тот же блок памяти для хранения какого-либо значения по всему основному отчету. Затем это значение может использоваться всеми формулами, в которых объявляется данная переменная, за исключением формул, содержащихся в подотчетах. Объявите глобальную переменную, как показано в следующем примере:
Использование глобальных переменных Глобальные переменные часто используются для выполнения сложных вычислений, в которых результаты формулы зависят от группировки и макета страницы напечатанного отчета. Для этого необходимо создать несколько формул, поместить их в различные разделы отчета и обеспечить взаимодействие разных формул посредством глобальных переменных. |
|
|