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

1.7. Функции

Функции в Си играют ту же роль, что и подпрограммы и функции в Фортране или процедуры и функции в Паскале. Функции дают удобный способ заключения некоторой части вычислений в черный ящик, который в дальнейшем можно использовать, не интересуясь его внутренним содержанием. Если функции организованы должным образом, то можно игнорировать то, как выполняется работа; достаточно знать что делается. Язык Си разработан таким образом, чтобы сделать использование функций легким, удобным и эффективным. Вам будут часто встречаться функции длиной всего в несколько строчек, вызываемые только один раз, и используемые c единственной целью — сделать фрагмент кода более ясным.

До сих пор мы пользовались готовыми функциями вроде printf, getchar и putchar, теперь настала пора написать несколько собственных функций. Поскольку в Си нет оператора воздедения в степень, такого как ** в Фортране, проиллюстрируем механизм определения функции на примере функции power(m, n), которая возводит целое число m в целую положительную степень n. Так значение power(2,5) равно 32. На самом деле для практического применения эта функция малопригодна, так как может вычислять лишь положительные степени небольших целых чисел, однако она вполне подойдет для учебного примера. (В стандартной библиотеке есть функция pow(x, y), вычисляющая xy.)

Итак, у нас есть функция power и использующая ее главная функция main, так что вся программа выглядит следующим образом:

  #inclue <stdio.h>

  int power (int m, int n);

  /* Тест функции power */
  main()
  {
      int i;

      for (i = 0; i < 10; ++i)
          printf("%d %d %d\n", i, power(2, i), power(-3, i));
      return 0;
  }
  
  /* Возведение base в степень n, n >= 0 */
  int power (int base, int n);
  {
      int i, p;

      p = 1;
      for (i = 1; i <= n; ++i)
          p = p * base;
      return p;
  }

Определение функции имеет следующий вид:

    тип-результата имя-функции (список-параметров)
    {
        объявления

        инструкции
    }

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

Функция power дважды вызывается в следующей строке функции main:

    printf("%d %d %d\n", i, power(2, i), power(-3, i));

При каждом вызове функции power передаются два аргумента, и каждый раз функция возвращает целое число, которое затем печатается в заданном формате. Внутри выражений вызов функции power (2, i) рассматривается как целое число, точно так же, как константа 2 или переменная i. (Не все функции в качестве результата возвращают целые значения; подробно об этом будет сказано в главе 4.)

В первой строке функцииpower

    int power(int base, int n)

указываются тип возвращаемого функцией значения, имя функции и типы параметров. Имена параметров являются локальными внутри power, и скрыты от других функций, так что применение тех же самых имен в других функциях не приведет к конфликтам. Последнее утверждение также справедливо для переменных i и p: переменная i в power никак не связана с переменной i в main.

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

Значение, вычисляемое функцией power, возвращается в функцию main с помощью инструкции return. За словом return может следовать любое выражение:

    return выражение;

Функция не обязательно возвращает какое-нибудь значение. Инструкция return без выражения просто передает управление в вызывающую функцию, не передавая ей никакого результата. То же самое происходит, если в процессе вычислений мы достигнем конца функции, обозначенного в тексте последней закрывающей фигурной скобкой. Кроме того, вызывающая функция может игнорировать возвращаемый результат.

Вы, вероятно, обратили внимание на инструкцию return в конце функции main. Поскольку main — обычная функция, она как и любая другая может вернуть значение тому, кто ее вызвал, — чаще всего сиситеме, в которой была запущена программа. Обычно возвращается нулевое значение, что говорит о нормальном завершении работы. Ненулевое значение сигнализирует о возникших проблемах или ошибочном завершении программы. До сих пор мы ради простоты не включали инструкцию return в функцию main, но с этого момента мы будем добавлять ее как напоминание о том, что программы должны сообщать операционной системе о причинах своего завершения.

Объявление

    int power(int m, int n);

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

соответствие имен параметров не требуется. Фактически в прототипе они могут быть произвольными или вообще отсутствовать, т.е. прототип можно было бы записать и так:

    int power(int, int);

Однако удачно подобранные имена поясняют программу, и мы будем часто этим пользоваться.


Историческая справка. Самые большие отличия ANSI-Си от более ранних версий языка как раз и заключаются в способах объявления и определения функций. В первой версии Си функцию power требовалось задавать в следующем виде:

  /* power - возводит base в степень n; n>=0 */
  /* Версия для старых версий языка Си         */
  power(base, n)
  int base, n;
  {
      int i, p;

      p = 1;
      for (i = 1; i <= n; ++i)
          p = p * base;
      return p;
  }

Здесь имена параметров перечислены в круглых скобках, а их типы заданы перед первой открывающей фигурной скобкой. В случае отсутствия указания о типе параметра, считается, что он имеет тип int. Тело функции не претерпело изменений.

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

    int power();

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

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



Упражнение 1-15


Перепишите программу преобразования температур, выделив само преобразование в отдельную функцию.



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

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