Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛекцииЛаб(Часть_1_Книги).doc
Скачиваний:
7
Добавлен:
03.05.2019
Размер:
1.04 Mб
Скачать

3.2. Операции сравнения.

Указатели можно сравнивать, используя обычные операции отношения (= =, != , <, <=, >, >=). Но при этом оба указателя (например, p и q) должны ссылаться на элементы одного и того же массива. В противном случае нет гарантии, что между адресами будет выполняться нужное соотношение. В результате операции p==q (p!=q) получается истина (ложь), если p и q указавают на один и тот же элемент массива. Остальные операции (p<q, p<=q, p>q, p>=q) дают в результате истину, если p указывает на элемент с меньшим (меньшим или равным, большим, большим или равным) индексом, чем q. Другими словами, получается истина, если p имеет меньший (меньший или равный, больший, больший или равный) адрес, чем q.

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

Но при работе с частично динамическими или динамическими матрицами (глава 3) накладываются некоторые ограничения на использование указателей, и, соответственно, рассмотренных выше операций.

§4. Использование операций над указателями при работе с одномерными массивами

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

4.1. Использование индексов

Рассмотрим сначала обычный вариант организации цикла без явного использования указателей. Пусть функция обрабатывает одномерный статический или динамический массив ar размерности size.

int MySum0 (int* ar, unsigned size)

{ int S=0;

for (unsigned i=0; i<size; i++) S+=ar[i]; // или S+=i[ar];

return S;

}

При использовании индексного выражения компилятор преобразует его в адресное *(ar+i). При выполнении программы сначала вычисляется адрес ar+i так, как было описано раньше, а затем берётся содержимое по этому адресу. При этом важно обратить внимание на то, что такое преобразование выполняется не потому, что в заголовке функции мы объявили указатель на массив. Такое преобразование имеет место и в случае объявления обычного статического массива const n=5; int a[n];. Так как a — константный указатель на начало массива, то a[i] равносильно *(a+i), где i=0,1,…,4.

Поэтому возникает вопрос, почему бы не помочь системе выполнить такое преобразование. Такая помощь реализуется следующим образом:

int MySum1 (int* ar, unsigned size)

{ int S=0; for (unsigned i=0; i< size; i++) S+=*(ar+i);

return S;

}

Это самый простой вариант использования указателя при работе с массивом. Здесь вместо ar[i] записали *(ar+i). Но последний вариант для компьютера “легче”. Дополнительную переменную-указатель здесь мы не использовали, а ограничились указателем на массив ar. Такой вариант приемлем как для статического, так и для динамического одномерных массивов.

Теперь должно быть понятно, почему индексы массивов в языках С и С++ начинаются с нуля. Это связано с тем, что индекс определяет не столько номер элемента, сколько его смещение относительно начала массива.

Так как ar+i=i+ar, то доступ к i-му элементу массива можно записать и так: *(i+ar) или даже более оригинально: i[ar].

Если по какой либо причине неизвестно количество элементов статического массива, то его можно определить следующим образом: sizeof(a)/sizeof(a[0]). Здесь учитывается, что все элементы массива имеют одинаковый размер. Важно также обратить внимание на следующее. Несколько раз напоминалось, что имя массива (a) — это константный указатель, в котором хранится адрес начала массива. Тогда возникает вопрос: sizeof(a) — это размер чего, ячейки для указателя или размер всего массива? Здесь сделано исключение. В этой операции массив “забывает” о связи с указателем, и её результатом является размер в байтах участка оперативной памяти, выделенного для всего массива, а не для указателя. Обратим внимание, что получается не количество элементов массива, а необходимый для всего массива объём памяти в байтах. Тогда для получения количества элементов в масссиве объём всей памяти разделили на объём памяти для одного элемента.

Но заметим, что если бы эту операцию использовали внутри функции MySum1 для ar, то sizeof(ar) — это объём памяти для указателя, а не для массива.