Как работает строка. Функции вывода строк. Какие операторы можно использовать с объектами класса string
В современном стандарте C++ определен класс с функциями и свойствами (переменными) для организации работы со строками (в классическом языке C строк как таковых нет, есть лишь массивы символов char):
#include
#include#include
Для работы со строками также нужно подключить стандартный namespace:
Using namespace std;
В противном случае придётся везде указывать описатель класса std::string вместо string .
Ниже приводится пример программы, работающей со string (в старых си-совместимых компиляторах не работает!):
#include
Основные возможности, которыми обладает класс string:
- инициализация массивом символов (строкой встроенного типа) или другим объектом типа string . Встроенный тип не обладает второй возможностью;
- копирование одной строки в другую. Для встроенного типа приходится использовать функцию strcpy() ;
- доступ к отдельным символам строки для чтения и записи. Во встроенном массиве для этого применяется операция взятия индекса или косвенная адресация с помощью указателя;
- сравнение двух строк на равенство. Для встроенного типа используются функции семейства strcmp() ;
- конкатенация (сцепление) двух строк, дающая результат либо как третью строку, либо вместо одной из исходных. Для встроенного типа применяется функция strcat() , однако чтобы получить результат в новой строке, необходимо последовательно задействовать функции strcpy() и strcat() , а также позаботиться о выделении памяти;
- встроенные средства определения длины строки (функции-члены класса size() и l ength()). Узнать длину строки встроенного типа можно только вычислением с помощью функции strlen() ;
- возможность узнать, пуста ли строка.
Рассмотрим эти базовые возможности более подробно.
Инициализация строк при описании и длина строки (не включая завершающий нуль-терминатор):
String st("Моя строка\n"); cout << "Длина " << st << ": " << st.size() << " символов, включая символ новой строки\n";
Строка может быть задана и пустой:
String st2;
Для проверки того, пуста ли строка , можно сравнить ее длину с 0:
If (! st.size()) // пустая
или применить метод empty() , возвращающий true для пустой строки и false для непустой:
If (st.empty()) // пустая
Третья форма создания строки инициализирует объект типа string другим объектом того же типа:
String st3(st);
Строка st3 инициализируется строкой st . Как мы можем убедиться, что эти строки совпадают ? Воспользуемся оператором сравнения (==):
If (st == st3) // инициализация сработала
Как скопировать одну строку в другую ? С помощью обычной операции присваивания:
St2 = st3; // копируем st3 в st2
Для сцепления строк используется операция сложения (+) или операция сложения с присваиванием (+=). Пусть даны две строки:
String s1("hello, "); string s2("world\n");
Мы можем получить третью строку, состоящую из конкатенации первых двух, таким образом:
String s3 = s1 + s2;
Если же мы хотим добавить s2 в конец s1 , мы должны написать:
S1 += s2;
Операция сложения может сцеплять объекты класса string не только между собой, но и со строками встроенного типа. Можно переписать пример, приведенный выше, так, чтобы специальные символы и знаки препинания представлялись встроенным типом char * , а значимые слова – объектами класса string:
Const char *pc = ", "; string s1("hello"); string s2("world"); string s3 = s1 + pc + s2 + "\n"; cout << endl << s3;
Подобные выражения работают потому, что компилятор "знает", как автоматически преобразовывать объекты встроенного типа в объекты класса string . Возможно и простое присваивание встроенной строки объекту string:
String s1; const char *pc = "a character array"; s1 = pc; // правильно
Обратное преобразование при этом не работает . Попытка выполнить следующую инициализацию строки встроенного типа вызовет ошибку компиляции:
Char *str = s1; // ошибка компиляции
Чтобы осуществить такое преобразование, необходимо явно вызвать функцию-член с названием c_str() ("строка Си"):
Const char *str = s1.c_str();
Функция c_str() возвращает указатель на символьный массив, содержащий строку объекта string в том виде, в каком она находилась бы во встроенном строковом типе. Ключевое слово const здесь предотвращает "опасную" в современных визуальных средах возможность непосредственной модификации содержимого объекта через указатель.
К отдельным символам объекта типа string , как и встроенного типа, можно обращаться с помощью операции взятия индекса. Вот, например, фрагмент кода, заменяющего все точки символами подчеркивания:
String str("www.disney.com"); int size = str.size(); for (int i = 0; i < size; i++) if (str[i] == ".") str[ i ] = "_"; cout << str;
Replace(str.begin(), str.end(), ".", "_");
Правда, здесь использован не метод replace класса string , а одноимённый алгоритм:
#include
Поскольку объект string ведет себя как контейнер, к нему могут применяться и другие алгоритмы. Это позволяет решать задачи, не решаемые напрямую функциями класса string .
Ниже приводится краткое описание основных операторов и функций класса string , ссылки в таблице ведут к русскоязычным описаниям в интернете. Более полный список возможностей класса string можно получить, например, в Википедии или на сайте cplusplus.com .
Задание символов в строке |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
operator= |
присваивает значения строке |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assign |
назначает символы строке |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Доступ к отдельным символам |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
at |
получение указанного символа с проверкой выхода индекса за границы |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
operator |
получение указанного символа |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
front |
получение первого символа |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
back |
получение последнего символа |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data |
возвращает указатель на первый символ строки |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
c_str |
возвращает немодифицируемый массив символов С , содержащий символы строки |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Проверка на вместимость строки |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
empty |
проверяет, является ли строка пустой |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size
|
возвращает количество символов в строке |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
max_size |
возвращает максимальное количество символов |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
reserve |
резервирует место под хранение |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Операции над строкой |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
clear |
очищает содержимое строки |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
insert |
вставка символов |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
erase |
удаление символов |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
push_back |
добавление символа в конец строки |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pop_back |
удаляет последний символ |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
append |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
operator+= |
добавляет символы в конец строки |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
compare |
сравнивает две строки |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
replace |
заменяет каждое вхождение указанного символа |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
substr |
возвращает подстроку |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
copy |
копирует символы |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
resize |
изменяет количество хранимых символов |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
34
--- Руководство по C# --- Строки С точки зрения регулярного программирования строковый тип данных string относится к числу самых важных в C#. Этот тип определяет и поддерживает символьные строки. В целом ряде других языков программирования строка представляет собой массив символов. А в C# строки являются объектами. Следовательно, тип string относится к числу ссылочных. Построение строкСамый простой способ построить символьную строку - воспользоваться строковым литералом . Например, в следующей строке кода переменной ссылки на строку str присваивается ссылка на строковый литерал: String str = "Пример строки"; В данном случае переменная str инициализируется последовательностью символов "Пример строки". Объект типа string можно также создать из массива типа char. Например: Char chararray = {"e", "x", "a", "m", "p", "l", "e"}; string str = new string(chararray); Как только объект типа string будет создан, его можно использовать везде, где только требуется строка текста, заключенного в кавычки. Постоянство строкКак ни странно, содержимое объекта типа string не подлежит изменению. Это означает, что однажды созданную последовательность символов изменить нельзя. Но данное ограничение способствует более эффективной реализации символьных строк. Поэтому этот, на первый взгляд, очевидный недостаток на самом деле превращается в преимущество. Так, если требуется строка в качестве разновидности уже имеющейся строки, то для этой цели следует создать новую строку, содержащую все необходимые изменения. А поскольку неиспользуемые строковые объекты автоматически собираются в "мусор", то о дальнейшей судьбе ненужных строк можно даже не беспокоиться. Следует, однако, подчеркнуть, что переменные ссылки на строки (т.е. объекты типа string) подлежат изменению, а следовательно, они могут ссылаться на другой объект. Но содержимое самого объекта типа string не меняется после его создания. Рассмотрим пример: Static void addNewString() { string s = "This is my stroke"; s = "This is new stroke"; } Скомпилируем приложение и загрузим результирующую сборку в утилиту ildasm.exe . На рисунке показан CIL-код, который будет сгенерирован для метода void addNewString(): Обратите внимание на наличие многочисленных вызовов кода операции ldstr (загрузка строки). Этот код операции ldstr в CIL предусматривает выполнение загрузки нового объекта string в управляемую кучу. В результате предыдущий объект, в котором содержалось значение "This is my stroke", будет в конечном итоге удален сборщиком мусора. Работа со строкамиВ классе System.String предоставляется набор методов для определения длины символьных данных, поиска подстроки в текущей строке, преобразования символов из верхнего регистра в нижний и наоборот, и т.д. Далее мы рассмотрим этот класс более подробно. Поле, индексатор и свойство класса StringВ классе String определено единственное поле: Public static readonly string Empty; Поле Empty обозначает пустую строку, т.е. такую строку, которая не содержит символы. Этим оно отличается от пустой ссылки типа String, которая просто делается на несуществующий объект. Помимо этого, в классе String определен единственный индексатор, доступный только для чтения: Public char this { get; } Этот индексатор позволяет получить символ по указанному индексу. Индексация строк, как и массивов, начинается с нуля. Объекты типа String отличаются постоянством и не изменяются, поэтому вполне логично, что в классе String поддерживается индексатор, доступный только для чтения. И наконец, в классе String определено единственное свойство, доступное только для чтения: Public int Length { get; } Свойство Length возвращает количество символов в строке. В примере ниже показано использование индексатора и свойства Length: Using System; class Example { static void Main() { string str = "Простая строка"; // Получить длину строки и 6й символ в строке используя индексатор Console.WriteLine("Длина строки - {0}, 6й символ - "{1}"", str.Length, str); } } Операторы класса StringВ классе String перегружаются два следующих оператора: == и!=. Оператор == служит для проверки двух символьных строк на равенство. Когда оператор == применяется к ссылкам на объекты, он обычно проверяет, делаются ли обе ссылки на один и тот же объект. А когда оператор == применяется к ссылкам на объекты типа String, то на предмет равенства сравнивается содержимое самих строк. Это же относится и к оператору!=. Когда он применяется к ссылкам на объекты типа String, то на предмет неравенства сравнивается содержимое самих строк. В то же время другие операторы отношения, в том числе =, сравнивают ссылки на объекты типа String таким же образом, как и на объекты других типов. А для того чтобы проверить, является ли одна строка больше другой, следует вызвать метод Compare(), определенный в классе String. Как станет ясно дальше, во многих видах сравнения символьных строк используются сведения о культурной среде. Но это не относится к операторам == и!=. Ведь они просто сравнивают порядковые значения символов в строках. (Иными словами, они сравнивают двоичные значения символов, не видоизмененные нормами культурной среды, т.е. региональными стандартами.) Следовательно, эти операторы выполняют сравнение строк без учета регистра и настроек культурной среды. Методы класса StringВ следующей таблице перечислены некоторые наиболее интересные методы этого класса, сгруппированные по назначению:
Пример следующей программы использует несколько из вышеуказанных методов: Using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string args) { // Сравним первые две строки string s1 = "это строка"; string s2 = "это текст, а это строка"; if (String.CompareOrdinal(s1, s2) != 0) Console.WriteLine("Строки s1 и s2 не равны"); if (String.Compare(s1, 0, s2, 13, 10, true) == 0) Console.WriteLine("При этом в них есть одинаковый текст"); // Конкатенация строк Console.WriteLine(String.Concat("\n" + "Один, два ","три, четыре")); // Поиск в строке // Первое вхождение подстроки if (s2.IndexOf("это") != -1) Console.WriteLine("Слово \"это\" найдено в строке, оно "+ "находится на: {0} позиции", s2.IndexOf("это")); // Последнее вхождение подстроки if (s2.LastIndexOf("это") != -1) Console.WriteLine("Последнее вхождение слова \"это\" находится " + "на {0} позиции", s2.LastIndexOf("это")); // Поиск из массива символов char myCh = {"Ы","х","т"}; if (s2.IndexOfAny(myCh) != -1) Console.WriteLine("Один из символов из массива ch "+ "найден в текущей строке на позиции {0}", s2.IndexOfAny(myCh)); // Определяем начинается ли строка с заданной подстроки if (s2.StartsWith("это текст") == true) Console.WriteLine("Подстрока найдена!"); // Определяем содержится ли в строке подстрока // на примере определения ОС пользователя string myOS = Environment.OSVersion.ToString(); if (myOS.Contains("NT 5.1")) Console.WriteLine("Ваша операционная система Windows XP"); else if (myOS.Contains("NT 6.1")) Console.WriteLine("Ваша операционная система Windows 7"); Console.ReadLine(); } } } Немного о сравнении строк в C#Вероятно, из всех операций обработки символьных строк чаще всего выполняется сравнение одной строки с другой. Прежде чем рассматривать какие-либо методы сравнения строк, следует подчеркнуть следующее: сравнение строк может быть выполнено в среде.NET Framework двумя основными способами: Во-первых, сравнение может отражать обычаи и нормы отдельной культурной среды, которые зачастую представляют собой настройки культурной среды, вступающие в силу при выполнении программы. Это стандартное поведение некоторых, хотя и не всех методов сравнения. И во-вторых, сравнение может быть выполнено независимо от настроек культурной среды только по порядковым значениям символов, составляющих строку. Вообще говоря, при сравнении строк без учета культурной среды используется лексикографический порядок (и лингвистические особенности), чтобы определить, является ли одна строка больше, меньше или равной другой строке. При порядковом сравнении строки просто упорядочиваются на основании невидоизмененного значения каждого символа. В силу отличий способов сравнения строк с учетом культурной среды и порядкового сравнения, а также последствий каждого такого сравнения настоятельно рекомендуется руководствоваться лучшими методиками, предлагаемыми в настоящее время корпорацией Microsoft. Ведь выбор неверного способа сравнения строк может привести к неправильной работе программы, когда она эксплуатируется в среде, отличающей от той, в которой она разработана. Выбор способа сравнения символьных строк представляет собой весьма ответственное решение. Как правило и без всяких исключений, следует выбирать сравнение строк с учетом культурной среды, если это делается для целей отображения результата пользователю (например, для вывода на экран ряда строк, отсортированных в лексикографическом порядке). Но если строки содержат фиксированную информацию, не предназначенную для видоизменения с учетом отличий в культурных средах, например, имя файла, ключевое слово, адрес веб-сайта или значение, связанное с обеспечением безопасности, то следует выбрать порядковое сравнение строк. Разумеется, особенности конкретного разрабатываемого приложения будут диктовать выбор подходящего способа сравнения символьных строк. В классе String предоставляются самые разные методы сравнения строк, которые перечислены в таблице выше. Наиболее универсальным среди них является метод Compare(). Он позволяет сравнивать две строки полностью или частично, с учетом или без учета регистра, способа сравнения, определяемого параметром типа StringComparison , а также сведений о культурной среде, предоставляемых с помощью параметра типа CultureInfo . Те перегружаемые варианты метода Compare(), которые не содержат параметр типа StringComparison, выполняют сравнение символьных строк с учетом регистра и культурной среды. А в тех перегружаемых его вариантах, которые не содержат параметр типа CultureInfo, сведения о культурной среде определяются текущей средой выполнения. Тип StringComparison представляет собой перечисление, в котором определяются значения, приведенные в таблице ниже. Используя эти значения, можно организовать сравнение строк, удовлетворяющее потребностям конкретного приложения. Следовательно, добавление параметра типа StringComparison расширяет возможности метода Compare() и других методов сравнения, например, Equals(). Это дает также возможность однозначно указывать способ предполагаемого сравнения строк. В силу имеющих отличий между сравнением строк с учетом культурной среды и порядковым сравнением очень важно быть предельно точным в этом отношении.
В любом случае метод Compare() возвращает отрицательное значение, если первая сравниваемая строка оказывается меньше второй; положительное значение, если первая сравниваемая строка больше второй; и наконец, нуль, если обе сравниваемые строки равны. Несмотря на то что метод Compare() возвращает нуль, если сравниваемые строки равны, для определения равенства символьных строк, как правило, лучше пользоваться методом Equals() или же оператором ==. Дело в том, что метод Compare() определяет равенство сравниваемых строк на основании порядка их сортировки. Так, если выполняется сравнение строк с учетом культурной среды, то обе строки могут оказаться одинаковыми по порядку их сортировки, но не равными по существу. По умолчанию равенство строк определяется в методе Equals(), исходя из порядковых значений символов и без учета культурной среды. Следовательно, по умолчанию обе строки сравниваются в этом методе на абсолютное, посимвольное равенство подобно тому, как это делается в операторе ==. Несмотря на большую универсальность метода Compare(), для простого порядкового сравнения символьных строк проще пользоваться методом CompareOrdinal(). И наконец, следует иметь в виду, что метод CompareTo() выполняет сравнение строк только с учетом культурной среды. В приведенной ниже программе демонстрируется применение методов Compare(), Equals(), CompareOrdinal(), а также операторов == и!= для сравнения символьных строк. Обратите внимание на то, что два первых примера сравнения наглядно демонстрируют отличия между сравнением строк с учетом культурной среды и порядковым сравнением в англоязычной среде: Using System; class Example { static void Main() { string str1 = "alpha"; string str2 = "Alpha"; string str3 = "Beta"; string str4 = "alpha"; string str5 = "alpha, beta"; int result; // Сначала продемонстрировать отличия между сравнением строк // с учетом культурной среды и порядковым сравнением result = String.Compare(str1, str2, StringComparison.CurrentCulture); Console.Write("Сравнение строк с учетом культурной среды: "); if (result 0) Console.WriteLine(str1 + " больше " + str2); else Console.WriteLine(str1 + " равно " + str2); result = String.Compare(str1, str2, StringComparison.Ordinal); Console.Write("Порядковое сравнение строк: "); if (result 0) Console.WriteLine(str1 + " больше " + str2); else Console.WriteLine(str1 + " равно " + str4); // Использовать метод CompareOrdinal() result = String.CompareOrdinal(str1, str2); Console.Write("Сравнение строк методом CompareOrdinal():\n"); if (result 0) Console.WriteLine(str1 + " больше " + str2); else Console.WriteLine(str1 + " равно " + str4); Console.WriteLine(); // Определить равенство строк с помощью оператора == // Это порядковое сравнение символьных строк if (str1 == str4) Console.WriteLine(str1 + " == " + str4); // Определить неравенство строк с помощью оператора!= if(str1 != str3) Console.WriteLine(str1 + " != " + str3); if(str1 != str2) Console.WriteLine(str1 + " != " + str2); Console.WriteLine(); // Выполнить порядковое сравнение строк без учета регистра, // используя метод Equals() if(String.Equals(str1, str2, StringComparison.OrdinalIgnoreCase)) Console.WriteLine("Сравнение строк методом Equals() с " + "параметром OrdinalIgnoreCase:\n" + str1 + " равно " + str2); Console.WriteLine (); // Сравнить части строк if(String.Compare(str2, 0, str5, 0, 3, StringComparison.CurrentCulture) > 0) { Console.WriteLine("Сравнение строк с учетом текущей культурной среды:" + "\n3 первых символа строки " + str2 + " больше, чем 3 первых символа строки " + str5); } } } Выполнение этой программы приводит к следующему результату: Теги: Си строки. Char array. Строки в си. Введение.Э
то вводная статья по строкам в си. Более подробное описание и примеры будут, когда мы научимся работать с памятью и указателями.
В компьютере все значения хранятся в виде чисел. И строки тоже, там нет никаких символов и букв.
Срока представляет собой массив чисел. Каждое число соответствует определённому символу, который берётся из таблицы кодировки. При выводе на экран символ отображается определённым образом.
#include Мы создали две переменные, одна типа char , другая int . Литера "A" имеет числовое значение 65. Это именно литера, а не строка, поэтому окружена одинарными кавычками. Мы можем вывести её на печать как букву Printf("display as char %c\n", c); Тогда будет выведено
#include Здесь будет сначала "выведен" звуковой сигнал, затем его числовое значение, затем опять звуковой сигнал.
#include Для вывода использовался ключ %s. При этом строка выводится до первого терминального символа, потому что функция printf не знает размер массива word.
Word = "\0"; то будет выведена строка символов произвольной длины, до тех пор, пока не встретится первый байт, заполненный нулями.
#include В данном случае всё корректно. Строка "ABC" заканчивается нулём, и ею мы инициализируем массив word. Строка text инициализируется побуквенно, все оставшиеся символы, как следует из главы про массивы, заполняются нулями. Чтение строкД ля того, чтобы запросить у пользователя строку, необходимо создать буфер. Размер буфера должен быть выбран заранее, так, чтобы введённое слово в нём поместилось. При считывании строк есть опасность того, что пользователь введёт данных больше, чем позволяет буфер. Эти данные будут считаны и помещены в память, и затрут собой чужие значения. Таким образом можно провести атаку, записав нужные байты, в которых, к примеру, стоит переход на участок кода с вредоносной программой, или логгирование данных.
#include В данном случае количество введённых символов ограничено 19, а размер буфера на 1 больше, так как необходимо хранить терминальный символ. Напишем простую программу, которая запрашивает у пользователя строку и возвращает её длину.
#include Так как числовое значение символа "\0" равно нулю, то можно записать While (buffer != 0) { len++; } Или, ещё короче While (buffer) { len++; } Теперь напишем программу, которая запрашивает у пользователя два слова и сравнивает их
#include Так как каждая буква имеет числовое значение, то их можно сравнивать между собой как числа. Кроме того, обычно (но не всегда!) буквы в таблицах кодировок расположены по алфавиту. Поэтому сортировка по числовому значению также будет и сортировкой по алфавиту. Работа со строками. Класс string . Конструкторы класса. Функции assign() , append() , insert() , replace() , erase() , find() , rfind() , compare() , c_str() . Примеры1. Какое назначение класса string в программах на C++?Класс string предназначен для работы со строками типа char* , которые представляют собой строку с завершающим нулем. Класс string был введенн как альтернативный вариант для работы со строками типа char* . Строки, которые завершаются символом ‘\0’ еще называются C-строками. Поскольку, string есть классом, то можно объявлять объекты этого класса. 2. Какие модули (библиотеки) нужно подключить, чтобы использовать возможности класса string в MS Visual Studio C++?Чтобы использовать возможности класса string
в MS Visual Studio (C++), нужно подключить библиотеку 3. Каким образом осуществляется объявление переменной типа string ? ПримерыОбъявление переменной типа string осуществляется точно так же как и обычной переменной. Возможный вариант объявления с одновременной инициализацией. // тип string string s1; // переменная с именем s1 типа string string s2 = "This is a string variable" ; // объявление с инициализацией // использование переменной типа string с оператором присваивания s1 = s2; // s1 = "This is a string variable" s2 = "New text" ;4. Какие преимущества и недостатки дает использование класса string в сравнении с типом char* ?Создание нового типа string было обусловлено недостатками работы с строками символов, который демонстрировал тип char* . В сравнении с типом char* тип string имеет следующие основные преимущества:
Основным недостатком типа string в сравнении с типом char* , есть замедленная скорость обработки данных. Это связано с тем, что тип string – это, фактически, контейнерный класс. А работа с классом требует дополнительной реализации программного кода, который, в свою очередь занимает лишнее время. 5. Какие операторы можно использовать с объектами класса string ?Класс string есть удобен тем, что позволяет удобно манипулировать строками, используя стандартные (перегруженные) операторы. С объектами класса string можно использовать нижеследующие операторы
Пример, который демонстрирует использование вышеприведенных операторов // тип string, операции над строками string s1 = "s-1" ; string s2 = "s-2" ; string s3; bool b; // операция "=" (присваивание строк) s3 = s1; // s3 = "s-1" // операция "+" - конкатенация строк s3 = s3 + s2; // s3 = "s-1s-2" // операция "+=" - присваивание с конкатенацией s3 = "s-3" ; s3 += "abc" ; // s3 = "s-3abc" // операция "==" - сравнение строк b = s2==s1; // b = false b = s2=="s-2" ; // b = true // операция "!=" - сравнение строк (не равно) s1 = "s1" ; s2 = "s2" ; b = s1 != s2; // b = true // операции "<" и ">" - сравнение строк s1 = "abcd" ; s2 = "de "; b = s1 > s2; // b = false b = s1 < s2; // b = true // операции "<=" и ">=" - сравнение строк (меньше или равно, больше или равно) s1 = "abcd" ; s2 = "ab" ; b = s1 >= s2; // b = true b = s1 <= s2; // b = false b = s2 >= "ab" ; // b = true // операция - индексация char c; s1 = "abcd" ; c = s1; // c = "c" c = s1; // c = "a"6. Содержит ли класс string конструкторы?Как и любой класс, класс string имеет ряд конструкторов. Основные из них следующие: String(); string(const char * str); string(const string & str); 7. Примеры инициализации с помощью конструкторовНиже приведены примеры инициализации переменных типа string String s1("Hello!" ); string s2 = "Hello!" ; // инициализация - конструктор string(const char * str) char * ps = "Hello" ; string s3(ps); // инициализация string s4(s3); // инициализация - конструктор string(const string & str) string s5; // инициализация - конструктор string() 8. Присваивание строк. Функция assign() . ПримерыЧтобы присвоить одну строку другой, можно применить один из двух методов:
Функция assign() имеет несколько перегруженных реализаций. Первый вариант – это вызов функции без параметров String &assign(void ); В этом случае происходит простое присваивание одной строки другой. Второй вариант позволяет копировать заданное количество символов из строки: String &assign(const string & s, size_type st, size_type num);
Третий вариант функции assign() копирует в вызывающий объект первые num символов строки s : String & assign(const char * s, size_type num);
Ниже приведен пример с разными реализациями функции assign() . Пример. // присваивание строк, функция assign() string s1 = "сайт" ; string s2; string s3; char * ps = "сайт" ; s3 = s1; // s3 = "сайт" s2.assign(s1); // s2 = "сайт" s2.assign(s1, 0, 4); // s2 = "best" s2.assign(ps, 8); // s2 = "bestprog"9. Объединение строк. Функция append() . ПримерДля объединения строк используется функция append() . Для добавления строк также можно использовать операцию ‘+’ , например: String s1; string s2; s1 = "abc" ; s2 = "def" ; s1 = s1 + s2; // s1 = "abcdef" Однако, функция append() хорошо подходит, если нужно добавлять часть строки. Функция имеет следующие варианты реализации: String &append(const string & s, size_type start); string &append(const char * s, size_type num); В первом варианте реализации функция получает ссылку на строчный объект s , который добавляется к вызывающему объекту. Во втором варианте реализации функция получает указатель на строку типа const char * , которая завершается символом ‘\0’ . Пример. Демонстрация работы функции append() . String s1 = "abcdef" ; s2 = "1234567890" ; append(s2, 3, 4); // s1 = "abcdef4567" char * ps = "1234567890" ; s1 = "abcdef" ; s1.append(ps, 3); // s1 = "abcdef123" 10. Вставка символов в строке. Функция insert() . ПримерЧтобы вставить одну строку в заданную позицию другой строки нужно использовать функцию insert() , которая имеет несколько вариантов реализации. Первый вариант функции позволяет вставить полностью всю строку s в заданную позицию start вызывающей строки (вызывающего объекта): String & insert(size_type start, const string &s); Второй вариант функции позволяет вставить часть (параметры insStart , num ) строки s в заданную позицию start вызывающей строки: String & insert(size_type start, const string &s, size_type insStart, size_type num); В вышеприведенных функциях:
11. Замена символов в строке. Функция replace() . ПримерФункция replace() выполняет замену символов в вызывающей строке. Функция имеет следующие варианты реализации: String &replace(size_type start, size_type num, const string &s); string &replace(size_type start, size_type num, const string &s, size_type replStart, size_type replNum); В первом варианте реализации вызывающая строка заменяется строкой s . Есть возможность задать позицию (start ) и количество символов (num ) в вызывающей строке, которые нужно заменить строкой s . Второй вариант функции replace() отличается от первого тем, что позволяет заменять вызывающую строку только частью строки s . В этом случае задаются два дополнительных параметра: позиция replStart и количество символов в строке s , которые образуют подстроку, которая заменяет вызывающую строку. Пример. Демонстрация работы функции replace() . String s1 = "abcdef" ; string s2 = "1234567890" ; s2.replace(2, 4, s1); // s2 = "12abcdef7890" s2 = "1234567890" ; s2.replace(3, 2, s1); // s2 = "123abcdef67890" s2 = "1234567890" ; s2.replace(5, 1, s1); // s2 = "12345abcdef7890" // замена символов, функция replace() string s1 = "abcdef" ; string s2 = "1234567890" ; s2.replace(2, 4, s1); // s2 = "12abcdef7890" s2 = "1234567890" ; s2.replace(3, 2, s1); // s2 = "123abcdef67890" s2 = "1234567890" ; s2.replace(5, 1, s1); // s2 = "12345abcdef7890" s2 = "1234567890" ; s2.replace(5, 1, s1, 2, 3); // s2 = "12345cde7890" s2 = "1234567890" ; s2.replace(4, 2, s1, 0, 4); // s2 = "1234abcd7890" 12. Удаление заданного количества символов из строки. Функция erase() . ПримерДля удаления символов из вызывающей строки используется функция erase() : String & erase(size_type index=0, size_type num = npos);
Пример. String s = "01234567890" ; s.erase(3, 5); // s = "012890" s = "01234567890" ; s.erase(); // s = "" 13. Поиск символа в строке. Функции find() и rfind() . ПримерыВ классе string поиск строки в подстроке можно делать двумя способами, которые отличаются направлением поиска:
Прототип функции find() имеет вид: Size_type find(const string &s, size_type start = 0) const ;
Прототип функции rfind() имеет вид: Size_type rfind(const string &s, size_type start = npos) const ;
Пример 1. Фрагмент кода, который демонстрирует результат работы функции find() // тип string, функция find() string s1 = "01234567890" ; string s2 = "345" ; string s3 = "abcd" ; int pos; pos = s1.find(s2); // pos = 3 pos = s1.find(s2, 1); // pos = 3 pos = s1.find("jklmn" , 0); // pos = -1 pos = s1.find(s3); // pos = -1 pos = s2.find(s1); // pos = -1Пример 2. Демонстрация работы функции rfind() . // тип string, функции find() и rfind() string s1 = "01234567890" ; string s2 = "345" ; string s3 = "abcd" ; string s4 = "abcd---abcd" ; int pos; pos = s1.rfind(s2); // pos = 3 pos = s1.rfind(s2, 12); // pos = 3 pos = s1.rfind(s2, 3); // pos = 3 pos = s1.rfind(s2, 2); // pos = -1 pos = s2.rfind(s1); // pos = -1 pos = s1.rfind(s3, 0); // pos = -1 // разница между функциями find() и rfind() pos = s4.rfind(s3); // pos = 7 pos = s4.find(s3); // pos = 014. Сравнение частей строк. Функция compare() . ПримерПоскольку тип string есть классом, то, чтобы сравнить две строки между собой можно использовать операцию ‘= =’ . Если две строки одинаковы, то результат сравнения будет true . В противном случае, результат сравнения будет false . Но если нужно сравнить часть одной строки с другой, то для этого предусмотрена функция compare() . Прототип функции compare() : int compare(size_type start, size_type num, const string &s) const ;
Функция работает следующим образом. Если вызывающая строка меньше строки s , то функция возвращает -1 (отрицательное значение). Если вызывающая строка больше строки s , функция возвращает 1 (положительное значение). Если две строки равны, функция возвращает 0. Пример . Демонстрация работы функции compare() : // тип string, функция compare() string s1 = "012345" ; string s2 = "0123456789" ; int res; res = s1.compare(s2); // res = -1 res = s1.compare("33333" ); // res = -1 res = s1.compare("012345" ); // res = 0 res = s1.compare("345" ); // res = -1 res = s1.compare(0, 5, s2); // res = -1 res = s2.compare(0, 5, s1); // res = -1 res = s1.compare(0, 5, "012345" ); // res = -1 res = s2.compare(s1); // res = 1 res = s2.compare("456" ); // res = -1 res = s2.compare("000000" ); // res = 115. Получение строки с символом конца строки ‘\0’ (char * ). Функция c_str() . ПримерЧтобы получить строку, которая заканчивается символом ‘\0’ используется функция c_str() . Прототип функции: const char * c_str() const ;Функция объявлена с модификатором const . Это означает, что функция не может изменять вызывающий объект (строку). Пример 1 . Преобразование типа string в const char * . // тип string, функция c_str() string s = "abcdef" ; const char * ps; ps = s.c_str(); // ps = "abcdef"Пример 2. Ниже продемонстрирован перевод строки из string в тип System::String для отображения его в элементе управления типа Label В программе строки могут определяться следующим образом:
Кроме того, должно быть предусмотрено выделение памяти для хранения строки. Любая последовательность символов, заключенная в двойные кавычки «» , рассматривается как строковая константа . Для корректного вывода любая строка должна заканчиваться нуль-символом "\0" , целочисленное значение которого равно 0. При объявлении строковой константы нуль-символ добавляется к ней автоматически. Так, последовательность символов, представляющая собой строковую константу, будет размещена в оперативной памяти компьютера, включая нулевой байт. Под хранение строки выделяются последовательно идущие ячейки оперативной памяти. Таким образом, строка представляет собой массив символов. Для хранения кода каждого символа строки отводится 1 байт. Для помещения в строковую константу некоторых служебных символов используются символьные комбинации. Так, если необходимо включить в строку символ двойной кавычки, ему должен предшествовать символ «обратный слеш»: ‘\»‘ . Строковые константы размещаются в статической памяти. Начальный адрес последовательности символов в двойных кавычках трактуется как адрес строки. Строковые константы часто используются для осуществления диалога с пользователем в таких функциях, как printf() . При определении массива символов
необходимо сообщить компилятору требуемый размер памяти. char
m; Компилятор также может самостоятельно определить размер массива символов, если инициализация массива задана при объявлении строковой константой: char
m2=; В этом случае имена m2 и m3 являются указателями на первые элементы массивов:
При объявлении массива символов и инициализации его строковой константой можно явно указать размер массива, но указанный размер массива должен быть больше, чем размер инициализирующей строковой константы: char
m2="Горные вершины спят во тьме ночной."
; Для задания строки можно использовать указатель на символьный тип
. char
*m4; В этом случае объявление массива переменной m4 может быть присвоен адрес массива: m4 = m3; Здесь m3 является константой-указателем. Нельзя изменить m3 , так как это означало бы изменение положения (адреса) массива в памяти, в отличие от m4 . Для указателя можно использовать операцию увеличения (перемещения на следующий символ): Массивы символьных строкИногда в программах возникает необходимость описание массива символьных строк
. В этом случае можно использовать индекс строки для доступа к нескольким разным строкам. char
*poet = {"Погиб поэт!", "- невольник чести -"
, В этом случае poet
является массивом, состоящим из четырех указателей на символьные строки. Каждая строка символов представляет собой символьный массив, поэтому имеется четыре указателя на массивы. Указатель poet
ссылается на первую строку: Инициализация выполняется по правилам, определенным для массивов. char
poet; Разница заключается в том, что такая форма задает «прямоугольный» массив, в котором все строки имеют одинаковую длину. Свободный массивОписание сhar *poet; определяет свободный массив, где длина каждой строки определяется тем указателем, который эту строку инициализирует. Свободный массив не тратит память напрасно. Операции со строкамиБольшинство операций языка Си, имеющих дело со строками, работает с указателями. Для размещения в оперативной памяти строки символов необходимо:
Для выделения памяти под хранение строки могут использоваться функции динамического выделения памяти . При этом необходимо учитывать требуемый размер строки: char
*name; Для ввода строки использована функция scanf()
, причем введенная строка не может превышать 9 символов. Последний символ будет содержать "\0"
. Функции ввода строкДля ввода строки может использоваться функция scanf() . Однако функция scanf() предназначена скорее для получения слова, а не строки. Если применять формат "%s" для ввода, строка вводится до (но не включая) следующего пустого символа, которым может быть пробел, табуляция или перевод строки. Для ввода строки, включая пробелы, используется функция char
* gets(char
*); или её эквивалент char
* gets_s(char
*); В качестве аргумента функции передается указатель на строку, в которую осуществляется ввод. Функция просит пользователя ввести строку, которую она помещает в массив, пока пользователь не нажмет Enter . Функции вывода строкДля вывода строк можно воспользоваться рассмотренной ранее функцией printf("%s"
, str); // str - указатель на строку
или в сокращенном формате printf(str); Для вывода строк также может использоваться функция int
puts (char
*s); которая печатает строку s и переводит курсор на новую строку (в отличие от printf() ). Функция puts() также может использоваться для вывода строковых констант, заключенных в кавычки. Функция ввода символовДля ввода символов может использоваться функция char
getchar(); которая возвращает значение символа, введенного с клавиатуры. Указанная функция использовалась в рассмотренных ранее примерах для задержки окна консоли после выполнения программы до нажатия клавиши. Функция вывода символовДля вывода символов может использоваться функция char
putchar(char
); которая возвращает значение выводимого символа и выводит на экран символ, переданный в качестве аргумента. 1 #include
Результат выполнения Основные функции стандартной библиотеки string.hОсновные функции стандартной библиотеки string.h приведены в таблице.
|