Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C_Kurs_Lekt / C_II_семестр / 08_Строки

.pdf
Скачиваний:
10
Добавлен:
13.02.2016
Размер:
186.17 Кб
Скачать

функции для работы со строками

1

СТРОКИ, ОБРАБОТКА СИМВОЛОВ

Строки в С представляют собой массивы символов, заканчивающиеся символом конца строки - нулем (записывается в виде управляющей последовательности '\0'). По положению нуль-символа определяется фактическая длина строки.

Например: ”Это строка” – строка, состоящая из 11 символов: {’Э’, ’т’, ’о’, ’ ’, ’с’, ’т’, ’р’, ’о’, ’к’, ’а’, ’\0’}. Память под сроки можно выделять как массивами, так и динамически, используя указатели.

Например: char s[20] - массив из 20 символов; char *s=”str1” – указатель на char (на символ, на строку) c инициализацией.

Особенность строк состоит в том, что компилятор может определить длину строки самостоятельно, используя символ конца строки. Поэтому, необходимо следить за тем, чтобы каждая строка заканчивалась нулем. В противном случае программа будет обрабатывать символы(байты) за пределами отведенного под строку места пока не встретит символ нуля.. Такая ошибка приводит слабопрогнозируемым, во многих случаях фатальным последствиям. Аналогичная ситуация может наблюдаться, если строка большей длины копируется в строку меньшей длины. В этом случае необходимо принудительно ограничить длину копируемого участка. Как и в случае с обычными массивами - имя строки является константным указателем на начало массива символов.

Рассмотрим некоторые примеры:

char s[11] = “OK”; - определение строки (массива символов), выделяется 11 байт из которых занято только три;

O K \0

Длину строки можно не задавать, если мы проводим инициализацию строки: char s[]={'И','Т','С','\0'}; - строка из 4-х символов;

char s[]={”ИТС”}; и char s[]=”ИТС”; - определения, эквивалентные вышерассмотренному; char s[]; - ошибка! Необходимо указывать длину строки или инициализировать.

Т.к. имя строки константный указатель – непопустима конструкция вида: char s[]={'И','Т','С','\0'}; s=”каф” , т.к. мы пытаемся присвоить указателю s адрес строковой-константы ”каф”.

Менять содержимое строки можно только поэлементно, например: s[0]=’к’; s[1]=’а’; s[2]=’ф’; В данном случае мы не меняем значение указателя s, а обращаемся к отдельным однобайтным участкам памяти *(s+0), *(s+1), *(s+2).

Многомерные символьные массивы организовываются добавлением необходимого количества индексов: Например: sNxM[3][10]; массив из трех строк длиною 10 символов; Имя массива «sNxM» указатель-константа.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

sNxM[0]

 

 

 

sNxM[1]

 

 

 

sNxM[2]

Самую левую размерность массива можно не указывать, если проводится инициализация:

sNxM[][20]= {“первая”, ”вторая”, ”3-я”}; число срок – 3 компиллятор определит сам, исходя из списка инициализации.

Недостаток такого ”статического” подхода заключается в том, что в каждой строке отведено место для 10 символов, а мы использовали только часть каждой строки.

Для более гибкого и эффективного использования памяти, можно воспользоваться указателями. Обратим внимание на то, что при определении указателя место для хранения строки символов не выделяется, это необходимо проводить отдельно.

Примеры:

char * sPtr; - указатель на char;

char * sPtr = “тест“; определение указателя и присваивание ему адреса строковой константы (но не значения). В этом случае мы можем обратиться к элементам строки только в режиме чтения (т.е. недопустимо sPtr[0] = ‘т’ – нельзя изменять строковый литерал); также мы можем перенастроить указатель на другой адрес в памяти, но при этом связь с исходной строкой у программы будет утеряна.

 

 

 

т

 

е

с

т

 

\0

sPtr

 

 

символьный литерал

 

Определение указателя не выделяет место под строку, поэтому недопустимо определение указателя со сле-

