Массив и константный указатель
Несмотря на некоторое сходство с константным указателем, массив является особым типом данных. В этом разделе мы рассмотрим основные отличия массива и константного указателя.
Прежде всего, рассмотрим варианты инициализации указателя:
char * const pcchVal_1 = chArray_2; char * const pcchVal_2 = new char[5]; char * const pcchVal_3 = (char *) malloc(5*sizeof(char));
Для инициализации последнего константного указателя был использован вызов функции malloc().
Каждый из этих операторов демонстрирует один из трёх возможных способов инициализации константного указателя: непосредственное присвоение значения, использование операции new, вызов функции. Операция new и функции распределения памяти, выделяют соответствующие участки памяти и возвращают начальный адрес выделенной области памяти. Ни один из этих способов не подходит для инициализации массива.
В свою очередь, при определении константных указателей не используются уже известные инициализаторы массивов с явным указанием размерности и списком инициализаторов.
Определим массив и константный указатель на область памяти:
int intArray[5]= {11,22,33,44,55}; int * const pciVal = new int[5];
К константным указателям и массивам применимы одни и те же методы навигации, связанные с использованием операции индексации:
intArray[-25] = 10; *(intArray + 25) = 10; pciVal[2] = 100; *(pciVal + 5) = 100;
А теперь применим операцию sizeof по отношению к проинициализированным указателям: cout "pciVal:" sizeof(pciVal) " intArray:" sizeof(intArray);
Для Borland C++ 4.5, операция sizeof покажет размер области памяти, занимаемой указателем (4 байта) и размер массива (размер элемента * размерность массива)==(10 байт). Операция sizeof различает указатели и имена массивов.
Кроме того, следующий тест также даёт различные результаты.
if (intArray == intArray) cout "Yes, массив." endl; else cout "No, массив." endl; if (pciVal == pciVal) cout "Yes, указатель. " endl; else cout "No, указатель." endl;
Результат выполнения:
Yes, массив. No, указатель.
Значение указателя, представляющего массив, совпадает с адресом первого элемента массива.
Значением указателя, проинициализированного с помощью выражения размещения, является адрес начала этой области. Сам указатель как объект обладает своим собственным адресом.
Интересно, что сравнение значения указателя с результатом выполнения операции взятия адреса не является абсолютно корректным с точки зрения соответствия типов. Операция взятия адреса возвращает лишь определённое значение адреса. И при этом после выполнения этой операции как бы ничего не известно о типе операнда, чей адрес определяли с помощью этой самой операции взятия адреса. Транслятор отслеживает это нарушение принципа соответствия типов и выдаёт предупреждение "Nonportable pointer comparison".
Поскольку это всего лишь предупреждение, выполнение процесса трансляции не прерывается и загрузочный модуль, построенный на основе этого программного кода, корректно выполняется. "Успокоить" транслятор можно с помощью операции явного преобразования типа, которая отключает контроль над типами:
if (intArray == (int *)intArray) cout "Yes"; else cout "No";