Язык С


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


По-видимому самым общим типом массива в "C" является массив символов. Чтобы проиллюстрировать использование мас- сивов символов и обрабатывающих их функций, давайте напишем программу, которая читает набор строк и печатает самую длин- ную из них. Основная схема программы достаточно проста:

WHILE (имеется еще строка) IF (эта строка длиннее самой длинной из предыдущих) запомнить эту строку и ее длину напечатать самую длинную строку По этой схеме ясно, что программа естественным образом распадается на несколько частей. Одна часть читает новую строку, другая проверяет ее, третья запоминает, а остальные части программы управляют этим процессом. Поскольку все так прекрасно делится, было бы хорошо и написать программу соответсвующим образом. Давайте сначала напишем отдельную функцию GETLINE, которая будет извлекать следующую строку из файла ввода; это - обобщение функции GETCHAR. мы попытаемся сделать эту функцию по возможности более гибкой, чтобы она была полезной и в других ситуациях. Как минимум GETLINE должна передавать сигнал о возможном по- явлении конца файла; более общий полезный вариант мог бы пе- редавать длину строки или нуль, если встретится конец файла. нуль не может быть длиной строки, так как каждая строка со- держит по крайней мере один символ; даже строка, содержащая только символ новой строки, имеет длину 1. Когда мы находим строку, которая длиннее самой длинной из предыдущих, то ее надо где-то запомнить. Это наводит на мысль о другой функции, COPY , которая будет копировать но- вую строку в место хранения. Наконец, нам нужна основная программа для управления функциями GETLINE и COPY . Вот результат :

#DEFINE MAXLINE 1000 /* MAXIMUM INPUT LINE SIZE */ MAIN() /* FIND LONGEST LINE */ { INT LEN; /* CURRENT LINE LENGTH */ INT MAX; /* MAXIMUM LENGTH SEEN SO FAR */ CHAR LINE[MAXLINE]; /* CURRENT INPUT LINE */ CHAR SAVE[MAXLINE]; /* LONGEST LINE, SAVED */

MAX = 0; WHILE ((LEN = GETLINE(LINE, MAXLINE)) > 0) IF (LEN > MAX) { MAX = LEN; COPY(LINE, SAVE); } IF (MAX > 0) /* THERE WAS A LINE */ PRINTF("%S", SAVE); } GETLINE(S,LIM) /* GET LINE INTO S,RETURN LENGTH */ 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(S1, S2) /* COPY S1 TO S2; ASSUME S2 BIG ENOUGH */ CHAR S1[], S2[]; { INT I;

I = 0; WHILE ((S2[I] = S1[I] != '\0') ++I; }

Функция MAIN и GETLINE общаются как через пару аргумен- тов, так и через возвращаемое значение. аргументы GETLINE описаны в строках

CHAR S[]; INT LIM;

которые указывают, что первый аргумент является массивом, а второй - целым. Длина массива S не указана, так как она определена в MAIN . функция GETLINE использует оператор RETURN для пере- дачи значения назад в вызывающую программу точно так же, как это делала функция POWER. Одни функции возвращают некоторое нужное значение; другие, подобно COPY, используются из-за их действия и не возвращают никакого значения. Чтобы пометить конец строки символов, функция GETLINE помещает в конец создаваемого ей массива символ \0 /нулевой символ, значение которого равно нулю/. Это соглашение ис- пользуется также компилятором с языка "C": когда в "C" - программе встречается строчная константа типа

"HELLO\N"

то компилятор создает массив символов, содержащий символы этой строки, и заканчивает его символом \0, с тем чтобы фун- кции, подобные PRINTF, могли зафиксировать конец массива:

------------------------------------------- ! H ! E ! L ! L ! O ! \N ! \0 ! -------------------------------------------

Спецификация формата %S указывает, что PRINTF ожидает стро- ку, представленную в такой форме. Проанализировав функцию COPY, вы обнаружите, что и она опирается на тот факт, что ее входной аргумент оканчивается символом \0, и копирует этот символ в выходной аргумент S2. /Все это подразумевает, что символ \0 не является частью нормального текста/. Между прочим, стоит отметить, что даже в такой маленькой программе, как эта, возникает несколько неприятных организа- ционных проблем. Например, что должна делать MAIN, если она встретит строку, превышающую ее максимально возможный раз- мер? Функция GETLINE поступает разумно: при заполнении мас- сива она прекращает дальнейшее извлечение символов, даже ес- ли не встречает символа новой строки. Проверив полученную длину и последний символ, функция MAIN может установить, не была ли эта строка слишком длинной, и поступить затем, как она сочтет нужным. Ради краткости мы опустили эту проблему. Пользователь функции GETLINE никак не может заранее уз- нать, насколько длинной окажется вводимая строка. Поэтому в GETLINE включен контроль переполнения. в то же время пользо- ватель функции COPY уже знает /или может узнать/, каков раз- мер строк, так что мы предпочли не включать в эту функцию дополнительный контроль.

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

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

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

----------------- Напишите программу печати всех строк длиннее 80 симво- лов.

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

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

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

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




    Содержание раздела