дующей инициализацией: char * sPtr = {‘т’, ’е’, ’с’, ’т’, ’\0’}.

Для работы со строкой в режиме чтения-записи необходимо выделить память и настроить на этот выделенный участок указатель: char * sPtr; sPtr = (char *) calloc(20, sizeof(char));. После этого допускаются присваивания типа: sPtr[0] = ‘т’; sPtr[1] =’е’; …

Можно определить многомерный массив через массив указателей: char *sPtr[]= {“первая строка”, ”вторая”, ”3-я”}; или

char *sPtr[3]= {“первая строка”, ”вторая”, ”3-я”}.

Имя массива указателей «sPtr» указатель-константа. А указатели sPtr[0], sPtr[1], sPtr[2] – переменные. Компилятор размещает в памяти три строковые константы (14 байт), (7 байт) и (4 байта), а их адреса становятся значе-

ниями элементов sPtr[0], sPtr[1], sPtr[2].

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

sPtr

 

sPtr[0]

 

п

е

р

в

а

я

 

с

т

р

о

к

а

\0

 

 

 

sPtr[1]

 

в

т

о

р

а

я

\0

 

 

 

 

 

 

 

 

 

 

sPtr[2]

 

3

-

я

\0

 

 

 

 

 

 

 

 

 

 

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

функции для работы со строками

2

Для ввода-вывода данных строки можно воспользоваться стандартной библиотекой ввода-вывода.

Прототип

 

Описание функции

int getchar (void)

 

Вводит следующий символ со стандартного устройства ввода и возвращает

 

 

его в формате целого.

char *gets (char *s)

 

Вводит символы со стандартного устройства ввода в массив s до тех пор,

 

 

пока не встретит символ новой строки или индикатор конца файла. После

 

 

этого к массиву добавляется ограничивающий символ NULL.

int putchar (int c)

 

Печать символа, хранящегося в с.

int puts (const char *s)

 

Печать строки s с последующим символом новая строка.

int printf(const char *format,. . .);

 

форматный вывод данных в стандартный выходной поток stdout

int scanf(const char *

for-

форматный ввод данных из стандартного входного потока stdin

mat,. ..);

 

 

int sprintf (char *s, const char *format,

Эквивалент функции printf за исключением того, что результат вывода

...)

 

запоминается в массиве s, а не отображается на экране.

int sscanf (char *s, const char * format,

Эквивалент функции scanf за исключением того, что ввод осуществляется

. . . )

 

из массива s, а не с клавиатуры.

char *fgets(char *s, int n, FILE

 

Ввод заданного количества символов из потока

*stream);

 

Считывает n – 1 символ и дописывает в строку ‘\0’

При вводе данных в строки необходимо тщательно следить за тем, чтобы не выйти за пределы отведенного места для строки и чтобы каждая строка завершалась символом-нулем. Поэтому вместо функции gets рекомендуется использовать fgets или scanf, так как они могут ограничить число вводимых символов. Однако при вводе, fgets будет читать символы до первого символа новой строки или признака конца файла, а scanf - пока не встретит пробельный символ (пробел, табуляция, новая строка) или признак конца файл, также в scanf мы не можем задать число вводимых символов переменым значением.

Пример:

char s[5]={‘\0’};

scanf(“%4s”, s); // считает первые 4 символа, если строка больше 4-х символов и допишет пятый – ‘\0’ fgets( s, 5, stdin); // считает первые (5-1) символа, если строка больше (5-1) символов и допишет пятый – ‘\0’

Библиотека обработки строк

Библиотека обработки строк содержит функции для выполнения операций со строковыми данными, для сравнения строк, для поиска символов и других строк в строке, для деления строки на лексемы (логические части) и определения длины строки. Если вы вызываете функции из библиотеки обработки строк, подключите заголовочный файл <string.h>.

Функции для выполнения операций над строками из библиотеки обработки строк

Прототип

Описание функции

char *strcpy (char *s1, const char *s2)

 

