Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Итог_Пособие C++.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.03 Mб
Скачать

1.7 Указатели и ссылки. Связь указателей и массивов. Библиотека cstring

1.7.1 Понятия указателя и ссылки

Указатель – это переменная, в которой хранится адрес памяти. Указатель может указывать (ссылаться) на переменную или функцию. В данный момент предмет нашего внимания – указатель на переменную. Две базовые операции при работе с указателями - & и *.

Операция определения адреса & определяет адрес ячейки памяти, содержащей заданную переменную. Например, если v – имя переменной, то &v – указатель на эту переменную (т.е. её адрес).

Операция косвенной адресации (операция разыменования указателя) * позволяет обратиться к переменной, на которую ссылается указатель.

Если p – указатель, то *p – значение, на которое он указывает. В выражениях разыменованные указатели могут находиться как слева, так и справа от операции присваивания.

Объявление указателя выполняется следующим образом:

тип * имя_указателя[=инициатор];

Например (фрагмент программы):

int a=10;

int *ptr = &a; //инициализация указателя адресом переменной a

cout <<“указатель =“<<ptr<<“\nПеременная =”<<*ptr;

*ptr=8;

cout << “Переменная a=” << a << endl; // будет выведено 8

Размер ячейки памяти для хранения указателя зависит от архитектуры компьютера и используемой модели памяти (обычно 4 байта).

Ссылка (reference) – видоизменённая форма указателя, которая используется в качестве псевдонима (другого имени) переменной.

int &d = a;

Далее в программе можно использовать имя d для переменной a. Ссылки обычно используются как средство упрощения записи при передаче параметров в функцию или возвращении результата функции (как альтернатива указателям). Этот вопрос мы подробно разберём в разделах, посвящённых функциям. Пока достаточно уяснить, что указатели и ссылки имеют схожую внутреннюю реализацию, но в программе используются немного по-разному.

1.7.2 Связь между массивами и указателями

В C++ массивы и указатели тесно связаны друг с другом. Имя массива можно рассматривать как указатель-константу на начало массива (адрес первого элемента массива):

int a[10];

int *p=a;//то же, что и int *p=&a[0]; - адрес первого элемент массива

Наоборот, с указателями можно работать как с массивами - использовать операцию индексирования − []:

p[3]=11; // то же самое, что a[3]=11;

cout << a[3]; // будет выведено 11

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

Например (фрагмент программы):

int a[4]={1,3,7,5}, *p=a; p+=3; cout<<*p;//выводит последний элемент 5

Разность двух указателей представляет собой количество элементов массива, их разделяющих (в последнем примере разность p-a имеет значение 3).

Следует помнить, что имя массива нужно рассматривать как указатель-константу, его изменение невозможно. Оператор a++; в примере с массивом a вызовет ошибку при компиляции.

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

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

Для динамического управления памятью будем использовать операции new и delete. Операция new выделяет объём памяти для одного или нескольких объектов указанного типа:

int *i, *j;

i = new int; //выделяет память под один элемент int

// и возвращает указатель на него

cin>>n; j = new int [n]; // выделяет память под массив из n элементов

// и возвращает указатель на первый элемент

Операция delete освобождает захваченную память: delete i;

delete[] j; // освободили всю память, выделенную для массива

Пример программы с использованием указателей. В данном примере динамически формируется массив из N элементов и заполняется путём ввода с клавиатуры. Если первый элемент массива больше последнего элемента, то они меняются местами. После этого массив выводится на экран.

//Пример 1.9 - работа с массивом на основе указателей

#include <iostream>

using namespace std;

int main()

{

int n, *c, *p;

cout<<"n=7"; cin>>n; c=new int[n];

cout<< "Enter numbers "<<endl;

for(p=c;p<c+n;p++) cin>>*p;

if (*c>*(c+n-1))//c+n-1 - адрес последнего элемента

{

int temp=*c; *c=*(c+n-1);

*(c+n-1)=temp;

}

for(p=c;p<c+n;p++) cout<<*p<<' ';

delete[] c;

cout<<endl; system("pause");

return 0;

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]