Я пытаюсь заменить каждую букву в строке следующей буквой (a -> b, c -> d и т. д.).
Я получаю случайные символы или XXXX после компиляции и запуска программы.
#include <iostream>
#include <string>
using namespace std;
int main(){
char arr1[26] = {'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
'q', 'r', 's', 't',
'u', 'v', 'w', 'x',
'y', 'z'};
string x;
getline(cin, x);
for(int i = 0; i < x.length(); i++){
for(int h = 0; h < 26; h++){
if (x[i] == arr1[h]){
x[i] = arr1[h + 1];
}
}
}
cout << x;
return 0;
}
Я думаю, что делаю что-то не так с типом данных char.
Пожалуйста, отредактируйте свой вопрос и добавьте минимальный воспроизводимый пример, как это требуется здесь. Внимательно прочитайте эту связанную статью (возможно, не один раз) и соответствующим образом обновите свой вопрос.
После компиляции я получаю случайные символы или XXXX. Успешная компиляция означает только отсутствие синтаксических ошибок. Это не имеет никакого отношения к тому, является ли код логически корректным. Как видите, проблема заключается в логике вашего кода, а не в синтаксисе.
@avent Показать входные данные, ожидаемый результат и фактический результат.
Вы ведь знаете, что делать это с помощью цикла for ужасно неэффективно, верно? Прямой поиск был бы лучше.
Было бы чрезвычайно полезно попробовать использовать отладчик в этой программе.
Не бывает глупых вопросов, но есть вопросы, которые нужно задавать с МНОГО боеприпасов, и вообще, чем больше работы вы делаете, чтобы вооружиться, тем больше вероятность, что вы решите проблему самостоятельно. Хороший процесс постановки вопросов также является хорошим процессом отладки. Лучшие спрашивающие не задают много вопросов, но те, которые они задают, действительно странные.





У вас есть две проблемы с вашим кодом. Во-первых, если h == 25, то h+1 есть 26, а arr1[26] нет. Вот откуда берутся «случайные символы».
Вторая проблема заключается в том, что после замены символа вы все равно проверяете его еще раз, и он находит другое совпадение и заменяет его, а затем проверяет заново (и т. д.).
Вы можете изменить свое утверждение if следующим образом:
if (x[i] == arr1[h]){
x[i] = arr1[(h + 1) % 26]; // in case h + 1 > 26, loop back to 0 (i.e. 'a')
break; // don't keep searching for another match
}
Вы можете изменить способ обработки значения, когда захотите, но для простоты я просто увеличил значение до 0.
Или измените размер массива на 27 и поставьте дополнительный 'a' в последнюю позицию. Тогда arr1[h+1] всегда работает.
Внутри внутреннего цикла for
for(int h = 0; h < 26; h++){
if (x[i] == arr1[h]){
x[i] = arr1[h + 1];
}
}
если буква x[i] найдена в массиве arr1 в позиции h, то из-за этого оператора она заменяется на букву arr1[h + 1]
x[i] = arr1[h + 1];
Таким образом, на следующей итерации цикла for (если h + 1 меньше 26) обновленная буква снова находится и заменяется следующей буквой в массиве arr1. Итерации цикла for продолжаются, пока условие h < 26 истинно. В результате на последней итерации цикла for выражение arr1[h + 1] обращается к памяти вне массива arr1, что вызывает неопределенное поведение.
Вам нужно прервать внутренний цикл for, как только в массиве x[i] будет найдена буква, равная выражению arr1. А если найденная буква 'z' (последний элемент массива), то выражению x[i] нужно присвоить букву 'a' (arr1[0]) вместо epxression arr1[h+1]
Но обратите внимание: использование оператора break внутри циклов в целом является плохим стилем программирования. Более того, нет необходимости использовать обычные циклы for, вводящие вспомогательные переменные i и h. Например, вместо внешнего цикла for вы можете использовать диапазон, основанный на цикле for. Также не используйте магические числа в качестве 26. Использование магических чисел обычно приводит к ошибкам в программе.
По крайней мере, вы могли бы написать заголовок <iterator> следующим образом.
char arr1[] = {'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
'q', 'r', 's', 't',
'u', 'v', 'w', 'x',
'y', 'z'};
//...
for( size_t h = 0; h < std::size( arr1 ); h++){
или оператор цикла for может быть записан так же, как
for( size_t h = 0, n = std::size( arr1 ); h < n; h++){
Могу предложить следующее решение.
#include <iostream>
#include <string>
#include <string_view>
#include <iterator>
int main()
{
const std::string_view lower_case_letters = "abcdefghijklmnopqrstuvwxyz";
if (std::string s; std::getline( std::cin, s ))
{
for (char &c : s)
{
auto pos = lower_case_letters.find( c );
if (pos != std::string_view::npos)
{
c = lower_case_letters[ ( pos + 1 ) % std::size( lower_case_letters ) ];
}
}
std::cout << s << '\n';
}
}
Вывод программы может выглядеть следующим образом
abcxyz
bcdyza
Или, чтобы справиться с чувствительностью к регистру, мы можем сделать что-то вроде:
#include <iostream>
#include <string>
using namespace std;
int main() {
string x;
getline(cin, x);
for (char &c : x) { // Iterate through characters by reference
if (isalpha(c)) { // Check if the character is a letter
if (tolower(c) == 'z') { // Handle 'z' and 'Z'
c = tolower(c) == 'z' ? 'a' : 'A';
} else {
c++; // Shift to the next letter
}
}
}
cout << x << endl;
return 0;
}
Решенные проблемы:
когда вы достигаете буквы «z», arr1[h + 1] пытается получить доступ к элементу за пределами массива, что приводит к неопределенному поведению
Вы можете вычислить сдвинутый символ напрямую. Не надо а
вложенный цикл
Код не обрабатывает заглавные буквы
Код выдаст неправильный вывод, если будет использоваться таблица символов EBCDIC.
Вы заменяете каждого символа несколько раз. И вы читаете дальше конца
arr1.