Указатели и ссылки позволяют неявно ссылаться на другие объекты. Как же тогда решить, когда применять указатели, а когда ссылки?
Во-первых, запомните, что не существуетнулевых ссылок.Ссылка всегдадолжнассылаться на какой-то объект. Если переменная обеспечивает доступ к объекту, которого может и не быть, то следует использовать указатель. При небходимости ему можно присвоить нулевое знаение. Это подразумевает, что в программе значение указателя следует проверять на равенство нулю, а значение ссылки нет.
Другое важное различие между указателем и ссылкой заключается в том, что указателю можно присваивать различные значения для доступа к разным объектам. Ссылка же всегда указывает на один и тот же объект, заданный при ее инициализации.
Пример 3_3_1. Указатели и ссылки
# include < iostream >
using std::cout;
using std::endl;
Int main()
{
int i =10, j =20;
int& rfc = i; cout<<rfc <<endl; // результат 10
int* ptr = &i; cout<<*ptr<<endl; //10
ptr = & j; cout <<* ptr << endl; //20, изменилось значение указателя
cout<< i <<endl; //10, значение i не изменилось;
rfc = j; cout << rfc << endl; //20, изменилось значение данных
cout<< i <<endl; //20, значение i изменилось,
//так как rfc по-прежнему ссылается на i;
system("pause");
return 0;
}
Указатели и массивы
Имя массива – этоуказатель-константа на начало массива.
Таким образом доступ к элементу массива можно записать через смещение от начала массива. Например для массива b, операция разыменования *(b +3) – это тоже, что и операция индексирования b [3] (взгляните еще раз на пример первой программы во введении). Для элемента двумерного массива data [ row ][ col ] операция индексирования переводится компилятором в операцию разыменования указателей *(*(data + row)+ col).
Описание int (* data 1)[20] определяет указатель на массив из 20 целых значений.
Описание int * data 1[20] определяет массив из 20 указателей на целые значения.
Начальный адрес массива определяется компилятором в момент описания массива, и такой адрес не может быть переопределен. Это делает невозможным копирование массивов с помощью простого оператора присваивания (как в языке Pascal).
Наример:
const int ArraySize=5;
int a[ArraySize] = {12, 3, 42, 5, 34};
int b[ArraySize];
b=a; // ОШИБКА! Попытка изменить константный указатель b,
// сообщение компилятора C++ Microsoft Visual Studio:
// «error C2106: '=': left operand must be l-value»,
// т.е. b должно быть изменяемой величиной
Динамическое размещение массива. Указатели используются для размещения массива в динамическойобласти оперативной памяти – «куче».
Для выделения памяти применяется оператор – new тип[размер массива],
для освобождения – delete [].
Например:
int * ptrArray1 = new int[5];//ptrArray1 – начальный адрес массива из 5 элементов
... // использование массива ptrArray1
delete [] ptrArray1; // освобождение памяти сначальным адресом ptrArray1
Пример 3_4_1. Указатели и массивы
# include < iostream >
using std::cout;
using std::endl;
Int main()
{
int Array[5] = {10, 20, 30, 40, 50}; // статический массив – память
//резервируется при компиляции
int * ptrArray1 = new int[5]; // динамические массивы – память резервируется
int* ptrArray2 = new int[5]; // «в куче» при выполнении программы
//Размер массива. В случае динамического массива получаем размер указателя!
cout<<"SizeofArray " <<sizeof(Array) <<endl; // результат - 20
cout<<"SizeofPtrArray "<<sizeof(ptrArray1)<<endl; // результат - 4
//Копирование значений массивов - доступ к элементам массивов одинаковый
for (int i=0; i<5; ++i){ // копируем значения из Array в ptrArray1,
*(ptrArray1+i)=*(Array+i); //используя для доступа к значениям
cout<<*(ptrArray1+i)<<endl; // массивов разыменование указателя
}
for (int i=0; i<5; i++) { // копируем значения из Array в ptrArray2,
ptrArray2[i]= Array[i]; // используя для доступа к значениям
cout<<ptrArray2[i]<<endl; // массивов имя массива и номер элемента
}
delete [] ptrArray1; //освобождаем память,
delete [] ptrArray2; //выделенную для ptrArray1 и ptrArray2
system (" pause ");
return 0;
}