bmstu_iu6_Cpp1 (823967), страница 8
Текст из файла (страница 8)
Такая схема называется косвенной адресацией. Глубина косвенной адресации не ограничена, однако, почти всегда, можно ограничиться «указателем на указатель». Более громоздкие схемы могут привести к ошибкам,которые трудно обнаружить.Переменная, представляющая собой указатель на указатель, объявляется следующимобразом:<Имя типа> ** <Имя переменной>где <Имя типа> – любой допустимый тип С++, например:float **ptr1;int **ptr2;При работе с косвенной адресацией указатели разыменовывают столько же раз,сколько раз выполнялась операция взятия адреса:float a,*ptr1=&a,**ptr2;puts(″Input a″);scanf(″%f″,&a);ptr2=&ptr1;printf(″%p%3d\n″,*ptr2,**ptr2);3.1.2 Понятие ссылкиКроме указателя в С++ для хранения адреса может использоваться ссылка. Ссылкаопределена как альтернативное имя уже существующего объекта.
Основные достоинствассылок проявляются при работе с возвращаемыми параметрами функций.Правила описания ссылок:<Тип данных> &<Имя>[= <Выражение>] или<Тип данных> &<Имя>[(<Выражение>)]Обе формы допустимы, например:int L=127;int &SL=L;// первая формаint &SL(L);// вторая формаОглавление48В качестве выражения для инициализации ссылки обычно задают имя некоторогообъекта, размещенного в памяти. Значением ссылки после инициализации становится адрес этого объекта, так в примере, приведенном выше, значением ссылки SL является адреспеременной L.3.1.3 Отличие ссылки от указателяОтличия ссылки от указателя следуют из их деклараций. Так указатель определяетсякак адрес и при работе с адресуемыми им данными необходимо использовать операциюразыменования. Ссылка объявляется как альтернативное имя, поэтому при работе сданными по ссылке разыменование не нужно:int a,*ptri=&a, // указатель – адрес переменной а&b=a;// ссылка – альтернативное имя переменной а…a=3; тоже самое, что и *ptri=3; тоже самое, что и b=3; (см.
рисунок 3.1).ptria=b4Рисунок 3.1 – Переменная a, указатель ptri и ссылка b3.2 Адресная арифметикаОсновное правило адресной арифметики определяется следующим образом: при увеличении или уменьшении адреса, хранящегося в указателе, на количество единиц n значение адреса изменяется на n, умноженное на размер элемента данных, единиц:<Указатель> + n⇔<Адрес> + n*sizeof(<Тип данных>)Например:short a, *ptrs =&a;1) ptrs++; // адрес в указателе меняется на длину элемента базового типа (см. рисунок 3.2);Оглавление49ptrsptrsaa22Рисунок 3.2 – Увеличение указателя на единицу2)ptrs+=4; // адрес в указателе меняется на 4 размера элемента базового типа(см.
рисунок 3.3).ptrsptrsaa22Рисунок 3.3 – Увеличение указателя на четыре единицы3) *(ptrs+2)=2; // адрес в указателе не меняется (см. рисунок 3.4)ptrsa2Рисунок 3.4 – Обращение к заштрихованному полю без изменения указателяОсобенности результатов выполнения операций адресной арифметики, связанные с реализацией языка С++. В С++ принят обратный порядок размещения объектов впамяти. Это объясняется особенностями работы компилятора.
При разборе текста, компилятор распознает и размещает в стек имена всех объектов, которые необходимо разместитьв памяти. На этапе распределения памяти имена объектов выбираются из стека и им отводятся смежные участки памяти. А так как порядок записи в стек обратен порядку чтения,размещение объектов оказывается обратным, например:int i1=10,i2=20,i3=30;Первой будет в памяти размещена переменная i3, она будет иметь меньший адрес.Адрес переменной i1 – самый большой, тогда, если указатель p определен какint *p=&i2;то *(p+1) ⇔ i1, а *(p-1) ⇔ i3.Оглавление503.3 Управление динамической памятьюС++ включает набора средств, позволяющих организовать работу с динамически выделяемой памятью: унаследованный от Си и реализованный в С++.
В программе не следует смешивать использование средств разных языков.Работа с динамической памятью с помощью средств Си. Процедуры работы с динамической памятью, унаследованные от Си, размещены в библиотеке alloc, соответственно их прототипы находятся в файле alloc.h.1. Процедура выделения памяти под одну переменную возвращает адрес начала области выделенной памяти или NULL, если память не выделена. Поскольку адрес не связанс данными конкретного типа, при записи значения в типизированный указатель необходимо явное преобразование типа.Прототип процедуры:void * malloc(size_t size);где size – параметр, определяющий размер выделяемой области.2.
Процедура выделения памяти под несколько переменных возвращает адрес области выделенной памяти или NULL, если память не выделена. Память выделяется однимкуском под размещение заданного количества элементов, поэтому для доступа к отдельным переменным можно использовать адресную арифметику.Прототип процедуры:void * сalloc(size_t n, size_t size);где size – параметр, определяющий размер выделяемой области;n – количество областей.Следует помнить, что любая память, динамически выделенная под размещениепеременных, должна быть освобождена.3.
Процедура освобождения памяти:void free(void *block);где block – параметр, определяющий адрес освобождаемого блока памяти.Примеры:а) выделение памяти под одно значение с проверкой результата выполнения операции:int *a;if ((a=(int *)malloc(sizeof(int)))==NULL){printf("Память для числа не выделена.");Оглавление51exit(1);}*a=-244;*a+=10;free(a);б) выделение памяти под размещение нескольких значений:int *list;list = (int *) calloc(3,sizeof(int));*list=-244;*(list+1)=15;*(list+2)=-45;…free(list);Управление динамической памятью средствами С++. Для работы с динамическойпамятью в С++ используют специальные операторы new и delete.
Форматы записи этихоператоров при работе с одним значением и несколькими значениями различны.1. Операция выделения памяти под одно значение:<Типизированный указатель> =new <Тип>[(<Значение>)];где <Тип> – тип значения, под размещение которого выделяется память – определяет размер памяти, выделяемый данным оператором;<Значение> – инициализирующее значение, которое, как показывают квадратныескобки, может быть опущено.2.
Операция освобождения памяти, выделенной под одно значение:delete <Типизированный указатель>;Примеры:а) выделение памяти без проверки правильности завершения операции:int *k;k = new int;*k = 85;delete k;б) с проверкой правильности выделения памяти:int *a;if ((a=new int(-244))==NULL){printf("Память для числа не выделена.");Оглавление52exit(1);// завершение программы с признаком ошибки}delete a;3. Операция выделения памяти под несколько значений:Указатель> = new <Тип>[<Количество>];где <Тип> – тип значения, под размещение которого выделяется память – определяет размер памяти, выделяемый для одного значения;<Количество> – количество значений, которое необходимо разместить в памяти.4.
Операция освобождения памяти, выделенной под несколько значений. Квадратныескобки присутствуют в операторе и указывают, что освобождается несколько значений, память под которые отводилась одним оператором new:delete[] <Типизированный указатель>;Пример выделения памяти под переменные одним куском (см. рисунок 3.5):listlist+1list+22Рисунок 3.5 – Использование адресной арифметики для обращения к переменнымshort *list;list = new int [3];*list=-244;*(list+1)=15;*(list+2)=-45;delete[] list;3.4 МассивыМассив С++ – абстракция, используемая при работе с последовательно расположенными в памяти значениями одного типа. Доступ к этим значениям может осуществлятьсялибо с применением возможностей адресной арифметики (как показано в предыдущемразделе), либо с указанием номера элемента (как обычно принято при работе смассивами).При размещении в памяти младший адрес соответствует первому элементу массива,а старший – последнему.
Однако индексы элементов массива всегда начинаются с 0.Оглавление53Массивы могут быть одномерными, двумерными, трехмерными и многомерными.Для доступа к элементам многомерных массивов необходимо столько индексов, каковаразмерность массива. Двумерные и многомерные массивы расположены в памяти «построчно», т.е. правые индексы меняется быстрее, чем расположенные левее. Так элементыматрицы A(3,4), где 3 – количество строк, а 4 – количество столбцов, расположены в памяти в следующей последовательности: a00, a01,a02,a03, a10, a11,a12,a13, a20, a21,a22,a23.Массив можно создать двумя способами:•запросить память для размещения его элементов посредством оператора new(см.