Структуры и другие формы данных 585
Во всех этих операциях участвовала всего лишь одна переменная типа структуры person, и каждая из функций для доступа к структуре применяла ее адрес. Первая функция передавала информацию изнутри себя вызывающей программе, вторая функция принимала информацию из вызывающей программы внутрь себя, а третья функция делала то и другое.
Теперь посмотрим, каким образом запрограммировать решение той же задачи с использованием структур как аргументов и возвращаемых значений. Во-первых, для передачи самой структуры необходимо применять аргумент person, а не Sperson. Тогда соответствующий формальный аргумент объявляется с типом struct namect, а не указателем на этот тип. Во-вторых, чтобы предоставить main() значения структуры, можно возвратить саму структуру. В листинге 14.9 показана версия программы без указателей.
Листинг 14.9. Программа names2.c

586 Глава 14

Эта версия дает тот же самый результат, что и предыдущая, но работает по-другому. Каждая из трех функций создает собственную копию структуры person, так что в программе задействованы четыре разные структуры, а не только одна.
Для примера рассмотрим функцию makeinfo(). В первой программе ей передавался адрес структуры person, и функция имела дело с действительными значениями person. Во второй версии программы создавалась новая структура по имени info. Значения, хранящиеся в person, копировались в info, и функция работала с копией. Следовательно, подсчитанное количество букв сохранялось в info, но не в person. Тем не менее, это исправляет механизм возврата. Строка в makeinfo()
return info;
объединяется со строкой в main()
person = makeinfo(person);
для копирования значений хранящихся внутри info, в person. Обратите внимание, что функция makeinfo() должна быть объявлена с типом struct namect, т.к. она возвращает структуру.
Структуры или указатели на структуры?
Предположим, что вам необходимо написать функцию, связанную со структурами. Должны ли вы использовать указатели на структуры в качестве аргументов или же типы структур для аргументов и возвращаемых значений? Каждый подход характеризуется сильными и слабыми сторонами.
Метод с применением указателей в аргументах обладает двумя достоинствами: он работает как в старых, так и в новых реализациях С и является быстрым; передается всего лишь один адрес. Недостаток в том, что данные менее защищены. Некоторые операции в вызываемой функции могут непреднамеренно воздействовать на данные в исходной структуре. Однако появившийся в ANSI С спецификатор const решает эту проблему. Например, если в функцию showinfo() из листинга 11.8 поместить код, который изменяет какой-то член структуры, то компилятор обнаружит это и сообщит об ошибке.
Одно из преимуществ передачи структур в качестве аргументов заключается в том, что функция имеет дело с копией исходных данных, что безопаснее, чем работать с исходными данными. Вдобавок стиль программирования становится более ясным.
Структуры и другие формы данных 587
Предположим, что вы определили следующий тип структуры:
struct vector {double х; double у;};
Вы хотите установить вектор ans в сумму векторов а и b. Вы могли бы написать функцию, передающую и возвращающую структуры, которая привела бы к следующему коду:
struct vector ans, a, b;
struct vector sum_vect(struct vector, struct vector);
ans = sum_vect(a,b);
Для инженера эта версия выглядит более естественной, чем версия с указателями, которая могла бы выглядеть так:
struct vector ans, a, b;
void sum_vect(const struct vector *, const struct vector *, struct vector *);
sum_vect(&a, &b, sans);
Кроме того, в версии с указателями пользователь должен помнить, каким аргументом должен быть представлен адрес суммы — первым или последним.
Два основных недостатка передачи структур связаны с тем, что старые реализации С могут не воспринимать такой код, а также с тем, что в этом случае неэкономно расходуется время и память. Особенно расточительно передавать крупные структуры в функцию, которая использует только один или два члена структуры. В этом случае имеет смысл передавать указатель или же требуемые члены как индивидуальные аргументы.
Обычно программисты применяют указатели на структуры в качестве аргументов функции из соображений эффективности, используя const, когда необходимо защитить данные от нежелательных изменений. Передача структур по значению чаще всего делается для структур небольших размеров.
Читать дальше