Читаем Язык программирования Си. Издание 3-е, исправленное полностью

В предыдущих примерах функции либо вообще не возвращали результирующих значений (void), либо возвращали значения типа int. А как быть, когда результат функции должен иметь другой тип? Многие вычислительные функции, как, например, sqrt, sin и cos, возвращают значения типа double; другие специальные функции могут выдавать значения еще каких-то типов. Чтобы проиллюстрировать, каким образом функция может возвратить нецелое значение, напишем функцию atof(s), которая переводит строку s в соответствующее число с плавающей точкой двойной точности. Функция atof представляет собой расширение функции atoi, две версии которой были рассмотрены в главах 2 и 3. Она имеет дело со знаком (которого может и не быть), с десятичной точкой, а также с целой и дробной частями, одна из которых может отсутствовать. Наша версия не является высококачественной программой преобразования вводимых чисел; такая программа потребовала бы заметно больше памяти. Функция atof входит в стандартную библиотеку программ: ее описание содержится в заголовочном файле ‹stdlib.h›.

Прежде всего отметим, что объявлять тип возвращаемого значения должна сама atof, так как этот тип не есть int. Указатель типа задается перед именем функции.

#include ‹ctype.h›

/*atof: преобразование строки s в double */

double atof (char s[])

{

 double val, power;

 int i, sign;

 for (i = 0; isspace(s[i]); i++)

  ; /* игнорирование левых символов-разделителей */

 sign = (s[i] == '-') ? -1 : 1;

 if (s[i] == '+' || s[i] == '-')

  i++;

 for (val = 0.0; isdigit(s[i]); i++)

  val = 10.0 * val + (s[i] - '0');

 if (s[i] == '.')

  i++;

 for (power = 1.0; isdigit(s[i]); i++) {

  val = 10.0 * val + (s.[i] - '0');

  power *= 10.0;

 }

 return sign * val / power;

}

Кроме того, важно, чтобы вызывающая программа знала, что atof возвращает нецелое значение. Один из способов обеспечить это - явно описать atof в вызывающей программе. Подобное описание демонстрируется ниже в программе простенького калькулятора (достаточного для проверки баланса чековой книжки), который каждую вводимую строку воспринимает как число, прибавляет его к текущей сумме и печатает ее новое значение.

#include ‹stdio.h›

#define MAXLINE 100

/* примитивный калькулятор */

main

{

 double sum, atof (char[]);

 char line[MAXLINE];

 int getline (char line[], int max);

 sum = 0;

 while (getline(line, MAXLINE) › 0)

  printf ("\t%g\n", sum += atof(line));

 return 0;

}

В объявлении

double sum, atof (char[]);

говорится, что sum - переменная типа double, a atof - функция, которая принимает один аргумент типа char[] и возвращает результат типа double.

Объявление и определение функции atof должны соответствовать друг другу. Если в одном исходном файле сама функция atof и обращение к ней в main имеют разные типы, то это несоответствие будет зафиксировано компилятором как ошибка. Но если функция atof была скомпилирована отдельно (что более вероятно), то несоответствие типов не будет обнаружено, и atof возвратит значение типа double, которое функция main воспримет как int, что приведет к бессмысленному результату.

Это последнее утверждение, вероятно, вызовет у вас удивление, поскольку ранее говорилось о необходимости соответствия объявлений и определений. Причина несоответствия, возможно, будет следствием того, что вообще отсутствует прототип функции, и функция неявно объявляется при первом своем появлении в выражении, как, например, в

sum += atof(line);

Если в выражении встретилось имя, нигде ранее не объявленное, за которым следует открывающая скобка, то такое имя по контексту считается именем функции, возвращающей результат типа int; при этом относительно ее аргументов ничего не предполагается. Если в объявлении функции аргументы не указаны, как в

double atof;

то и в этом случае считается, что ничего об аргументах atof не известно, и все проверки на соответствие ее параметров будут выключены. Предполагается, что такая специальная интерпретация пустого списка позволит новым компиляторам транслировать старые Си-программы. Но в новых программах пользоваться этим - не очень хорошая идея. Если у функции есть аргументы, опишите их, если их нет, используйте слово void.

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
97 этюдов для архитекторов программных систем
97 этюдов для архитекторов программных систем

Успешная карьера архитектора программного обеспечения требует хорошего владения как технической, так и деловой сторонами вопросов, связанных с проектированием архитектуры. В этой необычной книге ведущие архитекторы ПО со всего света обсуждают важные принципы разработки, выходящие далеко за пределы чисто технических вопросов.?Архитектор ПО выполняет роль посредника между командой разработчиков и бизнес-руководством компании, поэтому чтобы добиться успеха в этой профессии, необходимо не только овладеть различными технологиями, но и обеспечить работу над проектом в соответствии с бизнес-целями. В книге более 50 архитекторов рассказывают о том, что считают самым важным в своей работе, дают советы, как организовать общение с другими участниками проекта, как снизить сложность архитектуры, как оказывать поддержку разработчикам. Они щедро делятся множеством полезных идей и приемов, которые вынесли из своего многолетнего опыта. Авторы надеются, что книга станет источником вдохновения и руководством к действию для многих профессиональных программистов.

Билл де Ора , Майкл Хайгард , Нил Форд

Программирование, программы, базы данных / Базы данных / Программирование / Книги по IT
Программист-прагматик. Путь от подмастерья к мастеру
Программист-прагматик. Путь от подмастерья к мастеру

Находясь на переднем крае программирования, книга "Программист-прагматик. Путь от подмастерья к мастеру" абстрагируется от всевозрастающей специализации и технических тонкостей разработки программ на современном уровне, чтобы исследовать суть процесса – требования к работоспособной и поддерживаемой программе, приводящей пользователей в восторг. Книга охватывает различные темы – от личной ответственности и карьерного роста до архитектурных методик, придающих программам гибкость и простоту в адаптации и повторном использовании.Прочитав эту книгу, вы научитесь:Бороться с недостатками программного обеспечения;Избегать ловушек, связанных с дублированием знания;Создавать гибкие, динамичные и адаптируемые программы;Избегать программирования в расчете на совпадение;Защищать вашу программу при помощи контрактов, утверждений и исключений;Собирать реальные требования;Осуществлять безжалостное и эффективное тестирование;Приводить в восторг ваших пользователей;Формировать команды из программистов-прагматиков и с помощью автоматизации делать ваши разработки более точными.

А. Алексашин , Дэвид Томас , Эндрю Хант

Программирование / Книги по IT