И.Г. Головин, И.А. Волкова - Языки и методы программирования, страница 13
Описание файла
PDF-файл из архива "И.Г. Головин, И.А. Волкова - Языки и методы программирования", который расположен в категории "". Всё это находится в предмете "языки программирования" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 13 страницы из PDF
С точки зрения машинного языка имя подпрограммы соответствует машинному адресу первойкоманды тела подпрограммы. Поэтому в С и C++ имена подпрограммрассматриваются как указатели особого функционального типа. Подробнее этот тип рассматривается в гл. 6.Ссылочные типы данныхТ о л ь к о ч т о м ы в ы я с н и л и , ч т о понятие указателя слишком близкок машинному языку, и употребление указателей может привестик хитрым ошибкам в программах. Понятие ссылки тоже являетсяабстракцией адреса, но лишено недостатков указателя.В языке C++ ссылка — это аналог имени (можно рассматриватьссылку на объект данных как альтернативное имя объекта).
Синтаксис объявления ссылки на данные типа т следующий (сравнитес синтаксисом указателя):Т & имя_ссылкиК ссылкам языка C++ применима единственная операция — инициализация.Как именно выглядит инициализация ссылки зависит от контекста, в котором определена ссылка. Если ссылка объявлена как переменная (локальная или глобальная), то инициализация имеет видТ & имя_ссылки = объект_типа_ ТНапример:int k = -1; // объект типа int58int& kk = к; // инициализация ссылки kkkk++; // это — обращение к к. Теперь к содержит Оint b = 4;кк = Ь; //и это — обращение к к. Теперь к содержит 4После инициализации любое употребление ссылки эквивалентноупотреблению объекта, на который она ссылается (из инициализатора).Другим важным контекстом инициализации ссылки являетсяобъявление формального параметра функции как ссылки.
В этомслучае инициализация формального параметра—ссылки объектом,т.е. фактическим параметром, происходит в момент вызова функции(подробнее см. гл. 6). Во время выполнения функции формальныйпараметр обозначает объект — фактический параметр, поэтому операции над формальным параметром выполняются на самом деле надфактическим.В языках C# и Java ссылки — это единственный способ обращения к объектам.
В этих языках принята референциальная объектнаямодель. Поясним, что она собой представляет.В C# и Java выделены референциальные типы — это классы,массивы и интерфейсы. Объекты этих типов располагаются тольков динамической памяти, являются анонимными и доступными только через ссылки. Объект создается с помощью операции new либосоздается копия объекта (клонирование).Приведем пример на языке С#:X obj = new Х(); // создание нового объектаX obj = obj.Clone (); // создание копии объектаНа языке Java операция создания копии имеет видX obj = obj.clone ();Остальные типы в языке C# называются типами-значениями.К ним относятся все простые типы данных, а также структуры (структуры языка C# рассмотрим вместе с классами). В Java термина «типызначения» нет по той причине, что нереференциальные типы — этопростые типы данных (за исключением перечислимого типа, которыйявляется классом особого вида).
Аналога понятия «структура» в Javaнет. Мы будем употреблять термин «типы-значения» для любых нереференциальных типов в этих языках.Объекты типов-значений могут располагаться в любом классе памяти: в статической, квазистатической (т. е.
в стеке) и динамической(в составе объектов референциальных типов).Пусть X — класс. Объявление X а; не размещает объект, а объявляет ссылку на X. Начальное значение такой ссылки — пустое.Пустая ссылка обозначается ключевым словом null. Пустая ссылкасовместима с любым классом.
Рассмотрим следующий фрагмент(применимый как к С#, так и к Java):59X a,b; // это не объекты класса, а ссылкиа = new Х(); // объект размещен, а ссылается на негоЬ = а ; // b и а ссылаются на один и тот же объекта = new Х(); // еще один объект// а ссылается на второй объект// b ссылается на первый объектСсылки в C# и Java отличаются от ссылок в C++ тем, что ссылкив C++ «навсегда», т.е. в течение всего времени их жизни, полностьюассоциированы с объектом. Даже если ссылка стоит в левой частиоперации присваивания, все равно речь идет о присваивании объекту, которым инициализирована ссылка.
В C# и Java присваивание ссылке означает новую ассоциацию, поэтому нельзя считать,что ссылки в C# и Java — это альтернативное имя объекта (какв C++).Однако ссылки в C++ и ссылки в C# и Java похожи в том плане,что после установления ассоциации с объектом ссылка идентичнасамому объекту, и поэтому не требуется никакая операция разыменования (типа операции * с указателем).5.2.
Составные типы данныхСоставные типы данных — это типы, значения которых состоятиз подобъектов, т. е. имеют внутреннюю структуру. Самый популярный составной тип данных (и первый составной тип, появившийсяв языках программирования) — это массив.Одномерные массивыМассив — это непрерывная последовательность элементов одноготипа.Основная операция, применимая к любому массиву, это операция индексирования, обозначаемая чаще всего как [ ]. Операция,записанная в виде А [I ], имеет два аргумента: объект-массив А изначение I некоторого дискретного типа (к дискретным типам относятся целые, перечислимые и диапазоны). Значение I называютиндексом элемента массива. Индексирование возвращает ссылку наэлемент массива:[ ] : А, 1->Т&Отметим, что возвращаемое значение — это именно ссылка,а не просто значение элемента массива, так как результат операцииприсваивания может стоять в левой части операции присваивания.Основные требования к операции индексирования — однородность60и эффективность.
Однородность означает независимость временивыполнения операции от значения индекса, а эффективность —быстрое выполнение операции.Перечислим атрибуты массива:• базовый тип (Т);• тип индекса (I);• диапазон индекса (L и R — нижняя и верхняя границы) и связанная с ним характеристика — длина массива.Не вдаваясь в обсуждение вариантов реализации массивов в различных языках программирования, отметим, что в большинствесовременных языков концепция массива упростилась: тип индексавсегда целый, нижняя граница диапазона индексов (L) — всегда О,верхняя граница (R) — N - 1, где N — длина массива.Следовательно, основной вопрос, касающийся массивов в современных языках, — это время связывания базового типа Т и длинымассива N с объектом-массивом.Базовый тип элементов связывается с массивом всегда статически — в объявлении массива.
Длина массива N в С и C++ тоже статическая (и тоже задается в объявлении), а в C# и Java — динамическаяи задается при размещении объекта в динамической памяти (т. е. приобращении к операции new).Одномерные массивы в языке C++. Объявление массива имеетвидТ att[LEN];Здесь т — произвольный тип данных, a LEN — статическое (т.е.вычисляемое компилятором) выражение. В зависимости от контекстаобъявления массив размещается либо в статической, либо в динамической памяти.
Примеры размещения массива в динамическойпамяти см. в подразд. 5.1.Массив в C++ не является «полноценным» объектом данных. Этопроявляется, например в том, что один массив нельзя присвоитьдругому:int al[256]; int а2[256];al = а2; // ошибка !!!Операция индексирования в языке не контролирует корректностьиндекса:for (int k = 0; k < 300; k++)a l [k] = a 2 [k];В нашем примере индекс, начиная со значения 256, выходит заверхнюю границу, но ни при компиляции, ни во время выполненияникакой диагностики выдано не будет.
Поведение программы притаких ошибках непредсказуемо и зависит от реализации.61Имя массива трактуется в С и C++ как указатель, т. е. адрес первого элемента массива (напомним, что индекс первого элемента массива — 0), а операция индексирования тесно связана с адреснойарифметикой, т. е. для любого массива array и целого значения iверны следующие тождества:&(array[i]) з array+iили в другом видеarray[i] = * (array+i)Как уже отмечалось, корректность адресной операции не можетбыть проконтролирована, поэтому и операция индексирования неконтролируется, даже в очевидных случаях типа array [-1 ].Отличие имени массива типа т от указателя типа т* состоит в том,что имя массива трактуется как указатель-константа, поэтому этомуимени ничего нельзя присвоить (что вполне резонно, так как иначедоступ к элементам массива может исчезнуть). Более того, любойуказатель можно трактовать как имя массива и применять к немуоперацию индексирования:int * р; ...
р [0] = 0 ;// то же самое, что *р=0;Поэтому когда операция new [ ] (размещение массива в динамической памяти) возвращает указатель, это вполне согласуетсяс правилами языка.Таким образом, понятие указателя перекрывает понятие массива,поэтому программисты на С и C++ нередко предпочитают работатьс массивом через указатель (что, как правило, более эффективно).Приведем пример как можно суммировать элементы массива наС и C++:int arr[N];int * pCurr = arr;int * pEnd = arr+N;// pEnd указывает ЗА конец массиваint sum = 0;while (pCurr < pEnd)sum += *pCurr++;или более короткая запись:for (int *pCurr = arr, *pEnd=pCurr+N, sum =0;pCurr < pEnd; pCurr++)sum += *pCurr;Заметим, что C++ — действительно выразительный язык!Фактически понятие одномерного массива в С и C++ используется в основном как шаблон для размещения последовательностейв статической или квазистатической памяти.