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

4.1. Основные сведения о функциях

Для начала давайте создадим программу, печатающую те строки вводимого текста, в которых содержится некоторый «образец», заданный в виде строки символов. (Эта программа представляет собой частный случай программы grep системы UNIX.) Например, в результате поиска образца «ould» в строках текста

    Ah Love! could you and I with Fate conspire
    To grasp this sorry Scheme of Things entire,
    Would not we shatter it to bits -- and then
    Re-mould it nearer to the Heart's Desire!

мы получим

    Ah Love! could you and I with Fate conspire
    Would not we shatter it to bits -- and then
    Re-mould it nearer to the Heart's Desire!

Работа по поиску образца четко распадается на три этапа:

    while (существует еще строка)
        if (строка содержит образец)
            напечатать строку

Хотя все три составляющие процесса поиска можно поместить в функцию main, все же лучше сохранить приведенную структуру и каждую ее часть реализовать в виде отдельной функции. Легче иметь дело с тремя небольшими частями, чем с одной большой, поскольку, если несущественные особенности реализации скрыты в функциях, вероятность их нежелательного воздействия друг на друга минимальна. Кроме того, соответствующие части, оформленные в виде функций, могут оказаться полезными и в других программах.

Конструкция «while (существует еще строка)» уже была реализована в функции getline (см. главу 1), а блок «напечатать строку» можно реализовать с помощью готовой функции printf. Таким образом, нам остается перевести на Си только ту часть, которая определяет, входит ли заданный образец в строку.

Чтобы решить эту задачу, мы напишем функцию strindex(s, t), которая возвращает номер позиции (индекс) в строке s, где начинается текст совпадающий со строкой t, или –1, если совпадений со строкой t не обнаружено. Так как в Си нумерация элементов массива начинается с нуля, в качестве признака неудачного поиска выбрано отрицательное число –1. Если потом нам потребуется более сложное сравнение с образцом, мы просто заменим strindex на другую функцию, оставив при этом остальную часть программы без изменений. (Библиотечная функция strstr аналогична функции strindex и отличается от последней только тем, что возвращает не индекс, а указатель.)

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

#include <stdio.h>
#define MAXLINE 1000   /* максимальный размер вводимой строки */

int getline(char line[], int max);
int strindex(char source[], char searchfor[]);

char pattern[] = "ould"; /* образец для поиска */

/* Программа поиска строк, содержащих образец */
main()
{
    char line[MAXLINE];
    int found = 0;

    while (getline(line, MAXLINE) > 0)
        if (strindex(line, pattern) >= 0) {
            printf ("%s", line);
            found++;
        }
    return found;
}

/* getline: читает строку в s, возвращает длину */
int getline(char s[], int lim)
{
    int c,i;

    i = 0;
    while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
        s[i++] = c;
    if (c == '\n')
        s[i++] = c;
    s[i] = '\0';
    return i;
}

/* strindex: ищет строку t в строке s; возвращает место 
             строки t или -1, если образец не найден */
int strindex(char s[], char t[])
{
    int i, j, k;

    for (i = 0; s[i] != '\0'; i++) {
        for (j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
            ;
        if (k > 0 && t[k] == '\0')
        return i;
    }
    return -1;
}

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

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

Отдельные части определения могут отсутствовать, как в определении минимальной функции

    dummy() {}

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

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

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

    return выражение;

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

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

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

Механизмы компиляции и загрузки программ на Си, расположенных в нескольких исходных файлах, зависят от системы. В системе UNIX, например, эти работы выполняет упомянутая в главе 1 команда cc. Предположим, что три функции нашего последнего примера расположены в трех разных файлах: main.c, getline.c и strindex.c. Тогда команда

    cc main.c getline.c strindex.c

скомпилирует указанные файлы, поместив результат компиляции в файлы объектных модулей main.o, getline.o и strindex.o, и затем загрузит их в исполняемый файл a.out. Если обнаружилась ошибка, например в файле main.c, то его можно скомпилировать снова и результат скомпоновать с ранее полученными объектными файлами, выполнив следующую команду:

    cc main.c getline.o strindex.o

Команда cc использует стандартные расширения файлов «.c» и «.o», чтобы отличать исходные файлы от объектных.


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


Напишите функцию strindex(s, t), которая выдает позицию самого правого вхождения строки t в строку s или –1, если вхождения не обнаружено.



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

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