Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЯП - ПОИТ (Бахтизин) часть 1 редакт.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
1.76 Mб
Скачать

6) Присваивание указателей друг другу

p1 = p; // содержимое p копируется в p1, т.е. p1 теперь

// указывает на тот же элемент массива либо

// переменную, что и p

Указатель может быть присвоен другому указателю, если оба указателя имеют один и тот же тип. В противном случае нужно использовать операцию приведения типа. Исключением является указатель типа void.

4.5. Тип void

Ключевое слово void говорит об отсутствии информации о размере элемента данных в памяти.

Практическое значение имеет только понятие указателя на тип данных void. Все остальные применения этого ключевого слова носят скорее синтаксическую нагрузку.

Объявление указателя типа void:

void *p;

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

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

Например:

unsigned a = 0x1234;

void *p = &a;

char b;

unsigned c;

b = *(char *)p; // Приводит указатель типа void к типу

// char и присваивает b значение

// переменной, на которую он указывает

printf("%.2x\n", b); // Выводит 34

c = *(unsigned *)p;

printf("%.4x\n", c); // Выводит 1234

Строка формата "%.2x\n" означает, что число будет выведено в его шестнадцатиричном представлении с двумя знаками. В случае, если число представимо меньшим количеством цифр, оно будет дополнено слева нулями до заданной длины. Аналогично "%.4x\n" означает вывод шестнадцатиричного числа с 4 знаками. Более подробную информацию о строке формата, например "%.4x\n", можно получить в справочной системе среды программирования.

Перед использованием указателя на void в адресной арифметике он также должен быть приведен к нужному типу операцией приведения типа.

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

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

Имя массива является указателем-константой на первый элемент массива.

Объявим переменные:

int a[5];

int *p;

Можно присвоить указателю адрес первого элемента массива двумя способами:

p = a;

p = &a[0];

Есть несколько способов доступа к элементам массива.

  1. Обычный способ, через указание имени массива и индекса, например, a[3]

  1. Способ указатель/смещение: например, *(p + 3). Константа 3 называется смещением и показывает, на какой элемент массива производится ссылка, т.е. значение смещения равно значению индекса массива. В выражении используются скобки, так как приоритет операции * выше, чем операции +. В случае без скобок в выражении *p+3 к значению *p прибавляется число 3 (в данном случае к значению элемента a[0] будет прибавлено 3).

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

*(p++)

получает значение переменной по адресу p и устанавливает указатель p на следующий элемент массива. Операция

*(--p)

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

  1. Имя массива (т.к. является указателем) можно использовать в арифметике указателей. Например, выражение *(a+3) будет ссылаться на элемент массива a[3].

  1. Указатели, в свою очередь, могут быть использованы вместо имен массива. Если, p=&a[0], то p[1] и a[1] обращаются к одной и той же ячейке памяти.

Выражение a+=3 является недопустимым, так как имя массива – это указатель-константа, которая всегда указывает на первый элемент массива. А здесь делается попытка изменить значение начального адреса массива.

Объявим двумерный массив:

int a[3][3];

Выражения наподобие а[0], a[1], a[2] при компиляции заменяются адресами первых элементов соответственно первой, второй и третьей строк массива, a

a[0]-> a[0][0] a[0][1] a[0][2]

a[1]-> a[1][0] a[1][1] a[1][2]

a[2]-> a[2][0] a[2][1] a[2][2]

Очевидны следующие равенства:

a[i]+j == &a[i][j]; // адрес j-го элемента i-строки массива

*(a[i]+j) == a[i][j]; // содержимое j-го элемента i-ой строки массива

*(*(a+i)+j) == a[i][j]; // содержимое j-го элемента i-ой строки массива