строка в верхнем регистре добавляет мусор в конец массива символов

#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-strings

5. Интересное примечание: toupper параметр s-это an int , а не a char , позволяющий использовать внеполосные коды, такие как EOF. Это может привести к интересным проблемам, когда у вас есть подписанный char s. Стандартная рекомендация состоит char в том, чтобы unsigned char перед вызовом бросить в an, просто на всякий случай.