|
Программирование >> Структурное программирование
Типичная ошибка программирования 5.8 Выход за пределы массива при использовании арифметических действий с указателями. Указатель можно присваивать другому указателю, если оба указателя имеют одинаковый тип. В противном случае нужно использовать операцию приведения типа, чтобы преобразовать значение указателя в правой части присваивания к типу указателя в левой части присваивания. Исключением из этого правила является указатель на void (т.е. void*), который является общим указателем, способным представлять указатели любого типа. Указателю на void можно присваивать все типы указателей без приведения типа. Однако указатель на void не может быть присвоен непосредственно указателю другого типа - указатель на void сначала должен быть приведен к типу соответствующего указателя. Указатель void* не может быть разыменован. Например; компилятор знает, что указатель на int ссылается на четыре байта памяти на машине с 4-байтовыми целыми, но указатель на void просто содержит ячейку памяти для неизвестного типа данных - точное количество байтов, на которое ссылается указатель, неизвестно компилятору. Компилятор должен знать тип данных, чтобы определить количество байтов, которое должно быть разыменовано для определенного указателя. В случае указателя на void это количество байтов не может быть определено из типа. Типичная ошибка программирования 5.9 Присваивание указателя одного типа указателю другого типа (отличного от void*) вызывает синтаксическую ошибку. Типичная ошибка программирования 5.10 Разыменование указателя на void*. Указатели можно сравнивать, используя операции проверки равенства и отношения, но такое сравнение бессмысленно, если указатели не указывают на элементы одного и того же массива. При сравнении указателей сравниваются адреса, хранимые в указателях. Сравнение двух указателей, указывающих на один и тот же массив, может показать, например, что один указатель указывает на элемент массива с более высоким номером, чем другой указатель. Типичным использованием сравнения указателя является определение, равен ли указатель 0. Типичная ошибка программирования 5.7 Вычитание или сравнение двух указателей, которые не ссылаются на элементы одного и того же массива. 5.8. Взаимосвязи между указателями и массивами Массивы и указатели в С++ тесно связаны и могут быть использованы почти эквивалентно. Имя массива можно понимать как константный указатель. Указатели можно использовать для выполнения любой операции, включая индексирование массива. Хороший стиль программирования 5.5 Используйте нотацию массивов, а не нотацию указателей при манипуляции массивами. Несмотря на то, что программа может оказаться несколько длиннее, она, вероятно, будет более понятной. Предположим, что объявлены массив целых чисел Ь[5] и целая переменная указатель bPtr. Поскольку имя массива (без индекса) является указателем на первый элемент массива, мы можем задать указателю bPtr адрес первого элемента массива Ъ с помощью оператора bPtr = b; Это эквивалентно присваиванию адреса первого элемента массива следующим образом bPtr = &b[0]; Сослаться на элемент массива Ь[3] можно с помощью выражения указателя *(bPtr + 3) В приведенном выражении 3 является смещением указателя. Когда указатель указывает на начало массива, смещение показывает, на какой элемент массива должна быть ссылка, так что значение смещения эквивалентно индексу массива. Предыдущую запись называют записью указатель-смещение. Скобки необходимы, потому что приоритет * выше, чем приоритет +. Без скобок верхнее выражение прибавило бы 3 к значению выражения *bPtr (т.е. 3 было бы прибавлено к Ь[0] в предположении, что bPtr указывает на начало массива). Поскольку элемент массива может быть указан указателем выражением, адрес &Ь[3] может быть записан также выражением указателем bPtr + 3 Сам массив можно рассматривать как указатель и использовать в арифметике указателей. Например, выражение *(Ь +3) тоже ссылается на элемент массива Ь[3]. Вообще все выражения с индексами массива могли бы быть записаны с помощью указателей и смещений. В этом случае запись указатель-смещение применялась бы к имени массива как к указателю. Заметим, что предыдущий оператор никоим образом не модифицирует имя массива; b продолжает указывать на первый элемент массива. Указатели можно индексировать точно так же, как и массивы. Например, выражение bPtr[1] ссылается на элемент массива Ь[1]; это выражение рассматривается как запись указатель-индекс. Напомним, что имя массива, по существу, является постоянным указателем; оно всегда указывает на начало массива. Таким образом, выражение Ь+= 3 не разрешено, потому что оно пытается модифицировать значение имени массива с помощью арифметической операции над 5гказателем. Типичная ошибка программирования 5.11 Хотя имена массивов являются указателями на их начало, а указатели в арифметических выражениях можно модифицировать, имена массивов в этих выражениях модифицировать нельзя. В программе на рис 5.20 использованы четыре обсужденных нами метода ссылок на элементы массива (индексирование массива, згказатель-смещение с именем массива как указателем, индексирование указателя и указатель-смещение с указателем) для печати четырех элементов массива целых чисел Ь. Чтобы продолжить иллюстрацию взаимозаменяемости массивов и указателей, рассмотрим две функции копирования строк copyl и сору2 в программе на рис. 5.21. Обе функции копируют строку в массив символов. При сравнении прототипов функций для copyl и сору2 функции выглядят идентично. Они соответствуют одной и той же задаче, но выполняются по разному. Функция copyl использует для копирования строки s2 в массив символов si нотацию индексов массива. Функция объявляет целую переменную счетчика i, используемую как индекс массива. Заголовок структуры for полностью выполняет операцию копирования - ее тело является пустым оператором. Заголовок указывает, что i получает нулевое начальное значение и увеличивается на единицу в каждой итерации цикла. Условие (sl[i] = s2[i]) != \0 в for выполняет операцию копирования символ за символом из s2 в si. Когда в s2 встретится нулевой символ, он присваивается si, и цикл завершается, потому что нулевой символ равен \0. Напомним, что значением оператора присваивания является значение, присвоенное левому аргументу. Функция сору2 использует для копирования строки s2 в массив символов si указатели и арифметику указателей. Опять же, заголовок структуры for полностью выполняет операцию копирования. Заголовок не содержит никаких операций задания начальных условий. Так же, как в функции copyl, условие (*sl = *s2) !=\0 выполняет операцию копирования. Указатель s2 разыменовывается и результирующий символ присваивается разыменованному указателю si. После присваивания в условии указатели увеличиваются, чтобы указать на следующий элемент массива si и следующий символ строки s2 соответственно. Когда s2 указывает на нулевой символ, он присваивается разыменованному указателю si и цикл заканчивается.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |