14 Тип символ
Знаков тип данни
В C++ символният тип данни char е цяло число, тъй като променливите от този тип скриват кода на символа в кодовата таблица (ASCII). Размерът на паметта, разпределена за съхранение на обект от тип char, е 1 байт. Символните литерали (един или два знака) трябва да бъдат затворени в апостроф (единични кавички):
Използването на двойни кавички ще доведе до грешка. Имайте предвид обаче, че ако конзолата използва кодиране UTF-8, тогава само знаците от първата част на таблицата ASCII („asci“) ще бъдат обработени правилно, тъй като тя е включена в таблицата за кодиране UTF-8 без промени, включително размера, определен за съхраняване на знак, т.е. 1 байт. По време на свързването на програмата по-долу, компилаторът ще издаде предупреждение, че „B“: „многосимволна символна константа [-Wmultichar]“ и „имплицитно постоянно препълване на конверсия [-Woverflow]“.
Това означава, че символът 'B' не е еднобайтов знак. Разбира се, можете да стартирате програмата, но знакът "B" няма да бъде обработен правилно. За да разрешите този проблем, трябва да активирате локализацията и да използвате специалния широк символен тип wchar_t за работа със знаци. Ще обсъдим как да направите това по-долу. За да получите знак от клавиатурата, можете да използвате метода get() на класа istream:
Тъй като, както казахме, типът char е цяло число, не е необичайно да видите такъв трик за преобразуване на знак => номер:
Обяснява се просто. Кодът на знака '0' е 48, а кодът на символа '7' е 55. Разликата в кода дава цифрата 7, която имплицитно се преобразува в тип int. Извеждането на символи чрез техните кодове може да се извърши по следния начин:Програма 13.1
Тази програма използва явно преобразуване на типове. Специалните символни литерали саизходни последователности. Те се използват за описание на определени специални символи в низови литерали. Някои последователности за бягство:
Забележка. Вече сме използвали символа '\n' за нов ред при показване на матрици. Манипулаторът endl също превежда на нов ред, но в същото време изчиства изходния буфер (и следователно всички формати при използване на манипулатори). Следователно, когато трябва да преминете към нов ред и в същото време да запазите форматите, трябва да използвате '\n'.
C-низ като масив от знаци
C-низ в C++ е масив от знаци, където последният елемент е '\0' (нулев знак). Забележка. Да не се бърка със знака '0'. В ASCII кодовата таблица нулевият знак (иначе NULL ) е на първата позиция, а именно нула, оттук и името. Тази стойност е терминатор на ред. Знаковият масив не е низ, освен ако не е завършен с нула. Начинът за инициализиране на C-низ като масив не е удобен:
Можете да инициализирате C низ по по-прост начин, като го затворите в двойни кавички:
В този случай не е необходимо да добавяте нулев знак. Той ще бъде добавен имплицитно автоматично. Когато въвеждате масив от знаци от клавиатурата, нулевият знак също ще бъде добавен автоматично. Можете да използвате потока cin, за да получите C низ, така:
В този фрагмент константата buf определя размера на масива (включително нулевия знак). Възможно е да се ограничи броят на въведените знаци с помощта на манипулатора setw():
Потокът ще продължи да получава знаци, докато не се срещнезнак за празно пространство (те включват следното:самото пространство, \t , \v , \r , \n и \f ). В програмата символът за интервал ще се третира като нулев знак (т.е. краят на низа) и само част от низа, до първия интервал, ще бъде записана в масива от символи, а всичко останало ще бъде оставено на ред в потока.Програма 13.2
Вход и изход на C-низ. функции get() и getline().
Но какво ще стане, ако трябва да вземете не първата дума, а целия ред? За да прочетете низ, който има празни знаци, трябва да използвате функцията get(). Тази функция е метод на класа istream, така че се извиква като функция член на този клас: cin.get() . Нека поправим програмата 13.2:
Забележка. Когато използвате операцията за вмъкване " " и име на масив, C-низът се извежда така, сякаш използваме низова променлива, т.е. когато извеждате низ, не е необходимо да прибягвате до извеждане на символ по знак в цикъл, както се прави за C-масиви. Функцията get() чете целия низ, включително завършващия знак, но го оставя в потока. Крайният знак (нов ред) се заменя с нулев знак. Функцията get() приема два аргумента: името на масива от символи и неговия размер. Ако функцията се използва без аргументи, тогава символът ще бъде прочетен и премахнат от потока. Забележка. Обикновено функцията get() се използва без аргументи, ако е необходимо да се премахне завършващ знак от опашката на потока. Алтернатива на функцията get() е функцията getline(), която е по-лесна за използване:
Функцията има три аргумента. Две задължителни: името на масива и размера на прехвърления масив, като се вземе предвид знакът за край на реда. Третият аргумент (незадължителен) се използва за указване на завършващия знак. Ако няма трети аргумент, тогава се приема, че завършващият знак е '\0'. Функцията чете всички символи, докато не срещнезавършващ знак (или '\n', ако не е посочен завършващ знак като трети аргумент) или buf знаци (предмет на добавяне на завършващ знак), ако броят на входните знаци в низа е по-голям от посочения от buf. След това функцията чете завършващия знак, но не го оставя във входния поток (всички знаци, надвишаващи лимита на buf, също ще бъдат изтрити). За да бъдем по-точни, чете се знакът за нов ред, който се заменя със завършващия символ '\0' или char_delim.
Създаване на обект от клас низ и инициализиране
В C++ C низът е от тип const char*. Това означава, че C-низът е масив с фиксиран размер. За да работи с C-низ, STD предоставя голям набор от функции. Но въпреки това работата с C-низ е опасна и неудобна. Стандартната библиотека на C++ включва низ от класове на сериен контейнер, предназначен да работи с масиви от знаци. Този клас е по-безопасен за използване от C-string. Инструментариумът за клас низове е повече от достатъчен, за да избегнете необходимостта да прибягвате до функции за низове в стил C. В същото време функциите на класа могат да работят не само с екземпляри на клас, но и с низове на C. C-низовете се преобразуват автоматично в низове от тип string. (Обратното преобразуване не се извършва, но е възможно да се копират символи в символни C-масиви). За разлика от C низ, контейнерът за низ представя низ като динамичен масив. В низовете от тип string знакът в края не се добавя към масива, но може да се съдържа в масива като всеки друг знак. За да работи с контейнера за низове, стандартната библиотека предоставя пълен набор от функции, общи за всички контейнери. За да започнете да работите с класа низ, трябва да включите заглавния файл с директивата:
Това създава празен низ myStr. Обектите от низовия клас могат да бъдат инициализирани по различни начини.
Следното демонстрира използването на някои от методите за инициализация.Програма 13.3
Забележка. Не можете да инициализирате низ с един знак!
Вход и изход на обекти от клас string
Въвеждането и извеждането на низ от тип string с помощта на поточни обекти cin и cout ще се извършва точно по същия начин като въвеждане/извеждане на C-низ. За да въведете низ от тип string в неговата цялост, включително интервали, трябва да използвате функцията getline. Това не е методът на класа istream, който използвахме за C-низ, а глобална функция на класа низ, която може да се използва за получаване на обект от този клас. Синтаксисът за тази функция е:
Аргументи на функцията: is - обект на входен поток; myStr - обект от класа низ, където ще бъде поставен низът; char_delim - третият аргумент (незадължителен) се използва за указване на завършващия знак. Ако няма трети аргумент, тогава се приема, че завършващият знак е '\n'. Функцията чете целия низ със завършващ знак. Самият знак за нов ред се отхвърля и не се съхранява в променливата на низа. Освен това не се добавя нулев знак. Символът за нов ред завършва изпълнението на функцията, където и да е. Ако нулевият символ е в началото на низа, функцията ще върне празен низ. Разгледайте този случай: Програма 13.4
Локализация. Широки символни низове
За да работите с кодиране на знаци, което надвишава 8 бита (по-„широко“), е предоставен специален тип символ wchar_t (широк знак ). Размерът на този тип се определя от компилатора и платформата. Така че в API на Windows wchar_t има фиксиран размер от 16 бита (което не ви позволява да кодиратецелия набор от знаци на Unicode), докато в GNU/Linux е 32 бита. Преди да може да се използва широк символен низ, трябва да се зададе "локал", който определя в какво кодиране ще се предава широкият символ и какъв национален стандарт ще се използва за форматиране. За да направите това, трябва да включите директивата:
В самата програма трябва да създадете глобален локален обект, който съответства на локала на средата (кодиране и настройки, използвани в ОС). На членската функция locale() се предава низ - името на локала (за Linux е ru_RU.UTF-8), като аргумент:
За да работите с широки символи, има специални версии на типове и класове, които се използват с префикса "w": wstring, wcout, wcin и т.н. Литералът на широк символен низ трябва да има суфикс "L". Нека да разгледаме пример за използване на широк символен низ.Програма 13.5 Даден е низ G1, съдържащ както български, така и английски букви и символа G2. Пребройте общия брой знаци, равни на G2 в низ G1. Ако няма такива знаци, тогава докладвайте. Вземете нов низ, чиито знаци са написани в обратен ред.
Забележка. Методът find намира първия подниз (в този случай символ) в дадения низ и връща позицията на първия елемент от подниза.npos е константа на низовия клас. Значението на израза string::npos в този случай означава знак за край на низа. По-късно ще говорим по-подробно за методите на класа string.