ВІКІСТОРІНКА
Навигация:
Інформатика
Історія
Автоматизація
Адміністрування
Антропологія
Архітектура
Біологія
Будівництво
Бухгалтерія
Військова наука
Виробництво
Географія
Геологія
Господарство
Демографія
Екологія
Економіка
Електроніка
Енергетика
Журналістика
Кінематографія
Комп'ютеризація
Креслення
Кулінарія
Культура
Культура
Лінгвістика
Література
Лексикологія
Логіка
Маркетинг
Математика
Медицина
Менеджмент
Металургія
Метрологія
Мистецтво
Музика
Наукознавство
Освіта
Охорона Праці
Підприємництво
Педагогіка
Поліграфія
Право
Приладобудування
Програмування
Психологія
Радіозв'язок
Релігія
Риторика
Соціологія
Спорт
Стандартизація
Статистика
Технології
Торгівля
Транспорт
Фізіологія
Фізика
Філософія
Фінанси
Фармакологія


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

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

Проиллюстрирую создание строк на фрагментах кода с комментариями.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;

/*Строка - указатель на символ. В большинстве случаев для ее использования

потребуется выделить память.*/

str6=(char*) malloc(10);

free(str6);

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

Первый и самый очевидный способ присваивания строк – присваивание отдельных символов. Например,str1[0]=’H’;

str1[1]=’e’;

str1[2]=’l’;

str1[3]=’l’;

str1[4]=’o’;

str1[5]=’\0’;

Однако, это совершенно неудобно. Не зная о правильных способах, начинающие программисты часто «выдумывают» свои способы присваивания строк, конечно, неправильные. Приведу несколько примеров: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 указывает на строковый литерал, а не на его копию. Но, к сожалению, такой код тоже сработает:char* str; // Нет const

str="Hello";

Здесь мы имеем дело с наследством C, в котором отсутствовал const. Поэтому стандарт С++ разрешает такое присваивание. Что может иметь неприятные последствия:char* str; // Нет const

str="Hello";

str[1]=’u’;

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

str="Hello";

str[1]=’u’; //error: l-value specifies const object

Вопросы неправильного и рискованного присваивания строк мы рассмотрели. Пришла пора обсудить правильное присваивание или копирование строк.

Для копирования строк существуют несколько библиотечных функций, наиболее общеупотребительной из которых является функция char* strcpy(char* dest, const char* src)

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

strcpy(str1, "Hello");

strcpy(str2, str1);

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

Снизить риск такого развития событий способна функция char* strncpy(char* dest, const char* src, size_t count)

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

Никогда не забывайте контролировать используемую память!

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

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

Прототипы этих функций таковы:int stricmp(const char *string1, const char *string2);

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

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

Полагаю, вам не придет в голову сравнивать строки, используя операции ‘<’ и ‘>’.

Длина строки

Для вычисления длины строки используется функция 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. Все они очень похоже между собой. Функции из первой группы преобразуют строку в число (float, int или long) в зависимости от окончания. Функции из второй группы выполняют обратное преобразование. Должен заметить, что функции из второй группы (равно как и ранее упомянутая stricmp) не входят в стандарт С, однако они весьма удобны и доступны на некоторых платформах.

Прототипы функций из первой группы: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. Функции возвращают указатель на строку.ПРИМЕЧАНИЕ

При использовании этих функций не забывайте выделять память, достаточную для предоставления строкового предоставления числа. Например, максимальная длина десятичного строкового представления четырехбайтного беззнакового целого числа - 11 байт, включая нуль-терминатор ("4294967295").

Пример:char str1[5];

char str2[5];

char str3[5];

itoa(12, str1, 10); //str1=”12”

itoa(12, str1, 16); //str1=”C”

itoa(12, str1, 2); //str1=”1100”

Конкатенация (объединение) строк

Сначала простой вопрос – каков результат выполнения следующего кода:char str1[10]="Hello";

char str2[10]="World!";

char* str3;

str3=str1+str2;

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

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

Есть две специальные функции: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(str3, "%s%s%s", str1, str2, str3);

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

функции

memset (void*, int, size_t) - устанавливает n первых байтов в указанное значение;

strcat(char*, const char*) - добавляет одну строку к другой;

strchr(const char*, int) - ищет первое вхождение указанного символа в строке;

strcmp(const char*, const char*) - сравнивает две строки (0 - равны строки, отрц. - первая строка меньше второй, полож. первая строка больше второй);

