Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
нечетные.docx
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
59.67 Кб
Скачать

1. Арифметические операции с указателями и с указателями на массивы.

С указателями можно выполнять следующие операции: разадресация (*), присваивание, сложение с константой, вычитание, инкремент (++), декремент (– –), сравнение, приведение типов. При работе с указателями часто используется операция получения адреса (&). Операция разадресации, или разыменования, предназначена для доступа к величине, адрес которой хранится в указателе. Эту операцию можно использовать как для получения, так и для изменения значения величины (если она не объявлена как константа):

char a;//переменная типа char

char * p = new char;/*выделение памяти под указатель и под динамическую переменную типа char */

*p = 'Ю'; a = *p;//присваивание значения обеим переменным

На одну и ту же область памяти может ссылаться несколько указателей различного типа. Примененная к ним операция разадресации даст разные результаты.

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

Указатели и массивы в языке С++ тесно связаны. Имя массива можно использовать как указатель на его первый элемент:

int main()       {        char alpha[] = "abcdefghijkl";         char* p = alpha;        char ch;         while (ch = *p++)               cout << ch << " = " << int (ch)                    << " = 0" << oct(ch) << '\n';      }

Результат применения к указателям арифметических операций +, -, ++ или -- зависит от типа указуемых объектов. Если такая операция применяется к указателю p типа T*, то считается, что p указывает на массив объектов типа T. Тогда p+1 обозначает следующий элемент этого массива, а p-1 - предыдущий элемент. Отсюда следует, что значение (адрес) p+1 будет на sizeof(T) байтов больше, чем значение p.

Вычитание указателей определено только в том случае, когда они оба указывают на один и тот же массив. Результат вычитания одного указателя из другого равен числу (целое) элементов массива, находящихся между этими указателями. Можно складывать с указателем или вычитать из него значение целого типа; в обоих случаях результатом будет указатель. Если получится значение, не являющееся указателем на элемент того же массива, на который был настроен исходный указатель (или указателем на следующий за массивом элемент), то результат использования такого значения неопределен.

3.Динамическая память. Указатели и массивы. Ссылочный тип.

Программа может хранить информацию в основной памяти компьютера двумя основными спо­собами. Первый из них использует глобальные и локальные переменные, включая массивы, струк­туры и классы. В случае глобальных и статических локальных переменных место хранения инфор­мации фиксируется на все время выполнения программы. В случае локальных переменных память выделяется в стеке. Вторым способом хранения информации служит использование системы динамического выде­ления памяти С++. В этом методе память для хранения информации выделяется из сво­бодной области памяти по мере надобности и возвращается назад, т.е. освобождается, когда надобность в ней исчезла. Область свободной памяти лежит между областью памяти, где разме­щается программа, и стеком. Эта область называется кучей (heap) и используется для запросов на динамическое выделение памяти.

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

Ядром динамического выделения памяти языка С являются функции malloc() и free(), являющиеся частями стандартной библиотеки. Всякий раз, когда функцией malloc() осуществляется запрос на выделение памяти, выделяется порция имеющейся в наличии свободной памяти. Всякий раз, когда эта память освобождается с помощью функции free(), эта память возвращается назад системе.

Язык С++ определяет два оператора динамического выделения памя­ти — new и delete.

Указатели и массивы

Массивы и указатели тесно связаны между собой. Рассмотрим следующий фрагмент: char str [80], *p1; p1 = str; Здесь p1 устанавливается на первый элемент массива str. Если необходимо получить доступ к пятому элементу str, то следует написать str[4] или * (p1 +4) Оба оператора возвращают пятый элемент. Следует помнить, что индексация массивов начинается с нуля, поэтому для индексации str используется 4. К указателю p1 добавляется 4 для получения пятого элемента, поскольку p1 указывает на первый элемент str. (Надо помнить, что имя массива без индекса возвращает начальный адрес массива, то есть адрес первого элемента.)

С предоставляет два метода доступа к элементам массива. Это важно, поскольку арифметические действия с указателями могут выполняться быстрее, чем индексация массива. Поскольку скорость работы программы часто играет важную роль, использование указателей для доступа к элементам довольно типично в С.

Рассмотрим две упрощенные версии стандартной библиотечной функции puts() для демонстрации данных методов. Один вариант использует индексацию массива, а другой - указатели. Функция puts() выводит строку на стандартное устройство вывода: /* Использование массива */ int puts (const char *s) { register int t; for(t=0; s [t]; ++t) putchar (s [t]); return 1; } /* использование указателя */ int puts (const char *s) { while (*s) putchar (*s++); return 1; }

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

#include <iostream.h>

void swap_ref(int &a, int &b) { int c=a; a=b; b=c; }

void swap_ptr(int *a, int *b){ int c=*a; *a=*b; *b=c; }

int main(){int A=10,B=20;

cout << "A="<<A<<" B="<<B<<endl;

swap_ref(A,B);

cout << "after swap_ref(A,B): A="<<A<<" B="<<B<<endl;

swap_ptr(&A,&B);

cout << "after swap_ptr(&A,&B): A="<<A<<" B="<<B<<endl;

return 0;}