Объявление и инициализация C-строки

C-строка является массивом символов (тип char), последний элемент которого содержит нулевой символ ('\0'). Обратите внимание на то, что нулевой символ (нулевой байт) не имеет никакого отношения к символу '0'. Коды этих символов разные.

Объявляется C-строка также как и массив элементов типа char:

char str[7];

При инициализации C-строки можно перечислить символы внутри фигурных скобок:

char str[7] = {'S', 't', 'r', 'i', 'n', 'g', '\0'};
std::cout << str << std::endl;  // String

или указать строку внутри двойных кавычек:

char str[7] = "String";
std::cout << str << std::endl;  // String

При использовании двойных кавычек следует учитывать, что длина строки на один символ больше, так как в конец будет автоматически вставлен нулевой символ. Если это не предусмотреть и объявить массив из шести элементов, вместо семи, то это приведет к ошибке.

Если размер массива при объявлении не указать, то он будет определен автоматически в соответствии с длиной строки:

char str[] = "String";
std::cout << sizeof(str) << std::endl;  // 7
std::cout << str << std::endl;          // String

Если перед открывающей кавычкой указать комбинацию символов u8, то строка будет создана в кодировке UTF-8:

char utf8[] = u8"строка str";
std::cout << sizeof(utf8) << std::endl; // 17
for (size_t i = 0, len = std::strlen(utf8); i < len; ++i) {
   std::cout << (int)utf8[i] << ' ';
} // -47 -127 -47 -126 -47 -128 -48 -66 -48 -70 -48 -80 32 115 116 114
std::cout << std::endl;

При использовании кодировки UTF-8 следует учитывать, что латинские буквы и символы из кодировки ASCII кодируются одним байтом, русские буквы — двумя байтами, а некоторые символы — тремя и более байтами. Не забывайте также про нулевой символ в конце строки. Чтобы не ошибиться, внутри квадратных скобок при инициализации строки количество символов лучше не указывать.

Обратите внимание на то, что присваивать строку в двойных кавычках можно только при инициализации. Попытка присвоить строку позже приведет к ошибке:

char str[7];
str = "String"; // Ошибка!!!

В этом случае нужно воспользоваться функцией strcpy() или strcpy_s():

char str[7];
strcpy_s(str, 7, "String");
std::cout << str << std::endl; // String

Внутри строки в двойных кавычках можно указывать специальные символы (например, \n, \r и др.), которые мы уже рассматривали в разд. 7.1. Если внутри строки встречается кавычка, то ее необходимо экранировать с помощью обратного слэша:

std::setlocale(LC_ALL, "Russian_Russia.1251");
char str[] = "Группа \"Кино\"\n";
std::cout << str; // Группа "Кино"

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

char str1[] = "C:\\temp\\new\\file.txt"; // Правильно
char str2[] = "C:\temp\new\file.txt";    // Неправильно!!!
std::cout << str1 << std::endl; // C:\temp\new\file.txt
std::cout << str2 << std::endl; // Строка с ошибками!!!

Обратите внимание на вторую строку. В этом пути присутствуют сразу три специальных символа: \t, \n и \f. После преобразования специальных символов путь будет выглядеть следующим образом:

C:<Табуляция>emp<Перевод строки>ew<Перевод формата>ile.txt

Начиная со стандарта C++11, язык C++ поддерживает raw-строки, внутри которых специальные символы трактуются как комбинации обычных символов, поэтому их экранировать не нужно. Форматы raw-строк:

R"(текст строки)"
u8R"(текст строки)"
R"символы(текст строки)символы"
u8R"символы(текст строки)символы"

При использовании первых двух форматов текст строки указывается между отрывающей комбинацией символов R"( (или u8R"( для строк в кодировке UTF-8) и закрывающей комбинацией символов )":

std::cout << R"(текст строки\n)" << std::endl;       // текст строки\n
char utf8[] = u8R"(текст \n)";
for (size_t i = 0, len = std::strlen(utf8); i < len; ++i) {
   std::cout << (int)utf8[i] << ' ';
} // -47 -126 -48 -75 -48 -70 -47 -127 -47 -126 32 92 110
std::cout << std::endl;

Обратите внимание, символ перевода строки \n трактуется как комбинация двух символов \ и n, а не как специальный символ.

Последние два формата позволяют дополнительно указать произвольные символы-разделители, например, три точки. Благодаря этим символам мы можем в тексте строки использовать любые символы без опасения, что они случайно станут закрывающей строку комбинацией символов. Пример указания пути к файлу с помощью raw-строки:

char path[] = R"...(C:\temp\new\file.txt)..."; // Правильно
std::cout << path << std::endl;                // C:\temp\new\file.txt

Разместить C-строку при инициализации на нескольких строках нельзя. Переход на новую строку вызовет синтаксическую ошибку:

char str[] = "string1
string2"; // Ошибка!!!

Чтобы разместить C-строку на нескольких строках, следует перед символом перевода строки указать символ \:

char str[] = "string1 \
string2 \
string3"; // После символа \ не должно быть никаких символов
std::cout << str << std::endl; // string1 string2 string3

Можно также воспользоваться raw-строками, но символы перевода строки в исходном коде будут вставлены в строку:

char str[] = R"...(string1
string2
string3)...";
std::cout << str << std::endl;

Результат:

string1
string2
string3

Кроме того, можно воспользоваться неявной конкатенацией. Если строки расположены подряд внутри одной инструкции, то они объединяются в одну большую строку. Пример:

char str[] = "string1"
"string2" "string3";
std::cout << str << std::endl; // string1string2string3

Строку можно присвоить указателю, но в этом случае строка будет доступна только для чтения. Попытка изменить какой-либо символ внутри строки приведет к ошибке при выполнении:

const char *p = "string";
std::cout << p << std::endl; // string

Мы можем объявить несколько указателей и присвоить им одинаковую строку, но все они будут ссылаться на один и тот же адрес. Иными словами, строка, указанная в программе внутри двойных кавычек, в памяти существует в единственном экземпляре. Если бы была возможность изменить такую строку, то она изменилась бы во всех указателях. Поэтому строка, присвоенная указателю, доступна только для чтения:

const char *p1 = "string";
const char *p2 = "string";
const char *p3 = "string";
std::printf("%p %p %p\n", p1, p2, p3);
// 0000000000409017 0000000000409017 0000000000409017

Объявление массива строк выглядит так:

char str[][20] = {"String1", "String2", "String3"};
std::cout << str[0] << std::endl; // String1
std::cout << str[1] << std::endl; // String2
std::cout << str[2] << std::endl; // String3

или так:

const char *str[] = {"String1", "String2", "String3"};
std::cout << str[0] << std::endl; // String1
std::cout << str[1] << std::endl; // String2
std::cout << str[2] << std::endl; // String3

Обратите внимание: при использовании первого способа мы можем изменить символы в строках, а вот при использовании второго способа попытка изменения символа приведет к ошибке при выполнении программы. Так что эти способы объявления массива строк не эквивалентны.

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов