본문 바로가기

코딩테스트 공부

자주 하는 실수(단락 평가, off by one, 0으로 나누기, 중간 값의 오버플로)

단락 평가

논리 연산자 AND(&&)와 OR(||)의 조건식에서 첫 번째 피연산자의 평가 결과만으로 전체 표현식의 값을 결정할 수 있는 경우 두 번째 피연산자를 평가하지 않는다. 이를 단락 평가라고 한다.

아래와 같은 경우에 단락평가가 발생한다.

A && B에서 A가 false일 경우, B는 평가되지 않는다.

-> 첫 번째 피연산자가 false 이면 전체 조건식은 무조건 false이기 때문이다.

// 목적: A && B에서 A가 false일 경우 B는 평가되지 않음을 확인
#include <iostream>
using namespace std;

bool checkA() {
    cout << "checkA 실행" << endl;
    return false;
}

bool checkB() {
    cout << "checkB 실행" << endl;
    return true;
}

int main() {
    if (checkA() && checkB()) {
        cout << "둘 다 true" << endl;
    } else {
        cout << "조건 실패" << endl;
    }

    return 0;
}
// 출력결과: checkA 실행 \n 조건 실패

A || B 에서 A가 true인 경우 B는 평가되지 않는다.

-> 첫 번째 피연산자가 true이면 전체 조건식은 무조건 true가 되기 때문이다.

// 목적: A || B에서 A가 true일 경우 B는 평가되지 않음을 확인
#include <iostream>
using namespace std;

bool checkA() {
    cout << "checkA 실행" << endl;
    return true;
}

bool checkB() {
    cout << "checkB 실행" << endl;
    return false;
}

int main() {
    if (checkA() || checkB()) {
        cout << "최종 결과: true" << endl;
    }

    return 0;
}
// 출력결과: checkA 실행 \n 최종 결과: true

off by one

프로그램이 의도한 횟수보다 한 번 더 많거나 적게 반복되거나, 의도한 경계보다 앞이나 뒤의 요소를 한 위치만큼 벗어나 엑세스 하는 오류 off by one이라 한다.

// 목적: 배열 크기를 벗어난 인덱스에 접근하여 정의되지 않은 동작 발생
#include <iostream>
using namespace std;

int main() {
    int nums[5] = {10, 20, 30, 40, 50};

    for (int i = 0; i <= 5; i++) // i == 5일 때 nums[5]는 유효하지 않음
    {
        cout << nums[i] << " ";
    }

    return 0;
}
// 출력결과: 10 20 30 40 50 ??? (쓰레기값 또는 런타임 에러 발생 가능)

0으로 나누기

입력값이나 중간 계산 결과에 따라 분모가 0이 되는 경우 오류가 발생할 수 있습니다.

이러한 오류는 디버깅이 어렵고 예측하기 힘들기 때문에, 나누는 수가 0이 되는 상황을 방지하기 위해 항상 유효성 검사를 하는 습관을 들이는 것이 좋습니다.

// 목적: 나누기 연산 전에 분모가 0인지 확인하는 안전한 코드 예시
#include <iostream>
using namespace std;

int main() {
    int a = 10;
    int b = 0;

    if (b != 0) {
        int result = a / b;
        cout << "결과: " << result << endl;
    } else {
        cout << "오류: 0으로 나눌 수 없습니다." << endl;
    }

    return 0;
}
// 출력결과: 오류: 0으로 나눌 수 없습니다.

결과가 아닌 중간 값의 오버플로

각 변수의 타입은 표현할 수 있는 범위가 정해져있다.(예시 : int는 약 -21억 ~ 21억)

이 범위를 넘는 값을 저장하려고 하는 경우 오버플로가 발생하는데 최종적인 결과값이 넘는 경우는 분석하기 쉬우나 중간 계산 과정에서 오버플로가 발생하면 디버깅이 어렵다.

 

예시 1 : 2 * 21억 = 42억

결과값이 넘는 경우는 파악이 쉽다.

예시 2 : 2 * 5억 * 3 / 10

중간 계산 과정에서 30억이 될 때 오버플로가 발생하나 최종 결과 값은 3억으로 int 범위 안에 든다.

하지만 출력 값이 다른 값이 나오므로 중간 계산에서 오버 플로가 발생하면 파악이 어렵다.

 

출력 값이 예상과 다를 경우 이 부분도 확인을 해야한다.