
- •1 Компьютер для программиста.
- •12. Пользовательские скалярные типы данных в языках Си
- •13.Структурированые типы данных в языке си
- •14.Арифметические выражения
- •18. Выражения с указателями
- •20.Константные выражения
- •21. Приоритет операций и скобочная структура выражений
- •22. Структура программы на си
18. Выражения с указателями
1. К указателям можно применять операцию присваивания. Указателю на void можно присвоить указатель любого типа. Однако при обратном присваивании необходимо использовать явное преобразование указателя:
void *pv;
float f, *pf;
pf = &f;
pv = pf;
pf = (float *)pv;
2. Над указателями можно выполнять арифметические операции:
a. Сложение - (указатель + целое), вычитание – (указатель - целое)
<p> = <p> ± n*sizeof( тип), где <p> - значение указателя, n – целое. В общем случае добавление (вычитание) целого числа к указателю увеличивает (уменьшает) содержащийся в нем адрес на произведение этого целого числа на размер в байтах того объекта, на который этот указатель показывает.
Пусть р – указатель на целое и имеет значение 2000. Тогда в результате выполнения оператора р = р + 3; значение указателя р будет 2006.
b. Вычитание – (указатель - указатель)
Если р1 и р2 указатели на элементы одного и того же массива, то операция р1 – р2дает такой же результат, что и вычитание индексов соответствующих элементов массивов.
c. Приращение (увеличение или уменьшение): ++, --. То есть, указатель после каждого приращения будет указывать на следующий элемент базового типа. Это касается как положительного, так и отрицательного приращения.
int x, *px;
px = &x;
printf("\n px= %p\t++px= %p", px, ++px);
Результат: px= 9002:1000 ++px= 9002:1000
*р++; /*берется текущее значение указателя р*, затем адрес изменяется на количество байтов, отведенную под переменную базового типа*/
*р + 1; /*значение переменной из адреса р увеличивается на 1*/
*(р +1); /*значение переменной из адреса р + 1*/
Другие арифметические операции над указателями запрещены, например, нельзя сложить два указателя, умножит указатель на число и т.д.
3. Указатели можно сравнивать. Применимы все 6 операций сравнения: >, >=, <, <=, =, ==, !=
Например, если даны указатели p и q, то справедливо выражение: if(p<q) printf("р указывает на ячейку памяти с более низким адресом, чем q\n"); Обычно сравнение указателей используется, когда два или более указателей указывают на один объект, например массив (индекс элемента, на который указывает р, меньше индекса элемента, на который указывает q).
20.Константные выражения
В ряде случаев C++ требует, чтобы вычисляемое значение выражения было целочисленной константой. Это относится к границам массивов, размерам битовых полей, значениям инициализаторов элементов перечисления. Константные выражения представляют собой неизменяемые целочисленные значения. Они строятся на основе литералов, элементов перечисления (о них речь впереди), проинициализированных целочисленных констант, выражений, построенных на основе операции sizeof.
Константное выражение не меняет своего значения. Поэтому константное выражение не может быть именем переменной или выражением, которое включает имя переменной.
Константные выражения вычисляются на стадии трансляции, а потому в константном выражении не могут использоваться функции, объекты классов, указатели, ссылки, операция запятая и операция присваивания.
Константное выражение может состоять из литералов, имён констант, элементов перечисления (о них позже), может содержать символы арифметических операций, которые связывают константные выражения.
Основное назначение константного выражения в C++ - фиксация значений ограниченного множества значений, предназначенных для организации управленния процессом выполнения программы, задание предопределённых характеристик объектов (например, размер массива). Управление выполнением и характеристика размерности не требует особой точности. Органы управленния должны быть максимально простыми, количество элементов и длина в байтах задаются целочисленными значениями. Здесь нет проблем, связанных с точностью вычисления, здесь достаточно значений интегрального типа.
Значение константного выражения определяется уже на стадии трансляции, поскольку размерность массива и метка помеченного оператора в операторе выбора должны быть известны до начала выполнения программы. А это ещё один аргумент в пользу запрещения включения в константное выражение вызовов функций (на стадии трансляции нет возвращаемых значений).
По этой же причине константное выражение не может быть указателем или ссылкой (о ссылках - позже), поскольку всё, что связано с адресами, определяется лишь на этапе выполнения программы.
Константное выражение не может содержать операцию присваивания, операции инкрементации и декрементации.
А вот операции сравнения, арифметические операции, операция sizeof и, как ни странно, операция запятая не вызывают возражений транслятора (транслятор и считать умеет, и сравнивать, он и размеры определяет, а также понимает, какое значение следует присвоить выражению, содержащему символ операции запятая).