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

1.9. Массивы символов

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

while (есть еще строка)
    if (данная строка длиннее самой длинной из предыдущих)
        запомнить строку
        запомнить ee длину
напечатать самую длинную строку

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

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

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

Наконец, нам необходима главная программа, которая управляет функциями getline и copy. Вот как выглядит программа в целом:

  #include <stdio.h>
  #define  MAXLINE  1000  /* максимальный размер вводимой строки */
  
  int getline(char line[], int MAXLINE);
  void copy(char to[], char from[]);
  
  /* Печать самой длинной строки */
  main()
  {
      int len;               /* длина текущей строки */
      int max;  /* длина максимальной из просмотренных строк */
      char line[MAXLINE];    /* текущая строка */
      char longest[MAXLINE]; /* самая длинная строка */

      max = 0;
      while ((len = getline(line, MAXLINE)) > 0)
          if (len > max) {
              max = len;
              copy(longest, line);
          }
      if (max > 0) /* Если была хотя бы одна строка */
          printf("%s", longest);
      return 0;
  }

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

      for ( i = 0; i < lim-1 && (c = getchar()) != EOF && c != '\n'; ++i)
          s[i] = c;
      if (c == '\n') {
          s[i] = c;
          ++i;
      }
      s[i] = '\0';
      return i;
  }

  /* copy копирует строку из массива from в to */
  void copy(char to[], char from[])
  {
      int i;

      i = 0;
      while ((to[i] = from[i]) != '\0')
          ++i;
  }

Мы предполагаем, что функции getline и copy, объявленные в начале программы, находятся в том же файле, что и main.

Взаимодействие между функциями main и getline осуществляется через пару аргументов и возвращаемое значение. Аргументы функции getline объявлены в строке

    int getline(char s[], int lim)

Как мы видим, первый аргумент s — это массив, а второй, lim, — целое число. Размер массива указывается в его объявлении для резервирования памяти. В функции getline указывать длину массива s не требуется, так как его размер задан в функции main. Чтобы вернуть значение вызывающей программе, функция getline использует инструкцию return точно так же, как это делала функция power. В приведенной строке также указано, что getline возвращает значение типа int, но так тип int подразумевается по умолчанию, это указание можно опустить.

Одни функции возвращают результат, другие (такие, как copy) нужны только для выполнения определенных действий и не возвращают никаких значений. В качестве типа значения, возвращаемого функцией copy указано void. Это явно указывает, что никакого значения данная функция не возвращает.

Чтобы отметить конец строки символов, функция getline помещает символ '\0' (символ null, код которого равен нулю) в конец создаваемого массива. Это соглашение используется также языком Си: когда в программе встречается строковая константа вроде

    "Hello\n"

то компилятор создает массив символов, содержащий символы этой строки, и заканчивающийся символом '\0', который отмечает конец строки.


H e l l o \n \0

Спецификация формата %s в printf указывает, что соответствующий ей аргумент является строкой рассмотренного выше формата. Функция copy в своей работе также опирается на тот факт, что текстовая строка заканчивается символом '\0', который копируеся вместе с остальными символами.

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

Пользователь функции getline никак не может заранее узнать, насколько длинной окажется вводимая строка. Поэтому в getline включен контроль переполнения. В то же время пользователь функции copy уже знает (или может узнать), каков размер строк, так что мы предпочли не включать в эту функцию дополнительный контроль.


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


Перепишите функцию main предыдущей программы так, чтобы она могла печатать самую длинную строку без каких-либо ограничений на ее размер.



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


Напишите программу печати всех вводимых строк, содержащих более 80 символов.



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


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



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


Напишите функцию reverse (s), размещающую символы в строке s в обратном порядке. Примените ее при написании программы, которая будет менять порядок символов в каждой введенной строке.



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

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