Копирует строку s2 в массив s1. Возвращает значение s1. Массив символов s1 должен иметь

 

достаточный размер, чтобы запомнить строку и ограничивающий символ NULL, который

 

также копируется.

char *strncpy (char *s1, const char *s2, size_t n)

 

Копирует не более чем n символов строки s2 в массив s1. Возвращает значение s1. Функция

 

strncpy эквивалентна strcpy за исключением того, что strncpy задает число символов, кото-

 

рые необходимо скопировать из строки в массив. Обратите внимание, что функция strncpy

 

не копирует ограничивающий символ NULL второго аргумента, если не выполнено следую-

 

щее условие: число копируемых символов превышает длину строки, по меньшей мере, на

 

единицу( n >= strlen(s2)+1). Если значение третьего аргумента (n) больше s2, то символы

 

NULL добавляются в массив до тех пор, пока общее число записанных символов не станет

 

равным числу, заданному в третьем аргументе.

char *strcat (char *s1, const char *s2)

 

Объединяет строку s2 со строкой массива s1. Первый символ строки s2 переписывает (пере-

 

бивает) символ NULL строки s1. Возвращает значение s1. Программист должен убедиться,

 

что массив, содержащий первую строку, достаточен по размерам для хранения обеих строк

 

и ограничивающего символа NULL, который копируется из второй строки.

char *strncat (char *s1, const char *s2, size_t n)

 

Объединяет не более чем n символов строки s2 со строкой массива s1. Первый символ строки

 

s2 переписывает символ NULL строки s1. Возвращает значение s1. . Ограничивающий символ

 

NULL добавляется к строке результата автоматически (если массив, содержащий первую

 

строку, достаточен по размерам для хранения обеих строк и ограничивающего символа

 

NULL).

 

Функции сравнения из библиотеки обработки строк

В этом разделе представлены функции сравнения строк strcmp и strncmp из библиотеки обработки строк.

 

 

 

Прототип

 

Описание функции

int strcmp (const char *s1, const char *s2)

 

 

Сравнивает строку s1 со строкой s2. Функция возвращаете, значение меньше 0

 

 

или больше 0, если s1 соответственно равна, меньше или больше s2.

int strncmp (const char *s1, const char *s2, size_t n)

 

 

Сравнивает до n символов строки s1 со строкой s2. Функция возвращает 0, зна-

 

 

чение меньше 0 или больше 0, если s1 соответственно равна, меньше или больше

 

 

чем s2.

Функция strcmp сравнивает символ за символом первый аргумент-строку со вторым аргументом-строкой. Функция возвращает 0, если строки равны, отрицательное значение, если первая строка меньше второй, и положи-

функции для работы со строками

3

тельное значение, если первая строка больше второй. Функция strncmp эквивалентна функции strcmp, за исключением того, что strncmp сравнивает до n символов в строках. Функция strncmp не сравнивает символы, идущие за символом NULL.

Все символы представлены в компьютере в виде числовых кодов; когда компьютер сравнивает две строки, он фактически сравнивает числовые коды символов этш строк.

В целях стандартизации представления символов большинство производителей компьютеров разрабатывают свои машины для работы с одной из двух популярных схем кодировки — ASCII или EBCDIC. ASCII — это аббре-

виатура «American Standard Code for Information Interchange» (Американский стандартный код для обмена информацией), a EBCDIC означает «Extended Binary Coded Decimal Interchange Code» (Расширенный двоично-десятичный код обмена информацией).

ASCII и EBCDIC называются кодами символов (character codes) или наборами символов (characters sets). Фак-

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

Функции поиска из библиотеки обработки строк

В этом разделе представлены функции библиотеки обработки строк, использующиеся для поиска в строках символов и других строк (подстрок). Функции strcspn и strspn возвращают тип size_t. Тип size_t определяется как целочисленный тип (является системно-зависимым синонимом либо для типа unsigned long, либо для типа unsigned int), возвращаемый операцией sizeof.

