netlib.narod.ru | < Назад | Оглавление | Далее > |
Поскольку в Си функции в качестве своих аргументов получают значения параметров, нет прямой возможности, находясь в вызванной функции, изменить переменную вызывающей функции. В программе сортировки нам понадобилась функция 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; }
Графически это выглядит следующим образом:
Аргументы-указатели позволяют функции осуществлять доступ к объектам вызвавшей ее программы и дают возможность изменить эти объекты. Рассмотрим, например, функцию 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 | < Назад | Оглавление | Далее > |