strcpy(char*, const char*) - копирует одну строку в другую;

strcspn(const char*, const char*) - ищет первое вхождение одного из символов одной строки в другой (возвращается позиция);

strlen(const char*) - возвращает длину строки (без нулевого символа конца строки);

strncat(char*, const char*, size_t) - добавляет n символов одной строки к другой.

strncmp(const char*, const char*, size_t) - сравнивает n первых символов;

strncpy(char*, const char*, size_t) - копировать n первых символов одной строки в другую;

strpbrk(const char*, const char*) - ищет первое вхождение одного из символов одной строки в другой;

strrchr(const char*, int) - поиск символа с конца;

strspn(const char*, const char*) - поиск первого символа не входящего в указанную строку (возвращается номер первого символа);

strstr(const char*, const char*) - поиск первого вхождения подстроки;

strtok(char*, const char*) - возвращает следующий токен (элемент разбора).

Структуры. Работа со структурами. Примеры.

Структура является объединением простых переменных. Эти переменные могут иметь различные типы: int, float и т. д. (именно разнородностью типов переменных структуры отличаются от массивов, в которых все переменные должны иметь одинаковый тип). Переменные, входящие в состав структуры, называются полями структуры.

Для тех, кто изучает язык C++, структуры являются одной из составляющих главных концепций языка – объектов и классов. На самом деле синтаксис структуры фактически идентичен синтаксису класса. На практике отличие структуры от класса заключается в следующем: структуры в языке С++, как правило, используют в качестве объединения данных, а классы — в качестве объединения данных и функций. Таким образом, изучая структуры в языке С++, мы тем самым закладываем основы для понимания классов и объектов.

Простая структура

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

В программе PARTS определяется структура part и переменная part1 типа part. Затем полям переменной part присваиваются значения и выводятся на экран.1 // parts.срр - структура для хранения информации о деталях изделий

2 #include "iostream"

4 using namespace std;

6 struct part // объявление структуры

7 {

8 int modelnumber; // номер модели изделия

9 int partnumber; // номер детали

10 float cost; // стоимость детали

11 };

13 void main()

14 {

15 part part1; // определение структурной переменной

16 part1.modelnumber = 6244; // инициализация полей

17 part1.partnumber = 373; // переменной part1

18 part1.cost = 217.55F;

20 // вывод значений полей на экран

21 cout << "Модель " << part1.modelnumber;

22 cout << ", деталь " << part1.partnumber;

23 cout << ", стоимость $" << part1.cost << endl;

24 }

Результат работы программы выглядит следующим образом:

Модель 6244, деталь 373, цена $217.55

В программе PARTS присутствуют три основных аспекта работы со структурами: определение структуры, определение переменной типа этой структуры и доступ к полям структуры. Рассмотрим каждый из этих аспектов.

Определение структуры

Определение структуры в языке С++ задает ее внутреннюю организацию, описывая поля, входящие в состав структуры:struct part

{

int modelnumber;

int partnumber;

float cost;

};

Синтаксис определения структуры

Определение структуры в языке С++ начинается с ключевого слова struct. Затем следует имя структуры, в данном случае этим именем является part. Объявления полей структуры modelnumber, partnumber и cost заключены в фигурные скобки. После закрывающей фигурной скобки следует точка с запятой (;) – символ, означающий конец определения структуры. Обратите внимание на то, что использование точки с запятой после блока операторов при определении структуры отличает синтаксис структуры от синтаксиса других рассмотренных нами элементов про­граммы. Как мы видели, в циклах, ветвлениях и функциях блоки операторов тоже ограничивались фигурными скобками, однако точка с запятой после таких блоков не ставилась.

Смысл определения структуры

Определение структуры part необходимо для того, чтобы создавать на его основе переменные типа part. Само определение не создает никаких переменных; другими словами, не происходит ни выделения физической памяти, ни объявления переменной. В то же время определение обычной переменной предполагает выделение памяти под эту переменную. Таким образом, определение структуры фактически задает внутреннюю организацию структурных переменных после того, как они будут определены.

Определение структурной переменной

Первый оператор функции main() выглядит следующим образом:part part1;

Он представляет собой определение переменной part1, имеющей тип part. Определение переменной означает, что под эту переменную выделяется память.

Массивы структур. Особенности обработки. Примеры.

© 2013 wikipage.com.ua - Дякуємо за посилання на wikipage.com.ua | Контакти