백준 11655번 문제를 풀던 중 로직 자체는 분명 문제가 없는 것 같은데 올바른 결과가 나오지 않는 상황을 만났다.
#include<iostream>
#include<string>
using namespace std;
int main() {
string input = "";
string res = "";
getline(cin, input);
for(char c : input) {
cout << "c: " << c << " / num: " << (int)c;
if(65 <= c && c <= 90) {
c += 13;
if(c > 90) c -= 26;
} else if(97 <= c && c <= 122) {
c += 13;
if(c > 122) c -= 26;
}
cout << "/ c: " << c << " / num: " << (int)c << "\n";
res += c;
}
cout << res;
return 0;
}

's'의 ASCII 코드가 115임으로 13을 더한 후 -26을 빼면 'f'가 나올 것으로 예상했으나 -128이라는 결과를 얻었다.
문제의 원인은 범위 기반 반복문의 원소가 char 타입인 것에 있었다.
| char | int | |
|---|---|---|
| byte | 1 | 4 |
| 값의 범위 | -128 ~ 127 | –2,147,483,648 ~ 2,147,483,647 |
코드의 연산 흐름은 아래와 같다.
1. c += 13
2. if (c > 122)
2.1. 참일 경우: c -26 이후 res에 더하기
2.2. 거짓일 경우: c를 res에 더하기
반복문의 원소 타입이 char일 경우
0. c가 's'일 경우
1. c += 13 / 결과: -128(오버플로우 발생)
2. if (c > 122) / 결과: c는 -128임으로 추가 연산이 진행되지 않는다.
반복문의 원소 타입이 int일 경우
0. c가 's'일 경우
1. c += 13 / 결과 128
2. if (c > 122) / 결과: c는 122보다 큼으로 참일 경우를 계산
3. c -= 26 / 결과: 102('f')
#include<iostream>
#include<string>
using namespace std;
int main() {
string input = "";
string res = "";
getline(cin, input);
for(char c : input) {
int tmp = 0;
tmp = (int)c;
if(65 <= tmp && tmp <= 90) {
tmp += 13;
if(tmp > 90) tmp -= 26;
} else if(97 <= tmp && tmp <= 122) {
tmp += 13;
if(tmp > 122) tmp -= 26;
}
res += tmp;
}
cout << res;
return 0;
}

반복문의 원소를 int로 캐스팅하여 사용하니 정상적으로 결과 값이 출력되는 것을 확인할 수 있었다.