Прототип

 

Описание функции

char *strchr (const char *s, int c)

 

Находит позицию первого вхождения символа с в строку s. Если с найден, функция возвращает указатель на с в строке s. В противном случае возвращается указатель со значением NULL.

size t strcspn (const char *s1, const char *s2)

Определяет и возвращает длину начального сегмента строки s1, содержащего только те символы, которые не входят в строку s2.

size t strspn (const char *s1, const char *s2)

Определяет и возвращает длину начального сегмента строки s1, содержащего только те символы, которые входят в строку s2

char *strpbrk (const char *s1, const char *s2)

Находит в строке s1 позицию первого вхождения любого из символов строки s2. Если символ из строки s2 найден, функция возвращает указатель на этот символ в строке s1. В противном случае возвращается указатель со значением NULL

char *strrchr (const char *s, int c)

 

 

Находит позицию последнего вхождения символа с в строку s. Если с найден,

 

 

функция возвращает указатель на с в строке s. В противном случае возвращается

 

 

указатель со значением NULL.

char *strstr (const char *s1, const char *s2)

 

 

Находит позицию первого вхождения строки s2 в строку s1. Если подстрока найде-

 

 

на, возвращает указатель подстроки в строке s1. В противном случае возвращает-

 

 

ся указатель со значением NULL.

Прототип

 

Описание функции

char *strtok (char *s1, const char *s2)

 

 

Последовательный вызов функции выполняет разбиение строки s1 на лексемы (ло-

 

 

гические части, такие как слова в текстовой строке), разделенные символами, со-

 

 

держащимися в строке s2. При первом вызове функция получает в качестве аргу-

 

 

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

 

 

самой строки, в качестве первого аргумента передается NULL. При каждом вызове

 

 

возвращается указатель на текущую лексему строки s1. Если при очередном вызо-

 

 

ве функция находит, что лексем в строке не осталось, то возвращается NULL.

Функция strtok используется для разбиения строки на ряд лексем. Лексема — это последовательность символов, отделенная разделительными символами (обычно пробелами или знаками пунктуации). Например, в строке текста каждое слово можно рассматривать как лексему, а пробелы, отделяющие его от других слов, как разделительные символы.

Чтобы разбить строку на несколько лексем, требуется многократный вызов функции strtok (предполагаем, что строка содержит более одной лексемы). При первом вызове функция strtok получает два аргумента: строку, которую нужно разбить на лексемы, и строку, содержащую символы, использующиеся для разбиения. В программе,

приведенной ниже, оператор tokenPtr = strtok(string, " ");

присваивает tokenPtr значение указателя на первую лексему в строке string. Второй аргумент функции strtok " " означает, что лексемы в string отделяются пробелами. Функция strtok выполняет поиск первого символа в string, который не является разделительным символом (пробелом). С этого символа начинается первая лексема. Посл« этого функция ищет следующий разделительный символ в строке и заменяет его нулевым символом ('\0'). Этот символ завершает текущую лексему. Функция strtok запоминает значение указателя на символ, следующий сразу за найденной лексемой, и возвращает указательна текущую лексему.

/* Применение strtok */ #include <stdio.h> #include <string.h> main () {

char string[] = "This is a sentence with 7 tokens"; char *tokenPtr;

printf("%s\n%s\n\n%s\n", "The string to be tokenized is:", string, "The tokens are:");

функции для работы со строками

4

tokenPtr = strtok(string, " "); while (tokenPtr != NULL) { printf ("%s\n", tokenPtr); tokenPtr = strtok(NULL, " "); } return 0; }

The string to be tokenized is: This is a sentence with 7 tokens The tokens are:

This is a

sentence with

7 tokens

