Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Введите число, соответствующее выбранному отелю:
1) Fairfield Arms 2) Hotel Olympic
3) Chertworthy Plaza 4) The Stockton
5) выход
5
Благодарим за использование и желаем успехов.
Кстати, эта программа сама по себе обладает рядом интересных особенностей. В частности, функции menu() и get nights() пропускают нечисловые данные, проверяя возвращаемое значение функции scanf() и применяя вызов scanf ("%*s") для пропуска следующего пробельного символа. Взгляните, как следующий фрагмент функции menu() производит проверку на предмет нечислового ввода и ввода числовых значений, выходящих за пределы установленного диапазона:
while ((status = scanf("%d", &code)) != 1 II (code <111 code > 5))
В этом фрагменте кода используется действующее в С правило о том, что логические выражения вычисляются слева направо и что вычисление прекращается, как только становится понятно, что выражение ложно. В данном случае значения code проверяются только после того, как будет установлено, что функция scanf() успешно прочитала целочисленное значение.
Назначение отдельных задач разным функциям способствует такому улучшению кода. На первом этапе написания программы функция menu() или getnights() может применять функцию scanf() без дополнительных функций проверки допустимости данных. Затем, когда базовая версия заработает, можно приступить к совершенствованию отдельных модулей.
Выяснение адресов: операция &
Одним из наиболее важных концепций языка С (и временами самой трудной для понимания) является указатель, который представляет собой переменную, используемую для хранения адреса. Вы уже видели, что функция scanf() работает с адресами
354 глава 9 аргументов. В общем случае любая функция С, которая изменяет значение в вызывающей функции без использования значения в return, применяет адреса. Далее мы рассмотрим функции, использующие адреса, и начнем с унарной операции &. (В следующей главе мы продолжим исследование и работу с указателями.)
Унарная операция & предоставляет адрес, по которому хранится переменная. Если pooh является именем переменной, то &pooh — адрес этой переменной. Об адресе можно думать как о ячейке в памяти. Пусть имеется следующий оператор:
pooh = 24;
Предположим, что адресом, по которому хранится переменная pooh, является 0В76. (В IBM PC адреса часто задаются в виде шестнадцатеричных значений.) Тогда оператор
printf("%d %p\n", pooh, &pooh); выведет следующий результат (%р — спецификатор для адресов):
24 0В76
В листинге 9.12 эта операция применяется, чтобы посмотреть, где хранятся переменные, которые имеют одно и то же имя, но используются в разных функциях.
Листинг 9.12. Программа loccheck.c
Для вывода адресов в листинге 9.12 указан формат %р из ANSI С. В нашей системе был получен следующий вывод:
Внутри main() pooh = 2 и &pooh = 0x7fff5fbff8e8 Внутри main() bah = 5 и &bah = 0x7fff5fbff8e4 Внутри mikado() pooh = 10 и &pooh = 0x7fff5fbff8b8 Внутри mikado() bah = 2 и &bah = 0x7ff f 5fbf f8bc
Способ представления адреса спецификатором %р варьируется между реализациями. Однако многие реализации вроде той, что применяется в этом примере, отображают адрес в шестнадцатеричной форме. Учитывая, что каждая шестнадцатеричная
Функции 355
цифра соответствует четырем битам, показанные адреса, состоящие из 12 цифр, соответствуют 40-битным адресам.
Что демонстрирует приведенный вывод? Во-первых, две переменные pooh имеют отличающиеся адреса. То же самое справедливо и для двух переменных bath. Таким образом, как было обещано ранее, компьютер рассматривает их как четыре разных переменных. Во-вторых, вызов mikado (pooh) передает значение (2) фактического аргумента (pooh из main()) формальному аргументу (bah из mikado()). Обратите внимание, что было передано просто значение. Обе переменные (pooh из main() и bah из mi kado()) сохраняют свою идентичность.
Второй аспект был отмечен особо из-за того, что так дело обстоит не во всех языках. Например, в FORTRAN подпрограмма воздействует на исходную переменную в вызывающей процедуре. Переменная подпрограммы может иметь другое имя, но адрес будет тем же. В языке С это не так. Каждая функция использует собственные переменные. Такой подход предпочтительнее, поскольку он предотвращает загадочное изменение исходной переменной вследствие какого-то побочного эффекта вызванной функции. Тем не менее, этот подход также может создавать определенные трудности, как будет показано в следующем разделе.
Изменение переменных в вызывающей функции
Временами необходимо внести изменения в переменные другой функции. Например, распространенная задача, связанная с сортировкой, предусматривает обмен значениями двух переменных. Предположим, что есть две переменных с именами х и у, и нужно, чтобы они обменялись значениями. Простая последовательность
х = у;
у = х;
проблему не решит, потому что к моменту достижения второй строки исходное значение х уже было заменено исходным значением у. Необходим дополнительный оператор для временного запоминания исходного значения х:
temp = х;
х = у;
у = temp;
Теперь, когда метод заработал, вы можете поместить его в функцию и создать драйвер для ее тестирования. Чтобы прояснить, какая переменная принадлежит main(), а какая — interchange(), в листинге 9.13 функция main() имеет дело с переменными х и у, a interchange() — с переменными и и v.
Листинг9.13. Программа swapl.c
356 глава 9 void interchange(int u, int v) /* определение функции */
{
int temp;
temp = u; u = v; v = temp;
)
Выполнение этой программы дает следующие результаты:
Первоначально х = 5 и у = 10.
Теперь х = 5 и у = 10.
Как видите, значения не поменялись. Чтобы посмотреть, что именно пошло не так, давайте добавим в функцию interchange() несколько операторов вывода (листинг 9.14).
Листинг 9.14. Программа swap2.c
Вот новый вывод:
Первоначально х = 5 и у = 10.
Первоначально и = 5 и v = 10.
Теперь и = 10 и v = 5.
Теперь х = 5 и у = 10.
С функцией interchange() все в порядке; она меняет местами значения и и v. Проблема возникает при передаче результатов в main(). Как было указано, в interchange() применяются переменные, отличающиеся от используемых в main(), так что обмен значениями между и и v не влияет на переменные хну. Может быть, каким-то образом применить return?
Что же, функцию interchange() можно было бы завершить строкой
return(и);
Функции 357
а затем заменить ее вызов в main() следующим образом:
х = interchange(х,у);
Это изменение приводит к тому, что х получает новое значение, но значение у остается незатронутым. С помощью return обратно в вызывающую функцию можно отправлять только одно значение, а нам нужно передать два значения. Но все-таки это можно сделать! Понадобится только воспользоваться указателями.
Читать дальшеИнтервал:
Закладка: