основыкнигиwin/dos*nixготовоелирикагостиФОРУМПОИСК
Б.В. Керниган, Д.М. Ричи -- Язык C

4.1. Основные сведения

      Для начала давайте разработаем и составим программу печати каждой строки ввода, которая содержит определенную комбинацию символов. /Это -- специальный случай утилиты GREP системы "UNIX"/. Например, при поиске комбинации "THE" в наборе строк

     NOW IS THE TIME
     FOR ALL GOOD
     MEN TO COME TO THE AID
     OF THEIR PARTY

в качестве выхода получим

     NOW IS THE TIME
     MEN TO COME TO THE AID
     OF THEIR PARTY

основная схема выполнения задания четко разделяется на три части:

    WHILE (имеется еще строка)
    IF (строка содержит нужную комбинацию)
          вывод этой строки

      Конечно, возможно запрограммировать все действия в виде одной основной процедуры, но лучше использовать естественную структуру задачи и представить каждую часть в виде отдельной функции. С тремя маленькими кусками легче иметь дело, чем с одним большим, потому что отдельные не относящиеся к существу дела детали можно включить в функции и уменьшить возможность нежелательных взаимодействий. Кроме того, эти куски могут оказаться полезными сами по себе.
      "Пока имеется еще строка" -- это GETLINE, функция, которую мы запрограммировали в главе 1, а "вывод этой строки" -- это функция PRINTF, которую уже кто-то подготовил для нас. Это значит, что нам осталось только написать процедуру для определения, содержит ли строка данную комбинацию символов или нет. Мы можем решить эту проблему, позаимствовав разработку из PL/1: функция INDEX(S,т) возвращает позицию, или индекс, строки S, где начинается строка T, и -1, если S не содержит т . В качестве начальной позиции мы используем 0, а не 1, потому что в языке "C" массивы начинаются с позиции нуль. Когда нам в дальнейшем понадобится проверять на совпадение более сложные конструкции, нам придется заменить только функцию INDEX; остальная часть программы останется той же самой.
      После того, как мы потратили столько усилий на разработку, написание программы в деталях не представляет затруднений. ниже приводится целиком вся программа, так что вы можете видеть, как соединяются вместе отдельные части. Комбинация символов, по которой производится поиск, выступает пока в качестве символьной строки в аргументе функции INDEX, что не является самым общим механизмом. Мы скоро вернемся к обсуждению вопроса об инициализации символьных массивов и в главе 5 покажем, как сделать комбинацию символов параметром, которому присваивается значение в ходе выполнения программы. Программа также содержит новый вариант функции GETLINE; вам может оказаться полезным сравнить его с вариантом из главы 1.

 #DEFINE  MAXLINE  1000
 MAIN()  /* FIND ALL LINES MATCHING A PATTERN */
 {
      CHAR LINE[MAXLINE];
 
      WHILE (GETLINE(LINE, MAXLINE) > 0)
    IF (INDEX(LINE, "THE") >= 0)
       PRINTF("%S", LINE);
  }
 GETLINE(S, LIM) /* GET LINE INTO S, RETURN LENGTH */
  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);
  }
 
  INDEX(S,T) /* RETURN INDEX OF T IN S,-1 IF NONE */
  CHAR S[], 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 (T[K] == '\0')
       RETURN(I);
      }
      RETURN(-1);
  }

Каждая функция имеет вид имя (список аргументов, если они имеются) описания аргументов, если они имеются

  {
      описания и операторы , если они имеются
  }

      Как и указывается, некоторые части могут отсутствовать; минимальной функцией является

     DUMMY ()  { }

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

    RETURN (выражение)

      Вызывающая функция может игнорировать возвращаемое значение, если она этого пожелает. Более того, после RETURN может не быть вообще никакого выражения; в этом случае в вызывающую программу не передается никакого значения. Управление также возвращется в вызывающую программу без передачи какого-либо значения и в том случае, когда при выполнении мы "проваливаемся" на конец функции, достигая закрывающейся правой фигурной скобки. Eсли функция возвращает значение из одного места и не возвращает никакого значения из другого места, это не является незаконным, но может быть признаком каких-то неприятностей. В любом случае "значением" функции, которая не возвращает значения, несомненно будет мусор. Отладочная программа LINT проверяет такие ошибки.
      Механика компиляции и загрузки "C"-программ, расположенных в нескольких исходных файлах, меняется от системы к системе. В системе "UNIX", например, эту работу выполняет команда 'CC', упомянутая в главе 1. Предположим, что три функции находятся в трех различных файлах с именами MAIN.C, GETLINE.C и INDEX.C . Тогда команда

    CC MAIN.C GETLINE.C INDEX.C

компилирует эти три файла, помещает полученный настраиваемый объектный код в файлы MAIN.O, GETLINE.O и INDEX.O и загружает их всех в выполняемый файл, называемый A.OUT.
      Если имеется какая-то ошибка, скажем в MAIN.C, то этот файл можно перекомпилировать отдельно и загрузить вместе с предыдущими объектными файлами по команде

    CC MAIN.C GETLIN.O INDEX.O

      Команда 'CC' использует соглашение о наименовании с "" и "" для того, чтобы отличить исходные файлы от объектных.
      Упражнение 4-1.
      ----------------
      Составьте программу для функции RINDEX(S,T), которая возвращает позицию самого правого вхождения т в S и -1, если S не содержит T.

ПРЕДЫДУЩАЯ ЧАСТЬ
4. Функции и структура программ
СОДЕРЖАНИЕ СЛЕДУЮЩАЯ ЧАСТЬ
4.2. Функции, возвращающие нецелые значения