Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Тело цикла можно ужать до одной строки:
total += *start++;
Унарные операции * и ++ имеют один и тот же приоритет, но ассоциацию справа налево. Это означает, что операция ++ применяется к start, а не к * start.
388 глава 10
Другими словами, инкрементируется указатель, а не значение, на'которое он указывает. Использование постфиксной формы (start++вместо++start) приведет к тому, что указатель не инкрементируется до тех пор, пока указываемое им значение не будет добавлено к total. Если бы в программе применялось выражение *++start, то сначала бы инкрементировался указатель, а затем использовалось бы значения, на которое он указывает. Однако если бы в программе было задействовано выражение (*start)++, то сначала использовалось бы значение start и затем инкрементировалось бы значение, а не указатель. Тогда указатель остался бы нацеленным на тот же самый элемент, но элемент содержал бы новое число. Хотя обычно применяется запись *start++, форма * (start++) более понятна. В листинге 10.12 демонстрируются особенности приоритетов.
Листинг 10.12. Программа order.с
Вот вывод, полученный в результате запуска программы:
*р1 = 100, *р2 = 100, *рЗ = 300
*р1++ = 100, *++р2 = 200, (*рЗ)++ = 300
*р1 = 200, *р2 = 200, *рЗ = 301
Единственной операцией, которая изменяет значение массива, является (*рЗ)++. Другие две операции приводят к тому, что p1 и р2 начинают указывать на следующий элемент массива.
Комментарии: указатели и массивы
Как вы уже видели, функции, которые обрабатывают массивы, в действительности используют указатели в качестве аргументов, но при написании функций обработки массивов вы должны сделать выбор между формой записи в виде массива и формой записи посредством указателей. Применение формы записи для массивов, как в листинге 10.10, делает более очевидным тот факт, что функция работает с массивами. Кроме того, такая форма записи более привычна для программистов, перешедших с других языков, таких как FORTRAN, Pascal, Modula-2 или BASIC. Другие программисты могут быть больше приучены к работе с указателями и посчитают более естественной форму записи с использованием указателей вроде показанной в листинге 10.11.
Массивы и указатели 389
Что касается языка С, то два выражения ar [1] и * (ar+ i ) по смыслу эквивалентны. Оба работают, если ar является именем массива, и оба работают, если ar — это переменная типа указателя. Тем не менее, выражение наподобие ar++ работает только в тех случаях, когда ar представляет собой переменную типа указателя.
Запись с применением указателей, особенно когда она сопровождается операцией инкремента, ближе к машинному языку, и некоторые компиляторы обеспечивают в таком случае более эффективный код. Однако многие программисты придерживаются мнения о том, что их основная задача заключается в обеспечении корректности и ясности кода, а его оптимизация должна быть оставлена компилятору.
Операции с указателями
Что же разрешено делать с указателями? Язык С предлагает множество базовых операций, которые можно выполнять над указателями, и в следующей программе демонстрируются восемь из имеющихся возможностей. Чтобы показать результаты каждой операции, программа выводит значение указателя (адрес, на который он указывает), значение, хранящееся по указанному адресу, и адрес самого указателя. (Если ваш компилятор не поддерживает спецификатор %р, попробуйте воспользоваться для вывода адресов спецификатором %u или, возможно, %lu. Если компилятор не поддерживает спецификатор %td, предназначенный для вывода разности адресов, попробуйте применить %d или, возможно, %ld.)
В листинге 10.13 представлены восемь базовых операций, которые можно выполнять над переменными типа указателя. В дополнение к этим операциям можно использовать операции отношений для сравнения указателей.
Листинг 10.13. Программа ptr ops.с
390 глава 10
Ниже показаны результаты выполнения этой программы в одной из систем:
значение указателя, разыменованный указатель, адрес указателя: ptr1 = 0x7fff5fbff8d0, *ptг1 =100, &ptrl = 0x7fff5fbff8с8
сложение значения int с указателем:
ptr1 + 4 = 0x7fff5fbff8e0, *(ptr4 + 3) = 400
значения после выполнения операции ptrl++:
ptr 1 = 0x7fff5fbff8d4, *ptrl =200, &ptrl = 0x7fff5fbff8c8
значения после выполнения операции —ptr2:
ptr2 = 0x7fff5fbff8d4, *ptr2 = 200, &ptr2 = 0x7fff5fbff8c0
восстановление исходных значений указателей: ptr 1 = 0x7fff5fbff8d0, ptr2 = 0x7fff5fbff8d8
вычитание одного указателя из другого:
ptr2 = 0x7fff5fbff8d8, ptrl = 0x7fff5fbff8d0, ptr2 - ptrl = 2
вычитание из указателя значения типа int: ptr3 = 0x7fff5fbff8е0, ptr3 - 2 = 0x7fff5fbff8d8
Ниже описаны базовые операции, которые можно выполнять с переменными типа указателей.
• Присваивание. Указателю можно присвоить адрес. Присваиваемым значением может быть, например, имя массива, переменная, которой предшествует операция взятия адреса (&), или другой указатель. В листинге 10.13 переменной ptrl присваивается адрес начала массива urn. Этим адресом оказался номер ячейки памяти 0x7f ff5fbf f8d0. Переменная ptr2 получает адрес третьего (последнего) элемента, urn [2]. Обратите внимание, что адрес должен быть совместим с типом указателя. Другими словами, вы не можете присваивать адрес значения double указателю на int, во всяком случае, не делая неосмотрительное приведение типа. Это правило требуют стандарты С99/С11.
• Нахождение значения (разыменование). Операция * дает значение, хранящееся в ячейке, на которую указывает указатель. Таким образом, первоначально *ptrl равно 100, т.е. значению, хранящемуся в ячейке 0x7fff5fbff8d0.
• Взятие адреса указателя. Подобно всем переменным, переменная типа указателя имеет адрес и значение. Операция & сообщает, где хранится сам указатель. В рассмотренном примерю ptrl хранится в ячейке 0x7fff5fbff 8с8. Содержимым этой ячейки памяти является 0x7fff5fbff8d0, т.е. адрес массива urn. В итоге &ptl - указатель на ptl, что, в свою очередь, представляет собой указатель на urn[0].
Массивы и указатели 391
• Добавление целого числа к указателю. С помощью операции + можно добавить целое число к указателю или указатель к целому числу. В любом случае целое число умножается на количество байтов в типе данных, на который указывает указатель, и результат добавляется к исходному адресу. Это делает выражение ptrl + 4 эквивалентным &urn[4]. Результат сложения не определен, если он находится за пределами массива, на который указывает исходный указатель; исключением будет адрес, следующий за последним элементом массива, который считается допустимым.
Читать дальшеИнтервал:
Закладка: