Помощничек
Главная | Обратная связь


Археология
Архитектура
Астрономия
Аудит
Биология
Ботаника
Бухгалтерский учёт
Войное дело
Генетика
География
Геология
Дизайн
Искусство
История
Кино
Кулинария
Культура
Литература
Математика
Медицина
Металлургия
Мифология
Музыка
Психология
Религия
Спорт
Строительство
Техника
Транспорт
Туризм
Усадьба
Физика
Фотография
Химия
Экология
Электричество
Электроника
Энергетика

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



ТЕМА 7. СТРОКИ, ПОТОКИ, ФАЙЛЫ.

Строки.

 

В С и С++ отсутствуют встроенные строковые типы в том смысле, в котором они есть в языках типа Basic и Pascal. И присущая этим языкам легкость оперирования строковыми переменными (присвоение, сравнение) в С недоступна. Что же такое строка в С?

Для начала разберемся, что такое строка в жизни. Очевидно, что строка – это последовательность символов. В С – как в жизни. С-строка — это последовательность символов. Как известно, последовательности в С представляются массивами или указателями.

Как известно:

- массив можно привести к указателю на его первый элемент, что неявно происходит при передаче массивов в функции, ожидающие указатели;

- информация о размере массива переданного таким образом в функцию теряется;

- в С не существует способа передать массив по значению с сохранением его размера;

- указателя на первый элемент массива достаточно для работы со всем массивом, при условии, что нам известна его длина.

То есть в С строка – это массив элементов типа char, ограниченный символом с кодом 0, называемом нуль-терминатором. Напомню, что c массивом элементов типа char связан указатель на char, поэтому С-строка– это еще и указатель типа char* на область памяти, заканчивающуюся символом с кодом 0.

 

Создание строк

char str1[10]; Строка - массив из 10 символов. Начальное значение символов не определено.
char str2[10]="Hello"; Используется инициализация. В первые 5 символов записывается “Hello”, в 6 – нуль-терминатор, значение трех последних не определено.
char str3[10]={'H', 'e', 'l', 'l', 'o', '\0'}; Эквивалентно предыдущему.
char str4[10]="Very long line"; Ошибка. Массив из 10 элементов нельзя инициировать более длинной последовательностью.
char str5[]="Very long line"; Компилятор автоматически определяет длину массива (в нашем случае 15) и инициализирует его последовательностью символов
char* str6; Строка - указатель на символ. В большинстве случаев для ее использования потребуется выделить память.

 

Присваивание строк

Примеры неправильного присваивания строк:

char str1[10], str2[10];

str1="Hello";

str2=str1;

Одна и та же ошибка в обоих операторах “=”, имя массива нельзя использовать в левой части оператора присваивания.

Эта ошибка относительно безопасна, так как приводит к сбою на этапе компиляции. Есть и гораздо более опасная ошибка.

char str1[10]= "Hello";

char* str2;

str2=str1;

str2[1]='u';

Этот код откомпилируется, но, возможно, содержит ошибку. Неправильно полагать, что в str2 теперь содержится копия str1. На самом деле этот указатель указывает не на копию, а на ту же самую строку. При любом изменении содержимого str2 изменяется str1. Однако если именно это и требуется, то все в порядке.

 

Еще один рискованный вариант присваивания указателей – присваивание их строковым литералам. Тип строкового литерала – const char*. Стандарт С++ разрешает присваивание без спецификации const. Что может иметь неприятные последствия:

char* str;

str="Hello";

str[3]=’p’;

str[4]=’!’;

Результат работы такой программы непредсказуем. Компилятор может разместить константы в памяти только для чтения, и попытка их изменить приведет к сбою. Поэтому всегда объявляйте указатели, в которые вы собираетесь записывать адреса строковых литералов как const char*.

 

Вопросы неправильного и рискованного присваивания строк мы рассмотрели. Теперь о правильном присваивании или копировании строк.

Первый и самый очевидный способ присваивания строк – присваивание отдельных символов. Например,

str1[0]=’H’;

str1[1]=’e’;

str1[2]=’l’;

str1[3]=’l’;

str1[4]=’o’;

str1[5]=’\0’;

Однако, это совершенно неудобно.

 

Для копирования строк существуют несколько библиотечных функций, наиболее общеупотребительной из которых является функция strcpy(библиотека string.h).

 

char* strcpy(char* dest, char* src)

 

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

 

char str1[10], str2[10];

strcpy(str1, "Hello");

strcpy(str2, str1);

 

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

Снизить риск такого развития событий способна функция

 

char* strncpy(char* dest, char* src, int count)

 

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

 

Сравнение строк

Для лексикографического сравнения строк используются функции strcmp и stricmp. Первая сравнивает строки с учетом регистра, вторая – без. Однако, все это относится только к латинице. Кириллические строки сравниваются только с учетом регистра. Прототипы этих функций таковы:

 

int stricmp(char *string1, char *string2);

int strcmp(char *string1, char *string2);

 

Обе функции возвращают число меньшее 0, если первая строка меньше второй, большее нуля если первая строка больше второй и 0, если строки лексикографически равны.

Следующие две функции сравнивают с учетом регистра и без не более size символов строки string1 и строки string2.

 

int strncmp(char *string1, char *string2, int size);

int strnicmp(char *string1, char *string2, int size);

 

Длина строки

Для вычисления длины строки используется функция

 

size_t strlen(const char *string);

 

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

 

for (i=0;i<strlen(str);i++) {работа со строкой, не изменяющая ее длину}

 

 

больше подойдет примерно такой код :

char len;

len=strlen(str);

for (i=0;i<len;i++) { работа со строкой, не изменяющая ее длину}

 

Преобразования строк

Зачастую требуется преобразовать число в строку и наоборот. Есть несколько способов сделать это.

Во-первых, можно использовать функции sprintf и sscanf. Например, так:

 

char str[50];

int i=15;

int j;

sprintf(str, "%d", i); // Записать в str строковое представление i

sscanf(str, "%d", &j); // Записать в j число, содержащееся в строке str

sprintf(str, "i=%d and j=%d", i, j);

// содержимое str: "i=15 and j=15"

 

 

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

Хотя sprintf и sscanf довольно удобны, у них есть несколько недостатков. Во-первых, они не всегда быстро работают, во-вторых, не типобезопасны. Например, если в строке формата вы укажите, что передаете два целых, а вместо этого передадите два double, ошибка обнаружится только при выполнении программы и найти ее причину будет не так-то просто.

 

В-третьих, доступно целое семейство функций atof, atoi, atol и itoa, ltoa(библиотека stdlib.h). Все они очень похоже между собой. Функции из первой группы преобразуют строку в число (float, int или long) в зависимости от окончания. Функции из второй группы выполняют обратное преобразование.

Прототипы функций из первой группы:

double atof(const char* string);

int atoi(const char* string);

long atol(const char* string);

 

Вторая группа:

char* itoa(int value, char* string, int radix);

char* ltoa(long value, char* string, int radix);

 

Функции из второй группы могут создавать строковое представление чисел в любой системе (по любому основанию) от 2 до 36. Основание передается в третьем параметре. Чтобы получить строковое представление числа в десятичной системе, передайте 10. Функции возвращают указатель на строку.

 

Объединение строк

Сначала простой вопрос – каков результат выполнения следующего кода:

 

char str1[10]="Hello";

char str2[10]="World!";

char* str3;

str3=str1+str2;

 

Если ответ – ошибка на этапе компиляции, материал изложенный в статье вы усвоили (или знали это раньше). Если же вы полагаете, что в str3 будет хранится строка "Hello world!", то вероятно, мои предыдущих объяснений оказалось недостаточно. Нельзя складывать указатели (и имена массивов).

Для объединения строк следует использовать функции.

Есть две специальные функции (библиотека string.h):

 

char* strcat(char* dest, const char* source)

char* strncat(char* dest, const char* source, size_t size)

 

Эти функции добавляют к строке, на которую указывает dest, символы из строки source. Первая версия добавляет все символы до нуль-терминатора, вторая – максимум size символов. Результирующая строка завершается нуль-терминатором.

Кроме того, можно воспользоваться общей функцией sprintf так:

 

char str1[]="Hello ";

char str2[]="world";

char str3[]="!";

char str4[13];

sprintf(str4, "%s%s%s", str1, str2, str3);

 

Этот вариант удобнее, если нужно объединить более двух строк. Однако к его недостаткам относится типонебезопасность.

 

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

Функция Прототип и краткое описание действий
strchr char *strchr(char *str, int c); Ищет в строке str первое вхождение символа с, возвращает указатель на первое вхождение.
strcspn int strcspn(char *str1, char *str2); Определяет длину первого сегмента строки str1, содержащего символы, не входящие в строку str2.
strspn int strspn(char *str1, char *str2); Определяет длину первого сегмента строки str1, содержащего только символы, входящие в строку str2.
strlwr char *strlwr(char *str); Преобразует символы верхнего регистра в строке в соответствующие символы нижнего регистра.
strupr char *strupr(char *str); Преобразует символы нижнего регистра в строке в соответствующие символы верхнего регистра.
strset char *strset(char *str, int c); Заполняет строку str символом с.
strnset char *strnset(char *str, int c, int kol); Заменяет первые kol символов строки str символом с.
strpbrk int strpbrk(char *str1, char *str2); Ищет в строке str1 первое появление любого из множества символов, входящих в строку str2.
strrchr char *strrchr(char *str, int c); Ищет в строке str последнее вхождение символа с.
strstr char *strstr(char *str1, char *str2); Ищет в строке str1 подстроки str2. Возвращает указатель на тот элемент в строке str1, с которого начинается подстрока str2.

Файлы и потоки.

 

 




Поиск по сайту:

©2015-2020 studopedya.ru Все права принадлежат авторам размещенных материалов.