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

5.2. Указатели и аргументы функций

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

    swap(a, b)

где функция swap определена следующим образом:

  void swap(int x, int y)       /* НЕВЕРНО */
  {
      int temp;

      temp = x;
      x = y;
      y = temp;
  }

Поскольку swap получает лишь копии переменных a и b, она не может повлиять на переменные a и b той программы, которая к ней обратилась.

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

  swap(&a, &b);

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

  void swap(int *px, int *py) /* перестановка *px и *py */
  {
      int temp;

      temp = *px;
      *px = *py;
      *py = temp;
  }

Графически это выглядит следующим образом:


Рис. 3.

Аргументы-указатели позволяют функции осуществлять доступ к объектам вызвавшей ее программы и дают возможность изменить эти объекты. Рассмотрим, например, функцию getint, которая осуществляет ввод в свободном формате одного целого числа и его перевод из текстового предстваления в значение типа int. Функция getint должна возвращать значение полученного числа или сигнализировать значением EOF о конце файла, если входной поток исчерпан. Эти значения должны возвращаться по разным каналам, так как нельзя рассчитывать на то, что полученное в результате перевода число никогда не совпадет с EOF.

Одно из решений состоит в том, чтобы getint возвращала в качестве результата характеристику состояния файла (исчерпан или не исчерпан), а значение самого числа помещала согласно указателю, переданному ей в виде аргумента. Похожая схема действует и в функции scanf, которую мы рассмотрим в параграфе 7.4.

Показанный ниже цикл заполняет некоторый массив целыми числами, полученными с помощью getint.

    int n, array[SIZE], getint(int *);

    for (n = 0; n < SIZE && getint(&array[n]) != EOF; n++)
        ;

Результат каждого очередного обращения к getint посылается в array[n] и n увеличивается на единицу. Заметим, и это существенно, что функции getint передается адрес элемента array[n]. Если этого не сделать, у getint не будет способа вернуть в вызывающую программу переведенное целое число.

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

  #include <ctype.h>

  int getch(void);
  void ungetch(int);

  /* getint: читает целое число из ввода в *pn */
  int getint(int *pn)
  {
      int c, sign;

      while (isspace(c = getch()))
          ;    /* пропуск символов-разделителей */
      if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
          ungetch(c);    /* не число */
          return 0;
      }
      sign = (c == '-') ? -1 : 1;
      if (c == '+' || c == '-')
          c = getch();
      for (*pn = 0; isdigit(c); c = getch())
          *pn = 10 * *pn + (c - '0');
      *pn *= sign;
      if (c != EOF)
          ungetch(c);
      return c;
  }

Везде в getint под *pn подразумевается обычная переменная типа int. Функция ungetch вместе с getch (см. параграф 4.3) включена в программу, чтобы обеспечить возможность отослать назад лишний прочитанный символ.


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


Функция getint написана так, что знаки – или +, за которыми не следует цифра, она понимает как «правильное» представление нуля. Скорректируйте программу таким образом, чтобы в подобных случаях она возвращала прочитанный знак назад во входной поток.



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


Напишите функцию getfloat — аналог getint для чисел с плавающей точкой. Какой тип будет иметь результирующее значение, выдаваемое функцией getfloat?



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

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