При последующих вызовах для продолжения разбиения той же строки функция strtok получает в качестве первого аргумента символ NULL. Аргумент NULL показывает, что при вызове strtok должна продолжить разбиение с того места строки string, которое было записано при последнем вызове функции. Если при очередном вызове strtok обнаруживается, что лексем уже не осталось, то функция возвращает NULL. Программа, приведенная выше, использует функцию strtok для разбиения на лексемы строки "This is a sentence with 7 tokens" ("Это предложение содержит 7 лексем"). Каждая лексема печатается отдельно. Отметьте, что strtok модифицирует входную строку и, следовательно, если строка будет использоваться в программе после обращения к функции strtok, то следует сделать копию исходной строки.

Функции памяти библиотеки обработки строк

Функции библиотеки обработки строк, представленные в этом разделе, упрощают выполнение операций с блоками памяти, сравнение блоков памяти и поиск в блоках памяти. Эти функции обращаются с блоками памяти, как с массивами символов и могут оперировать с любыми блоками данных. Далее в тексте, при обсуждении функций, термин "объект" обозначает блок данных.

Параметры-указатели для этих функций объявляются как void *. Мы знаем, что указатель любого типа данных может быть прямо присвоен указателю типа void *, и наоборот — указатель void * может прямо быть присвоен указателю на любой тип данных. Поэтому обсуждаемые функции могут получать в качестве параметра указатель на любой тип данных. Поскольку указатель типа void * не может быть разыменован (т.е. тип объекта, на который ссылается данный указатель, не может быть определен), каждая функция получает дополнительный аргумент, определяющий число символов (байтов), которое будет обрабатывать функция. Для простоты примеры этого раздела оперируют с массивами символов (блоками символов). Замечание: функции операций со строками, за исключением функции memmove, дают неопределенный результат, когда копирование происходит между частями одной и той же строки.

Прототип Описание функции

void *memcpy (void *s1, const void *s2, size_t n)

Копирует n символов из объекта, указываемого s2, в объект, указываемый s1. Функция возвращает указатель, ссылающийся на результирующий объект. Функция может получать указатель на любой тип объекта. Поведение этой функции не определено в том случае, если два объекта перекрываются в памяти, т.е. являются частями одного и того же объекта.

void *memсcpy (void *s1, const void *s2, int С, size_t n)

аналолгично memcpy, но копирует из s2, пока не встретится символ «С», включая его, но не более n символов из объекта, указываемого s2. Если символ «С» был скопирован, ф-я возвращает указатель на символ расположенный непосредственно за «С» в результирующей строке (s1). В противном случае функция возвращает NULL.

void *memmove (void *s1, const void *s2, size_t n)

Копирует n символов из объекта, указываемого s2, в объект, указываемый s1. Копирование выполняется последовательно: символы из объекта, указываемого s2, копируются во временный массив и затем из временного массива копируются в объект, указываемый s1. Функция возвращает указатель, ссылающийся на результирующий объект. Сначала функция копирует заданное число байтов из второго аргумента во временный массив, а затем копирует этот массив в первый аргумент. Такой способ позволяет копировать данные из одной части объекта в другую часть того же объекта.

void *memcmp (const void *s1, const void *s2, size_t n)

Сравнивает первые n символов объектов, указываемых s1 и s2. Функция возвращает значения 0, меньше 0 и больше 0, если s1 соответственно равен, меньше или больше чем s2.

void *memicmp (const void *s1, const void *s2, size_t n)

Аналогично memcmp, но сравнивает без учета регистра символов.

void *memchr (const void *s, int c, size_t n)

Выполняет поиск первого вхождения с (преобразованного в тип unsigned char)- в первых n символах объекта, указываемого s. Если с найден, возвращает указатель на с в объекте. В противном случае возвращает NULL.

void *memset (const void *s, int c, size_t n)

Копирует с (преобразованный в тип unsigned char) в первые n символов объекта, указываемого s. Возвращает указатель результата.

функции для работы со строками

5

 

Другие функции из библиотеки обработки строк

 

 

 

Прототип

 

Описание функции

int strerror (int errornum)

 

Устанавливает соответствие номера ошибки errornum полной текстовой

 

 

строке (зависящей от системы). Возвращает указатель на строку.

int strlen (const char *s)

 

Определяет длину строки s. Возвращает число символов, предшествующих

 

 

ограничивающему символу NULL (ограничивающий символ NULL в длину

 

 

строки не включен). .

Библиотека обработки символов включает в себя функций, выполняющих ряд полезных проверок и операций с символьными данными. Прототипы этих функций находятся в заголовочном файле <ctype.h>. Каждая функция получает в качестве аргумента символ — представляемый типом int — или индикатор EOF (конец файла). Операции с символами часто выполняются как с целыми числами, поскольку символ в С это однобайтовое целое, а EOF обычно имеет значение -1, а архитектура некоторых аппаратных средств не позволяет запоминать отрицательные значения в переменных типа char.

Прототип

Описание функции

int isdigit (int с)

Возвращает значение true, если с является цифрой, и 0 (false) в других случаях.

int isalpha (int c)

Возвращает значение true, если с является буквой, и 0 в других случаях.

int isalnura (int c)

Возвращает значение true, если с является цифрой или буквой, и 0 в других случаях.

int isxdigit (int c)

Возвращает значение true, если с является одним из символов шестнадцатеричного

 

формата, и 0 в других случаях

int islower (int c)

Возвращает значение true, если с является буквой нижнего регистра, и 0 в других

 

случаях.

int isupper (int c)

Возвращает значение true, если с является буквой верхнего регистра, и 0 в других

 

случаях.

int tolower (int c)

Если с является буквой верхнего регистра, то tolower возвращает с как букву нижнего

 

регистра. В других случаях tolower возвращает аргумент без изменений.

int toupper (int c)

Если с является буквой нижнего регистра, то toupper возвращает с как букву верхне-

 

го регистра. В других случаях toupper возвращает аргумент без изменений.

int isspace (int c)

Возвращает значение true, если с является пробельным символом: пробел (' '), новая

 

страница '\f), новая строка '\n'}, возврат каретки '\r'), горизонтальная табуляция '\t')

 

или вертикальная табуляция '\v'), - и 0 в других случаях.

int iscntrl (int c)

Возвращает значение true, если с является управляющим символом, и 0 в других

 

случаях.

int ispunct (int c)

Возвращает значение true, если с является отображаемым при печати символом, но

 

не относится к пробельным символам, цифрам или буквам. В других случаях функция

 

возвращает значение 0.

int isprint (int c)

Возвращает значение true, если с является отображаемым при печати символом,

 

включая символ пробела (' '), и 0 в других случаях.

int isgraph (int c)

Возвращает значение true, если с является отображаемым при печати символом, ис-

 

ключая символ пробела (' '), и 0 в других случаях.

 

Функции преобразования строк

Функции преобразования строк из библиотеки утилит общего назначения (stdlib). Эти функции преобразуют строки цифр в целые значения и значения с плавающей точкой. Обратите внимание на модификатор const в описании переменной nPtr в заголовке функции (читается справа налево: *nPtr является указателем на символьную константу»); const объявляет, что значение аргумента не будет изменяться.

Прототип

 

Описание функции

double atof (const char *nPtr)

 

Преобразует строку nPtr в тип double.

int atoi (const char *nPtr)

 

Преобразует строку nPtr в тип int.

long atol (const char *nPtr)

 

Преобразует строку nPtr в тип long int.

double strtod (const char *nPtr, char **endPtr)

 

Преобразует строку nPtr в тип double.

long strtol (const char *nPtr, char **endPtr, int base)

 

Преобразует строку nPtr в тип long.

unsigned long strtoul (const char *nPtr, char **endPtr,

int

Преобразует строку nPtr в тип unsigned long.

base)

 

 

функции для работы со строками

6

Строки как параметры функций.

