Язык С

       

Указатели символов и функции


Строчная константа, как, например,

"I AM A STRING"

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

PRINTF ("HELLO, WORLD\N");

когда символьная строка, подобная этой, появляется в прог- рамме, то доступ к ней осуществляется с помощью указателя символов; функция PRINTF фактически получает указатель сим- вольного массива. Конечно, символьные массивы не обязаны быть только аргу- ментами функций. Если описать MESSAGE как

CHAR *MESSAGE;

то в результате оператора

MESSAGE = "NOW IS THE TIME";

переменная MESSAGE станет указателем на фактический массив символов. Это не копирование строки; здесь участвуют только указатели. в языке "C" не предусмотрены какие-либо операции для обработки всей строки символов как целого. Мы проиллюстрируем другие аспекты указателей и массивов, разбирая две полезные функции из стандартной библиотеки вво- да-вывода, которая будет рассмотрена в главе 7.

Первая функция - это STRCPY(S,T), которая копирует стро- ку т в строку S. Аргументы написаны именно в этом порядке по аналогии с операцией присваивания, когда для того, чтобы присвоить T к S обычно пишут

S = T

сначала приведем версию с массивами:

STRCPY(S, T) /* COPY T TO S */ CHAR S[], T[]; { INT I; I = 0; WHILE ((S[I] = T[I]) != '\0') I++; }



Для сопоставления ниже дается вариант STRCPY с указате- лями.

STRCPY(S, T) /* COPY T TO S; POINTER VERSION 1 */ CHAR *S, *T; { WHILE ((*S = *T) != '\0') { S++; T++; } }

Так как аргументы передаются по значению, функция STRCPY может использовать S и T так, как она пожелает. Здесь они с удобством полагаются указателями, которые передвигаются вдоль массивов, по одному символу за шаг, пока не будет ско- пирован в S завершающий в T символ \0. На практике функция STRCPY была бы записана не так, как мы показали выше. Вот вторая возможность:


STRCPY(S, T) /* COPY T TO S; POINTER VERSION 2 */ CHAR *S, *T; { WHILE ((*S++ = *T++) != '\0') ; }

Здесь увеличение S и T внесено в проверочную часть. Зна- чением *T++ является символ, на который указывал T до увели- чения; постфиксная операция ++ не изменяет T, пока этот сим- вол не будет извлечен. Точно так же этот символ помещается в старую позицию S, до того как S будет увеличено. Конечный результат заключается в том, что все символы, включая завер- шающий \0, копируются из T в S.

И как последнее сокращение мы опять отметим, что сравне- ние с \0 является излишним, так что функцию можно записать в виде

STRCPY(S, T) /* COPY T TO S; POINTER VERSION 3 */ CHAR *S, *T; { WHILE (*S++ = *T++) ; }

хотя с первого взгляда эта запись может показаться загадоч- ной, она дает значительное удобство. Этой идиомой следует овладеть уже хотя бы потому, что вы с ней будете часто вст- речаться в "C"-программах. Вторая функция - STRCMP(S, T), которая сравнивает сим- вольные строки S и т, возвращая отрицательное, нулевое или положительное значение в соответствии с тем, меньше, равно или больше лексикографически S, чем T. Возвращаемое значение получается в результате вычитания символов из первой пози- ции, в которой S и T не совпадают.

STRCMP(S, T) /* RETURN <0 IF S<T, 0 IF S==T, >0 IF S>T */ CHAR S[], T[]; { INT I;

I = 0; WHILE (S[I] == T[I]) IF (S[I++] == '\0') RETURN(0); RETURN(S[I]-T[I]); }

Вот версия STRCMP с указателями:

STRCMP(S, T) /* RETURN <0 IF S<T, 0 IF S==T, >0 IF S>T */ CHAR *S, *T; { FOR ( ; *S == *T; S++, T++) IF (*S == '\0') RETURN(0); RETURN(*S-*T); } так как ++ и -- могут быть как постфиксными, так и префиксными операциями, встречаются другие комбинации * и ++ и --, хотя и менее часто.

Например

*++P

увеличивает P до извлечения символа, на который указывает

P, а

*--P

сначала уменьшает P.

Упражнение 5-2

--------------- Напишите вариант с указателями функции STRCAT из главы 2: STRCAT(S, T) копирует строку T в конец S.

Упражнение 5-3

--------------- Напишите макрос для STRCPY.

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

-------------- Перепишите подходящие программы из предыдущих глав и уп- ражнений, используя указатели вместо индексации массивов. Хорошие возможности для этого предоставляют функции GETLINE /главы 1 и 4/, ATOI, ITOA и их варианты /главы 2, 3 и 4/, REVERSE /глава 3/, INDEX и GETOP /глава 4/.




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