Урок №79. Строки C-style

  Юрий  | 

  |

  Обновл. 13 Сен 2021  | 

 90968

 ǀ   8 

На уроке №57 мы определили термин «строка», как набор последовательных символов (например, Hello, world!). Строки — это основной способ работы с текстом в языке C++, а std::string упрощает этот способ работы.

Современный C++ поддерживает два разных типа строк:

   std::string (как часть Стандартной библиотеки С++);

   строки C-style (изначально унаследованные от языка Cи).

std::string реализован с помощью строк C-style.

Строки C-style

Строка C-style — это простой массив символов, который использует нуль-терминатор. Нуль-терминатор — это специальный символ (ASCII-код которого равен 0), используемый для обозначения конца строки. Строка C-style еще называется «нуль-терминированной строкой».

Для её определения нужно просто объявить массив типа char и инициализировать его литералом (например, string):

Хотя string имеет только 6 букв, C++ автоматически добавляет нуль-терминатор в конец строки (нам не нужно добавлять его вручную). Следовательно, длина массива mystring на самом деле равна 7!

В качестве примера рассмотрим следующую программу, которая выводит длину строки, а затем ASCII-коды всех символов литерала string:

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

string has 7 characters.
115 116 114 105 110 103 0

Нуль в конце является ASCII-кодом нуль-терминатора, который был добавлен в конец строки.

При таком объявлении строк рекомендуется использовать квадратные скобки [], чтобы позволить компилятору определить длину массива самому. Таким образом, если вы измените строку позже, вам не придется вручную изменять значение длины массива.

Важно отметить, что строки C-style следуют всем тем же правилам, что и массивы. Это означает, что вы можете инициализировать строку при создании, но после этого не сможете присваивать ей значения с помощью оператора присваивания:

Это то же самое, как если бы мы сделали следующее:

Поскольку строки C-style являются массивами, то вы можете использовать оператор [] для изменения отдельных символов в строке:

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

spring

При выводе строки C-style объект std::cout выводит символы до тех пор, пока не встретит нуль-терминатор. Если бы вы случайно перезаписали нуль-терминатор в конце строки (например, присвоив что-либо для mystring[6]), то от std::cout вы бы получили не только все символы строки, но и всё, что находится в соседних ячейках памяти до тех пор, пока не попался бы 0!

Обратите внимание, это нормально, если длина массива больше строки, которую он хранит:

В этом случае строка Max будет выведена, а std::cout остановится на нуль-терминаторе. Остальные символы в массиве будут проигнорированы.

Строки C-style и std::cin


Есть много случаев, когда мы не знаем заранее, насколько длинной будет наша строка. Например, рассмотрим проблему написания программы, где мы просим пользователя ввести свое имя. Насколько длинным оно будет? Это неизвестно до тех пор, пока пользователь его не введет!

В таком случае мы можем объявить массив размером больше, чем нам нужно:

В программе, приведенной выше, мы объявили массив из 255 символов, предполагая, что пользователь не введет имя длиннее 255 символов. Хоть это и распространенная практика, но она не очень эффективна, так как пользователю ничего не мешает ввести имя, содержащее более 255 символов (случайно или намеренно).

Намного лучше сделать следующим образом:

Вызов cin.getline() будет принимать до 254 символов в массив name (оставляя место для нуль-терминатора!). Любые лишние символы будут проигнорированы. Таким образом, мы можем гарантировать, что массив не будет переполнен!

Управление строками C-style

Язык C++ предоставляет множество функций для управления строками C-style, которые подключаются с помощью заголовочного файла cstring. Вот несколько самых полезных функций:

Функция strcpy_s() позволяет копировать содержимое одной строки в другую. Чаще всего это используется для присваивания значений строке:

Тем не менее, использование функции strcpy_s() может легко вызвать переполнение массива, если не быть осторожным! В следующей программе длина массива dest меньше длины копируемой строки, поэтому в результате мы получим переполнение массива:

Еще одной полезной функцией управления строками является функция strlen(), которая возвращает длину строки C-style (без учета нуль-терминатора):

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

My name is Max
Max has 3 letters.
Max has 15 characters in the array.

Обратите внимание на разницу между функцией strlen() и оператором sizeof. Функция strlen() выводит количество символов до нуль-терминатора, тогда как оператор sizeof возвращает размер целого массива, независимо от того, что в нем находится.

Вот еще полезные функции для управления строками C-style:

   функция strcat() — добавляет одну строку к другой (опасно);

   функция strncat() — добавляет одну строку к другой (с проверкой размера места назначения);

   функция strcmp() — сравнивает две строки (возвращает 0, если они равны);

   функция strncmp() — сравнивает две строки до определенного количества символов (возвращает 0, если до указанного символа не было различий).

Например:

Стоит ли использовать строки C-style?


Знать о строках C-style стоит, так как они используются не так уж и редко, но использовать их без веской на то причины не рекомендуется. Вместо строк C-style используйте std::string (подключая заголовочный файл string), так как он проще, безопаснее и гибче.

Правило: Используйте std::string вместо строк C-style.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (403 оценок, среднее: 4,97 из 5)
Загрузка...

Комментариев: 8

  1. Сергей:

    Всегда использовать строки std::string неудобно, если используются символы на нескольких языках. Строка std::string может содержать UTF8 строки, в которых строковые операции без перекодировки нельзя использовать напрямую.
    При работе с строками std::string конвертирую в С строки или в CString.
    Как вы работает со строками?

  2. Павел:

    Тут нашел задачник с ответами, там была задача:
    Составить программу, которая на входе должна получать последовательность цифр, после чего программа показывает цифру, порядковый номер которой ввел пользователь.
    Я ее решил и потом решил посмотреть ответ и немного прифигел от решения, так как я думал strlen только считает длину строки складывая, а тут используется для сравнения.

  3. Alex_1988:

    Пройдя 79 часть решил объявить строку C-style через структуру:

    Но не получается присвоить данные сразу же:

    а только если добавлять посимвольно:

    Как правильно присвоить слово целиком через структуру?

    1. Сергей:

      Присвоить слово целиком через структуру можно:

      Дело в том, что mass[JOHN].name — это адрес памяти, а адресу нельзя присвоить строковую константу.
      Это легко увидеть в следующих выражениях

  4. Игорь:

    Хмм. То есть, я правильно понял — весь текст который я видел выше это набор массивов? Каждое слово это массив? Или здесь какая-то другая технология?

    1. Fray:

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

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

      Создав массив типа char, каждый элемент будет рассматриваться как переменная типа char. А мы знаем, что переменные типа char могут хранить только 1 символ. Следовательно указывая текст в двойных кавычках при объявлении массива, мы задаем длину в виде символов. Каждый символ — это отдельный элемент. Текст — совокупность элементов(символов).

  5. Владимир:

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

    Результат:
    Put any text here.

    1. Юра:

      Ну и в чем безопасность? strlen возвращает кол-во символов до ТЕРМИНАЛЬНОГО НУЛЯ. Зачем переписывать велосипед?

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *