Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lab12.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
91 Кб
Скачать
☆
      1. Присваивание указателей

Как и обычные переменные, указатели могут использоваться с правой стороны оператора присваивания для присвоения значения другому указателю. Например:

#include <stdio.h>

int main(void)

{

int x;

int *p1, *p2;

p1 = &x;

p2 = p1;

printf(“%p %p”, p1, p2); /* выводит адреса, хранящиеся в p1 и р2.

Они будут одинаковы */

return 0;

}

      1. Арифметические действия с указателями

К указателям могут применяться только две арифметические операции: сложение и вычитание. Предположим, что p1 – это указатель на целое длиной 2 байта. После выполнения выражения

p1++;

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

p1 ;

приведет к уменьшению значения указателя на 2 и сдвигу его к предыдущему элементу.

Можно вычитать из указателей любые целые числа. Выражение:

p1 = p1 + 7;

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

Операция

р2 – р1

дает число элементов между указателями р1 и р2.

      1. Сравнение указателей

В общем случае сравнение указателей с помощью одной из операций отношения имеет смысл в том случае, если оба указателя указывают на общий для них объект, например, массив или строку. Например:

#include <stdio.h>

int main(void)

{

int a, b;

int p1, *p2;

p1 = &a;

p2 = &b;

/* указатели р1 и р2 не равны, так как они указывают на разные объекты */

if (p1 != p2) printf(“Указатели р1 и р2 не равны\n”);

else printf(“Эта строка не напечатается”);

return 0;

}

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

Между указателями и массивами существует прямая связь. Когда объявляется массив, например

int arr[25];

то этим определяется несколько больше, чем только выделение памяти для 25 элементов типа int. А именно, идентификатор массива arr определяется как указатель на первый (нулевой) элемент массива (адрес первого элемента массива &arr[0]). Так как идентификатор массива определяется как адрес, то следующее присваивание является допустимым:

int arr[25];

int *ptr;

ptr = arr;

Указатель ptr устанавливается на адрес первого элемента массива arr. Указатель ptr становится указателем на массив и его можно использовать для ссылки на элементы массива. Это присваивание можно записать в эквивалентной форме:

ptr = &arr[0];

Для доступа к элементам массива тоже существует два способа.

Первый способ доступа к элементам массива связан с использованием обычных индексных выражений вида arr[i]. Например, индексное выражение arr[5] ссылается на шестой элемент массива arr.

Второй способ доступа к элементам массива связан с использованием адресного выражения (или выражения с указателем на массив)

*(ptr+1) .

Например, адресное выражение *(ptr+5) ссылается на шестой элемент массива arr.

Рассмотрим как вычисляется индексное выражение arr[5]. Идентификатор arr является указателем начала массива. В соответствии с правилами выполнения операции сложения указателя с целой величиной целая величина преобразуется к адресному представлению путем умножения ее на размер типа, адресуемого указателем. Целая константа 5 умножается на размер типа int. Преобразованное значение числа 5 складывается со значением указателя arr, что дает адрес, относящийся к шестой позиции типа int после arr. К полученному адресу применяется операция «разадресация». Результатом является значение шестого элемента массива. В терминах языка С это выглядит так:

arr[5] = (arr+5) = (arr + 5*sizeof(int)) .

Следовательно, следующие выражения ссылаются на шестой элемент массива arr:

arr[5];

5[arr];

*(arr + 5);

*(5 + arr) .

Как следует из определения индексного выражения языка С, любой указатель может быть задан с индексом. Указатель на массив тоже может быть проиндексирован. Выражения

Ptr[5]

5[ptr]

ссылаются на тот же шестой элемент массива arr. Если расписать индексное выражение ptr[5], то получается адресное выражение

*(ptr + 5) .

В действительности компилятор языка С преобразует все индексные выражения в адресные выражения. Например:

arr[i] в *(arr + i)

ptr[i] в *(ptr + i) .

Таким образом, для доступа к i-му элементу массива arr можно пользоваться любым из данных выражений

arr[i] i[arr] *(arr + i)

*(i + arr) *(ptr + i) *(i + ptr)

ptr[i] i[ptr]

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

Пример.

/* Функция strcpy – копирование строк */

/* Вариант с использованием массивов */

char *strcpy (char s1[ ], char s2[ ])

{

int I;

for (i = 0; s1[i] = s2[i]; i++);

return (s1);

}

/* Вариант с использованием указателей */

char *strcpy (char *s1, char *s2)

{

char *str = s1;

while (*s1++ = *s2++);

return (str);

}

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