자료형의 크기를 잊지말자

주성천·2023년 10월 4일

문제 상황


백준 11655번 문제를 풀던 중 로직 자체는 분명 문제가 없는 것 같은데 올바른 결과가 나오지 않는 상황을 만났다.

백준 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 타입인 것에 있었다.

charint
byte14
값의 범위-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로 캐스팅하여 사용하니 정상적으로 결과 값이 출력되는 것을 확인할 수 있었다.

profile
기록과 정리

0개의 댓글