Строки в качестве фактических параметров могут быть специфицированы либо как одномерные массивы типа char [ ], либо как указатели типа char *. В обоих случаях с помощью параметра в функцию передается адрес начала символьного массива, содержащего строку. В отличие от обычных массивов для параметров-строк нет необходимости явно указывать их длину. Признак '\0', размещаемый в конце каждой строки, позволяет всегда определить ее длину, точнее, позволяет перебирать символы строки и не выйти за ее пределы. Рассмотрим аналоги приведенных выше функций обработки строк и некоторые типовые примервы обработки строк

Функция вычисления длины строки. (в стандартной библиотеке ей соответствует функция strlen(): int len( char e[]) {

int m;

for (m=0; e[m]!='\0'; m++); return m; }

Следующий вариант той же функции явно реализует механизм работы с указателями: int len (char *s) {

int m;

for (m=0; *s++!='\0'; m++) return m; }

Для формального параметра-указателя s внутри функции выделяется участок памяти, куда записывается значение фактического параметра. Так как s не константа, то значение этого указателя может изменяться. Именно поэтому допустимо выражение s++.

Функция инвертирования строки-аргумента с параметром-массивом : void invert(char e[]) {

char s;

int i, j, m; /*m - номер позиции символа '\0' в строке e */ for (m=0; e[m] !='\0'; m++);

for (i=0, j=m-l; i<j; i++, j—) { s=e[i]; e[i]=e[j]; e[j]=s; } }

При выполнении функции invert() строка - фактический параметр, например, "сироп" превратится в строку "порис". При этом символ '\0' остается на своем месте в конце строки. Пример использования функции invert():

#include <stdio.h> void invert(char [ ]); void main( ) {

char ct[ ]="0123456789"; invert(ct); printf("\n%s",ct) ; }

Результат выполнения программы: 9876543210

Функция поиска в строке ближайшего слева вхождения другой строки (в стандартной библиотеке имеется подобная функция strstr() ):

/*Поиск строки ST2 в строке ST1 */ int index (char * ST1, char * ST2) {

int i, j, ml, m2;

for (m1=0; ST1[m1] !='\0'; m1++); /* Вычисляются m1 и m2 - длины строк */ for (m2=0; ST2[m2] !='\0'; m2++);

if (m2>ml) return -1;

for (i=0; i<=m1-m2; i++) {

for (j=0; j<m2; j++) if (ST2[j] !=ST1[i+j]) break; /*Цикл сравнивания */ if (j==m2) return i;

}

return -1; }

Функция index() возвращает номер позиции, начиная с которой SТ2 полностью совпадает с частью строки SТ1. Если строка SТ2 не входит в SТ1, то возвращается значение -1.

Пример обращения к функции index():

#include <stdio.h>

int index(char [], char []); void main() {

char C1[]="сумма масс", C2[]="ма", C3[]="ам"; printf("\nДля %s индекс=%d",C2,index(Cl,C2)); printf("\nДля %s индекс=%d",C3,index{Cl,C3)); }

Результат выполнения программы: Для ма индекс=3 Для ам индекс=-1

Функция сравнения строк. Для сравнения двух строк можно написать следующую функцию (в стандартной библиотеке имеется близкая к этой функция strcmp:

int row(char C1[], char C2[ ]) {

int i, m1, m2; /* ml,m2 - длины строк C1,C2 */ for (m1=0; *(C1+m1)!= '\0'; m1++);

for (m2=0; *(C2+m2)!= '\0'; m2++); if (ml!=m2) return -1;

for (i=0; i<ml; i++) if (*C1++ != *C2++) return (i+l); return 0; }

В теле функции обращение к элементам массивов-строк реализовано через разыменование указателей. Функция row() возвращает: значение -1, если длины строк-аргументов С1, С2 различны; 0 - если все символы строк совпадают. Если длины строк одинаковы, но символы не совпадают, то возвращается порядковый номер (слева) первых несовпадающих символов.

Функция соединения строк. Следующая функция позволяет "присоединить" к первой строке-аргументу вторую строку-аргумент (в стандартной библиотеке есть подобная функция strncat() ):

/* Соединение (конкатенация) двух строк: */ void conc(char *C1, char *C2) {

int i,m; /* m - длина 1-й строки */ for (m=0; *(C1+m)!='\0'; m++);

функции для работы со строками

7

for (i=0; *(C2+i)!='\0'; i++) *(C1+m+i)=*(C2+i) ; *(C1+m+i)='\0'; }

Результат возвращается как значение первого аргумента С1. Второй аргумент С2 не изменяется. Обратите внимание на то, что при использовании функции соnс() длина строки, заменяющей параметр С1, должна быть достаточной для приема результирующей строки.

Функция выделения подстроки. Для выделения из строки С1 фрагмента заданной длины (подстроки) можно предложить такую функцию:

void substr(char *C1, char *C2, int n, int k)

/* C1

- исходная строка, C2 - выделяемая подстрока, n - начало выделяемой подстроки,

k - длина выделяемой

подстроки */

{ int i,m;

/* m - длина исходной строки */

for

(m=0;

Cl[m]!='\0'; m++);

if (n<0 || n>m || k<0

|| k>m-n) { C2[0]='\0'; return; }

for

(i=n;

i<k+n; i++)

C2[i-n]=Cl[i-l];

C2[i-n]='\0';

 

return; }

 

 

Результат выполнения функции - строка С2[] из k символов, выделенных из строки С1[], начиная с символа, имеющего номер n. При неверном сочетании значений параметров возвращается пустая строка, использованная в качестве параметра С2.

Функция копирования содержимого строки. Так как в языке Си отсутствует оператор присваивания для строк, то полезно иметь специальную функцию, позволяющую "переносить" содержимое строки в другую строку (такая функция strcpy() есть в стандартной библиотеке, но она имеет другое возвращаемое значение):

/* Копирование содержимого строки C2 в C1 */

void copy(char *C1, char *C2) '/* C2 - оригинал, C1 - копия */ { int i ;

for (i=0; C2[i]!='\0'; i++) Cl[i]=C2[i]; Cl[i]='\0'; }

Другой вариант функции копирования строки: void copy(char C1[ ], char C2[ ]) {

int i=0; do {

C1[i] = C2[i]; } while (Cl[i++]!='\0'); }

В той же функции операция присваивания может быть перенесена в выражение-условие продолжения цикла. Ранги операций требуют заключения выражения-присваивания в скобки:

void copy(char *C1, char *C2) { int i=0;

while ((C1[i] = C2[i]) != '\0') i++; }

Так как ненулевое значение в выражении после while считается истинным, то явное сравнение с '\0' необязательно и возможно следующее упрощение функции:

void copy(char * C1, char * C2) { int i=0;

while (Cl[i] = C2[i]) i++; }

И, наконец, наиболее короткий вариант: void сору {char * C1, char * C2) {

while (*C1++ = *C2++); }

Резюме по строкам-параметрам. Часть из приведенных функций для работы со строками, а именно функции: конкатенации строк соnс(), инвертирования строки invert(), копирования одной строки в другую сору(), выделения подстроки substr(); предусматривают изменение объектов вызывающей программы. Это возможно и допустимо только потому, что параметрами являются указатели. Это либо имена массивов, либо указатели на строки. Как уже говорилось, параметры-указатели позволяют функции получить непосредственный доступ к объектам той программы, из которой функция вызвана. В приведенных определениях функций этот доступ осуществляется как с помощью индексированных переменных, так и с помощью разыменования указателей. На самом деле компилятор языка Си, встречая, например, такое обращение к элементу массива s[i], всегда заменяет его выражением *(s+i), т.е. указателем s со смещением i.

В заключение пример функции конкатенации строк, использующей библиотечную функцию strlen(), позволяющую вычислить длину строки-параметра.

Функция для сцепления (конкатенации) строк:

#include <string.h>

void concat(char * C1, char * C2) { int m, i=0;

m=strlen (C1);

while ((*(C1+m+i) = *(C2+i))!='\0') i++;

}