Ребята, вы знаете, почему следующий код вылетает во время выполнения?
char* word;
word = new char[20];
word = "HeLlo";
for (auto it = word; it != NULL; it++){
*it = (char) tolower(*it);
Я пытаюсь строчные буквы * (строка). Я использую визуальную студию.
Спасибо
Вы не можете сравнить it
в NULL
, Вместо этого вы должны сравнивать *it
в '\0'
, Или еще лучше, используйте std::string
и никогда не переживай об этом 🙂
Таким образом, при цикле по строке в стиле C. Вы должны быть в цикле, пока персонаж вы видите это '\0'
, Сам итератор никогда не будет NULL
, поскольку он просто указывает место в строке. Тот факт, что итератор имеет тип, который можно сравнить с NULL
это деталь реализации, которую вы не должны касаться напрямую.
Кроме того, вы пытаетесь записать строковый литерал. Что нет-нет :-).
РЕДАКТИРОВАТЬ:
Как отмечено @Cheers и hth. — Альф, tolower
может сломаться, если даны отрицательные значения. К сожалению, нам нужно добавить приведение, чтобы оно не сломалось, если вы передадите ему данные в кодировке Latin-1 или аналогичные.
Это должно работать:
char word[] = "HeLlo";
for (auto it = word; *it != '\0'; ++it) {
*it = tolower(static_cast<unsigned char>(*it));
}
Вы устанавливаете word
указывать на строковый литерал, но литералы доступны только для чтения, поэтому при назначении *it
, Вам необходимо сделать копию этого в динамически распределенной памяти.
char *word = new char[20];
strcpy(word, "HeLlo");
Также в вашем цикле вы должны сравнить *it != '\0'
, Конец строки обозначается символом, являющимся нулевым байтом, а не указателем, являющимся нулевым.
Данный код (как я пишу это):
char* word;
word = new char[20];
word = "HeLlo";
for (auto it = word; it != NULL; it++){
*it = (char) tolower(*it);
Этот код имеет Неопределенное поведение 2 различными способами, и UB также будет иметь третий способ, если только текстовые данные будут немного отличаться:
Переполнение буфера.
Условие продолжения it != NULL
не будет false
пока указатель it
обернул в конце диапазона адресов, если это так.
Модификация только для чтения памяти.
Указатель word
установлен, чтобы указать на первый char
строкового литерала, а затем цикл перебирает эту строку и присваивает каждому char
,
Передача возможного отрицательного значения в tolower
,
char
классификационным функциям требуется неотрицательный аргумент или специальное значение EOF
, Это прекрасно работает со строкой "HeLlo"
в предположении ASCII или без знака char
тип. Но в целом, например со строкой "Blåbærsyltetøy"
, проходя мимо каждого char
значение для tolower
приведет к передаче отрицательных значений; правильный вызов с ch
типа char
является (char) tolower( (unsigned char)ch )
,
Кроме того, код имеет утечка памяти, выделив немного памяти с new
а потом просто забываешь об этом.
Правильный способ кодирования очевидного намерения:
using Byte = unsigned char;
auto to_lower( char const c )
-> char
{ return Byte( tolower( Byte( c ) ) ); }
// ...
string word = "Hello";
for( char& ch : word ) { ch = to_lower( ch ); }
Уже есть два хороших ответа о том, как решить ваши проблемы, используя завершенные нулем c-строки и poitners. Для полноты картины я предлагаю вам подход, использующий строки c ++:
string word; // instead of char*
//word = new char[20]; // no longuer needed: strings take care for themseves
word = "HeLlo"; // no worry about deallocating previous values: strings take care for themselves
for (auto &it : word) // use of range for, to iterate through all the string elements
it = (char) tolower(it);
Это сбой, потому что вы модифицируете строковый литерал.
для этого есть специальные функции
использование
strupr
для создания строки в верхнем регистре и strlwr
для создания строки в нижнем регистре.
Вот пример использования:
char str[ ] = "make me upper";
printf("%s\n",strupr(str));char str[ ] = "make me lower";
printf("%s\n",strlwr (str));