Наше обсуждение указателей строится на рассмотрении связей между именами, aдреcaми и значениями переменных; дальше мы продолжим обсуждение этих вопросов.
При написании программы мы представляем себе переменную как объект, имеющий два атрибута: имя и значение. (Кроме указанных, существуют еще и другие атрибуты, например тип, но это уже другой вопрос). После компиляции программы и загрузки в память "с точки зрения машины" данная переменная имеет тоже два атрибута: адрес и значение. Адрес - это машинный вариант имени.
Во многих языках программирования адрес объекта скрыт от программиста и считается относящимся к уровню машины. В языке Си благодаря операции & мы имеем возможность узнать и использовать адрес переменной:
&bаrn - это адрес переменной bаrn.
Мы можем получить значение переменной, соответствующее данному имени,
Мы можем также получить значение переменной, исходя из ее адреса, при помощи операции *:
РИС. 9.6. Имена, адреса и величнны в системе с "байтовой адресацией" тина IBM PC.
Дано pbarn = &bаrn; тогда *pbarn - это величина, помещенная по адресу &bаrn. Хотя мы и можем напечатать адрес переменной для удовлетворения своего любопытства, это не основное применение операции &. Более важным является то, что наличие операций &, * и указателей позволяет обрабатывать адреса и их содержимое в символическом виде, чем мы и занимались в программе обмен3.
ИСПОЛЬЗОВАНИЕ НАШИХ ЗНАНИЙ О ФУНКЦИЯХ
Теперь, когда мы знаем о функциях немного больше, соберем вместе несколько поучительных примеров, но сначала решим, чем мы будет заниматься.
Что вы скажете насчет функции возведения в степень, которая дает возможность возводить 2 в 5-ю степень или 3 в 3-ю и т. д.? Во-первых, необходимо решить, что будет служить входом программы. Это понятно: Cи требуется знать число, возводимое в степень, и показатель степени. Достичь этого можно путем введения двух аргументов:
(Мы ограничились здесь целыми числами, а также тем предположением, что результат будет сравнительно невелик.)
Далее требуется решить, что будет выходом функции. Ответ, конечно, тоже очевиден. Выходом должно быть одно число, являющееся значением переменной answer. Мы можем реализовать это с помощью оператора
rеturn(answcr);
Теперь для получения требуемого результата выберем алгоритм:
установим переменную answer равной 1,
умножим answer на base столько раз, сколько указывает exp.
Возможно, не совсем ясно, как осуществить второй шаг, поэтому разобьем его дальше на более мелкие шаги:
умножим answer на base и уменьшим на 1, остановимся, когда exp станет равной 0.
Если значение exp равно, скажем 3, тогда использование такого алгоритма приведет к трем умножениям; поэтому данный способ кажется вполне разумным.
Очень хорошо. Выразим теперь этот алгоритм в виде программы на языке Си.
Теперь проверим ее работу с помощью драйвера.
Объединим указанные две функции, проведем компиляцию и выполним данную программу. Результаты оказываются следующими:
Итак, 2 в 3-й степени - это 8, а - 3 в 3-й равно -27. Пока все правильно. Но 4 в степени -2 равно 1/16, а не 1. А 5 в 10-й степени, если память нам не изменяет,- это 9 765 625. В чем дело? Во-первых, программа не предназначалась для обработки отрицательных степеней, поэтому она и не смогла справиться с этой задачей. Во-вторых, в нашей системе величины типа int не могут превосходить 65 535.
Можно расширить программу путем включения в нее обработки отрицательных степеней и использования чисел с плавающей точкой для представления переменных base и answer. В любом случае показатель степени должен выражаться целым числом, потому что это число выполняемых умножений; нельзя произвести 2,31 умножения.