netlib.narod.ru< Назад | Оглавление | Далее >

4.2. Функции, возвращающие значения с типом, отличным от int

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

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

#include <ctype.h>

/* atof: преобразование строки в число типа 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, а atof — функция, которая принимает один аргумент типа char[] и возвращает результат типа double.

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

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

    sum += atof(line)

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

    double atof();

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

Располагая соответствующим образом описанной функцией atof, мы можем написать функцию atoi, преобразующую строку символов в целое число, следующим образом:

/* atoi: преобразование строки s в целое число
         с использованием функции atof */
int atoi(char s[])
{
    double atof(char s[]);

    return (int)atof(s);
}

Обратите внимание на вид объявления и инструкции return. Значение выражения в инструкции

    return выражение;

перед тем, как оно будет возвращено в качестве результата, приводится к типу функции. Следовательно, поскольку функция atoi возвращает значение типа int, вычисленный функцией atof результат типа double в инструкции return автоматически преобразуется в тип int. При преобразовании возможна потеря информации, и некоторые компиляторы предупреждают об этом. Оператор приведения явно указывает на необходимость преобразования типа и подавляет любое предупреждающее сообщение.


Упражнение 4-2


Дополните функцию atof таким образом, чтобы она справлялась с числами вида 123.45e-6 в которых после мантиссы может стоять e (или E) с последующим порядком (возможно, со знаком).



netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz