Определение этой функции ограничено; она будет работать только с массивами типа int, содержащими 10 элементов. Более гибкий подход предполагает передачу во втором аргументе размера массива:
int sumlint * ar, int n) // более общий подход
{
int i;
int total = 0;
for ( i = 0; i < n; i++) // используются n элементов
total += ar [i]; // ar [i] - то же самое, что и *(ar + i)
return total;
}
Здесь первый параметр сообщает функции, где находится массив и какой тип данных он содержит, а второй параметр уведомляет функцию о том, сколько элементов имеется в массиве.
Есть еще один момент, который необходимо отметить касательно параметров функции. В контексте прототипа или заголовка определения функции, и только в этом контексте, вместо int * ar можно подставить int ar[]:
int sum (int ar[] , int n);
Массивы и указатели 385
Форма int * ar всегда означает, что ar является типом указателя на int. Форма int ar[] также означает, что ar — тип указателя на int, но лишь тогда, когда он применяется для объявления формальных параметров. Вторая форма напоминает читателю кода о том, что ar не только указывает на int, но указывает на значение int, которое представляет собой элемент массива.
НА ЗАМЕТКУ! Объявление параметров массива
Поскольку имя массива — это адрес его первого элемента, фактический аргумент в виде имени массива требует, чтобы соответствующий формальный аргумент был указателем. В этом и только в этом контексте С интерпретирует int ar[] как int * ar, т.е. ar является типом указателя на int. Поскольку в прототипах разрешено опускать имя, все четыре приведенных ниже прототипа эквивалентны: int sumlint *ar, int n); int sum(int *, int); int sumlint ar[], int n); int sum(int[], int);
В определениях функций имена опускать нельзя, поэтому следующие две формы определения эквивалентны:
int sumlint *ar, int n)
{
// здесь находится код
}
int sum(int ar[], int n);
{
// здесь находится код
}
Вы должны иметь возможность использовать любой из четырех показанных выше прототипов с любым из двух приведенных определений.
В листинге 10.10 показана программа, в которой применяется функция sum(). Чтобы отразить интересный факт, касающийся аргументов типа массива, в ней также выводится размер исходного массива и размер параметра функции, представляющего массив. (Если ваш компилятор не поддерживает спецификатор %zd, для вывода значений функции sizeof используйте спецификатор %u или, возможно, %lu.)
Листинг 10.10. Программа sum_arr1.c

386 Глава 10

Вывод в нашей системе имеет следующий вид:
Размер ar составляет 8 байтов.
Общая сумма элементов массива marbles равна 190.
Объем памяти, отведенной под массив marbles, составляет 40 байтов.
Обратите внимание, что размер массива marbles равен 40 байтов. Это имеет смысл, т.к. массив marbles содержит 10 значений типа int, каждое из которых занимает 4 байта, что в сумме составляет 40 байт. Но размер ar равен всего 8 байтов. Причина в том, что ar — это не сам массив, а указатель на первый элемент marbles. В нашей системе для хранения адресов применяются 8 байтов, поэтому размером переменной типа указателя будет 8 байтов. (В других системах может использоваться другое количество байтов.) Короче говоря, в листинге 10.10 имя marbles — это массив, ar — указатель на первый элемент массива marbles, а связь между массивами и указателями в языке С позволяет применять форму записи массива вместе с указателем ar.
Использование параметров типа указателей
Функция, работающая с массивом, должна знать, где начинать и где заканчивать свое действие. В функции sum() используется параметр типа указателя для идентификации начала массива и целочисленный параметр, отражающий количество элементов массива, которые нужно обработать. (Параметр типа указателя также описывает тип данных в массиве.) Но это не единственный способ сообщения функции того, что она должна знать. Другой способ описания массива предусматривает передачу функции двух указателей, первый из которых отмечает, где массив начинается (как и раньше), а второй — где он заканчивается. Этот подход иллюстрируется в листинге 10.11. Здесь также задействован тот факт, что параметр типа указателя является переменной, так что вместо применения индекса для сообщения о том, к какому элементу массива обращаться, в функции можно изменять значение самого указателя, заставляя его по очереди указывать на каждый элемент массива.
Читать дальше