#c #string
Вопрос:
Я изучаю c , я пишу некоторый код, чтобы преобразовать строку в верхний регистр и отобразить ее. Я назначаю строку str с «asdf», а затем создаю указатель на массив символов и выделяю длину, аналогичную длине строки.
Но после того, как я присвоил индексам массива символов символы в верхнем регистре, когда я пытаюсь отобразить массив символов, в конце добавляется много ненужных символов. Почему это происходит, поскольку я выделил массив символов только с размером = «длина строки», тогда как в массиве символов в конце есть ненужные символы даже после фактического выделенного размера.
string str{ "asdf" };
char* str_c = new char[str.length()];
for (int i = 0; i < str.length(); i ) {
str_c[i] = toupper(str[i]);
}
cout << str_c; // displays ASDF²▌r┐│w²A∙
Ответ №1:
Ваш массив символов должен быть на один символ длиннее, чем длина строки, для нулевого терминатора
string str{ "asdf" };
char* str_c = new char[str.length() 1];
for (int i = 0; i < str.length(); i ) {
str_c[i] = toupper(str[i]);
}
str_c[str.length()] = '';
cout << str_c; // displays ASDF
В строках в стиле C (символ*) длина строки не сохраняется в памяти. Таким образом, он должен использовать какой-то другой способ определить, где заканчивается строка. Это делается путем предположения, что строка содержит все байты до байта, равного нулю (так называемый null-terminator).
Без явного выделения дополнительного байта для терминатора null и его установки ваша строка продолжает работать с мусором, который происходит после выделенных вами байтов, пока не встретится (случайно) с ближайшим 0.
Комментарии:
1. спасибо, что это работает . но не могли бы вы, пожалуйста, объяснить мне, почему требуется «str_c[длина строки()] = 0;»?
2. В строках в стиле C (
char*
) длина строки не сохраняется в памяти. Таким образом, он должен использовать какой-то другой способ определить, где заканчивается строка. Это делается путем предположения, что строка содержит все байты до байта, равного нулю (так называемый null-terminator).3. о, это интересно, означает ли это, что я не могу иметь 0 в качестве символа между моей строкой.
4. Большинство библиотек (например
cout
, которые вы используетеiostream
, или большая часть материалов изstring.h
них ) сломаются, если вам нужно иметь 0 байт в вашемchar*
string
классе s. (str
в вашем коде был экземплярstring
) действительно хранит длину и во многих случаях правильно обрабатывает 0 байт внутри. В этой статье есть хорошее сравнение embeddedartistry.com/blog/2017/07/26/stdstring-vs-c-strings5. Интересное примечание:
toupper
параметр s-это anint
, а не achar
, позволяющий использовать внеполосные коды, такие как EOF. Это может привести к интересным проблемам, когда у вас есть подписанныйchar
s. Стандартная рекомендация состоитchar
в том, чтобыunsigned char
перед вызовом бросить в an, просто на всякий случай.