Изучаем Си [Александр Борисович Крупник] (pdf) читать постранично, страница - 10

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]

4.2.
Листинг 4.2.

#include
main(){
int i,j;
for(i=0;i) и
влево ( x2) ? x1 : x2;
По сравнению с конструкцией, которую мы рассматривали
раньше
if(x1 > x2)
max=x1;
else
max=x2;
условное выражение более компактно, и хорошо смотрится
при записи в одну строчку.

95

Глава 5. Функции,
указатели, массивы
Функции и массивы
Мы уже научились передавать функции переменные (в том
случае, когда необходимо только читать их) и указатели (когда
нужно менять переменные, на которые настроен указатель). Но
как передать функции массив? Передать ей все элементы
массива или указатели на все элементы?
Ни то ни другое. Функции достаточно передать указатель на
нулевой элемент массива и число элементов в нем. Тогда она
сможет менять указатель в безопасных пределах и получит
полный доступ к любому элементу массива.
Посмотрим, например, как может выглядеть функция, которая
определяет максимальный элемент массива. Разумно
спроектировать ее так, чтобы она принимала указатель на
нулевой элемент массива и число элементов в нем, а
возвращала максимальное значение. Прототип функции будет
при этом таким:
int maxi(int *a, int n).
В листинге 5.1 показана программа, которая использует
функцию maxi() для нахождения максимального элемента
массива:
Листинг 5.1

#include
int maxi(int *, int);
int main(){
int dig[10]={5,3,2,4,6,7,11,17,0,13};
int m;
m=maxi(&dig[0],10);

96

printf("%d\n",m);
return 0;
}
int maxi(int *a,int n){
int i,max;
max=*a;
for(i=1;i max)
max=*(a+i);
return max;
}
В самом начале программы показан прототип функции, int
maxi(int *, int), сообщающий о том, что функция
принимает указатель на int и целое int, возвращает также
целое.
Возвращаемое функцией значение присваивается переменной
m: m=maxi(&dig[0],10). Как видим, функции передается
адрес нулевого элемента массива &dig[0] и число элементов
в нем (10). Попав внутрь функции, эти аргументы
превращаются в указатель a и целочисленную переменную n.
Далее переменной max присваивается значение нулевого
элемента массива: max=*a. Затем в цикле перебираются все
остальные элементы с номерами от 1 до 9. В строке
if(*(a+i)
>
max)сравнивается текущее значение
переменной max со значением элемента i (напомним, что
согласно правилам работы с указателями, a+i указывает на iй элемент массива, а раскрытие ссылки *(a+i) дает значение
этого элемента). Если текущий элемент массива больше max,
то он становится новым значением максимума: max=текущее
значение, то есть max=*(a+i). В конце концов, значение max
возвращается во внешний мир и выводится на экран.

97

Очень поучительно сравнить программу, показанную в
листинге 5.1 с программой из раздела «Массивы» второй
главы (листинг 2.4), также вычисляющей максимальное
значение в массиве, но без использования функций.
Программа, из листинга 2.4, как одноразовый стаканчик,
годится для решения единственной задачи: нахождения
максимального элемента массива dig[], состоящего из десяти
элементов. А программа, показанная в листинге 5.1 (вернее,
функция maxi()), уже способна вычислить максимальный
элемент в любом целочисленном массиве!
Задача 5.1 Подумайте, как можно сконструировать функцию,
которая возвращает не только максимальное значение, но и
номер наибольшего элемента в массиве.

Массивы и указатели
Выводя на экран содержимое массива (см. раздел «Строки и
символы» в главе 3), мы уже поняли, что функции printf()
можно вместо указателя на начало строки передать само имя
строки. Передача имени вместо указателя, оказывается,
возможна не только для строк, но и для любых массивов и
любых функций, принимающих указатели. Так, в программе из
листинга 5.1 можно было бы вместо
m=maxi(&dig[0],10)
написать просто m=maxi(dig,10).
Это значит, что компилятор рассматривает имя массива как
адрес его нулевого элемента. И он поступает с именем массива
так, как будто это указатель! Встретив какой-то элемент
массива, например arr[i], компилятор преобразует его по
правилам работы с указателями: *(arr + i). То есть, arr
— это как бы указатель, i — целочисленная переменная.
Сумма arr+i указывает на i-й элемент массива, а оператор
раскрытия ссылки * дает значение самого элемента. На
рис. 5.1 показан массив х, в котором хранятся три целых числа
— 13, 28 и 5, и некоторые комбинации имен элементов,
указателей и связанных с ними операторов & и *.

98

Рис. 5.1. Действия с именем массива и его элементами

Самая важная строчка на рисунке — предпоследняя. Она
показывает, что адрес нулевого элемента массива &(x[0])
равен имени массива x.
Преобразование x[0] в *x, показанное на рис. 5.1, может
навести на мысль, что имя массива — и есть указатель на его
нулевой элемент. Но это не так. Отличие имени массива от
указателя в том, что имя не может быть изменено. Пусть
имеется массив x[i]. Как мы теперь знаем, его нулевой
элемент равен *x, первый *(x+1) и т.д. Но если бы x был
настоящим указателем, его значение можно было бы

99

увеличить на единицу x=x+1 и тогда x указывал бы на первый
элемент массива. Ничего