백준 알고리즘 1330번

문제

두 정수 A와 B가 주어졌을 때, A와 B를 비교하는 프로그램을 작성하시오.

입력

첫째 줄에 A와 B가 주어진다. A와 B는 공백 한 칸으로 구분되어 있다.

출력

첫째 줄에 다음 세 가지 중 하나를 출력한다.

  • A가 B보다 큰 경우에는 '>'를 출력한다.
  • A가 B보다 작은 경우에는 '<'를 출력한다.
  • A와 B가 같은 경우에는 '=='를 출력한다.

출처 : https://www.acmicpc.net/problem/1330

사소한 오해로 인해 커진 문제


[문제]에서 두 정수 A와 B가 주어진다고 했다.

[입력]에서 첫째 줄에 A와 B가 주어지며 공백 한 칸으로 구분되어진다고 했으므로
ex) 1 3 과 같이 공백이 포함된 문자열로 받아들인다고 오해하였다. 사실 cin을 이용하여 각각 받아야 하는 문제였다.

C++을 시작한지 얼마 되지 않은 상황에서 계속 마주하는 오류는 이제 서서히 익숙해진다.

하지만 그 오류가 발생하면 "왜 이 오류가 발생했지?"라는 생각을 하며 파고든다.

답답하리만큼 시간이 오래걸리긴 하지만 그만큼 한 단계 성장한다고 생각하자 : /

소스코드와 정답 비교
  • 백준 1330번 정답코드
#include <iostream>
using namespace std; 
int main(){ 
	int a, b; 
    cin>>a>>b; 
	
    if (a>b){ 
    	cout<<">";
    }else if (a<b){ 
    	cout<<"<"; 
    }else
    	cout<<"=="; 
return 0; 
}
  • 로보봇이 작성한 백준 1330번 정답 코드
#include <iostream>
#include <string> 

using namespace std;

int main(){
    
    string num;

    getline(cin,num);

    char c = num[0];
    char d = num[2];

    int a = c-'0';
    int b = d-'0';

    if (a > b){

        cout<<">"<<endl;
    }else if (a < b){

        cout<<"<"<<endl;
    }else{

        cout<<"=="<<endl;
    }


    return 0;
}



어떤 차이점이 있을까?

정답 소스코드는 std::cin 함수를 이용하여 변수를 받아들이기 때문에 간단한 알고리즘으로 문제를 해결할 수 있다.

내가 작성한 소스코드는 문자열을 받아들여야 하기 때문에 복잡한 과정이 들어갔다.

내가 설계한 알고리즘을 간단하게 설명하자면 다음과 같다.

알고리즘 START
사용자로부터 문자열을 받는다
문자 배열에서 숫자를 추출한다
If문을 통해 결과를 도출한다.

간단해 보이지만 과정이 복잡하다.

  1. 공백을 포함한 문자열을 받아야 한다. string 객체를 도입했다.
  2. string 객체에 공백을 포함한 문자열 값을 받기 위해 getline() 함수를 이용한다.
  3. string 객체에 저장된 문자 배열에서 비교할 값들을 추출한다. 이 값들은 char 객체에 문자 형태로 저장한다.
  4. char 객체에 저장된 각 값들은 int 객체에 저장되면 ASCII코드의 숫자로 출력된다.
    • ASCII 코드가 1byte이기 때문에 0부터 9까지는 [48 ~ 57] 까지의 정수로 나타난다.
    • 소스코드상에서 문자를 서로 빼는 것처럼 보이지만 사실은 '0'의 ASCII코드 넘버인 48을 기준으로 상대 측정하는 것이다.
  5. 정수로 출력된 각 A와 B의 값을 if문을 통해 비교하고 값을 도출한다.


간결해야 하는 코딩에서 이와 같은 오류는 치명적이기 때문에 생각을 잘 정리하고 문제 해석 능력을 길러야 함을 깨달았다.

배운 것들을 살펴보자

1. char와 string

  • char
    • char는 1byte의 문자 변수 지정자이다.
    • 1byte를 사용하는 ASCII 코드로 해석한다. 함수에 정수를 집어넣게 되면 해당되는 ASCII 코드 값을 출력한다.
    • char [...] 문자열을 배열로 저장할 수 있다. 수정이 가능하다.
    • char* 포인터를 이용하여 문자열을 저장할 수 있다. 할당된 주소 값을 이용하기 때문에 수정이 불가능하다.
  • string
    • string은 C++에 객체지향이 도입되며 생긴 함수이다.
    • string을 사용하기 위해서 <string>이라는 헤더 파일을 정의해야 한다.
    • 다양하고 편리한 멤버 함수들이 존재하므로 사용하기 편리하다.

string함수를 처음 쓸 때는 굉장히 복잡하고 이해하기 힘들었다. 하지만 이해하고 나니 활용하기 너무 좋을 것 같았다.

멤버 함수는 그 종류가 굉장히 많다. 내가 이 코드에서 사용했으면 좋았을법한 멤버함수 몇 가지를 적어본다.

[string의 멤버 함수]

1. string str.front()
여기서 str은 변수이고 이 뒤에. front()가 붙는 형태이다. 저장된 변수의 맨 앞 인자를 반환하는 멤버 함수이다.
나의 소스코드에서 문자 배열을 따로 지정하고 불러올 필요 없이 이 함수 하나면 변수를 호출할 수 있었다.

2. string str.back()
저장된 변수의 가장 뒤쪽의 인자를 반환하는 멤버함수이다.

3. string str.at(n)
저장된 변수에서 인덱싱하여 인자를 반환하는 멤버 함수이다. index가 string의 범위를 벗어나면 [예외]를 반환한다.

4. string str.operator[n]
저장된 변수에서 인덱싱하여 인자를 반환하는 멤버 함수이다. index의 범위를 검사하지 않으며 string의 범위를 초과해도 [예외] 반환은 없다.

2. cin.getline() 과 getline()

  • cin.getline(char* str, streamsize n, char dlim);
    • istream라이브러리에 있는 함수이다.
    • 쉬운 표현 : cin.getline(변수 주소, 받을 문자수, 입력을 멈출 문자);
    • char dlim(입력을 멈출 문자)는 생략 가능하다. 생략시 엔터적용됨.
  • getline(istream& is, string str, char dlim​);
    • string라이브러리에 있는 함수이다.
    • 쉬운 표현 : getline(입력스트림 오브젝트, 변수, 입력을 멈출 문자);
    • 입력스트림 오브젝트는 보통 cin을 사용한다.
    • char dlim(입력을 멈출 문자)는 생략 가능하다. 생략시 엔터적용됨.

3. cin.ignore()

cin.ignore() 는 getline 함수들을 보조해주는 역할을 한다.

이런 코드를 살펴보자.

string str1; 
int num1; 

cin>>num1; 
getline(cin,str1);

string객체에 str1 변수를 지정하였고, int객체에 num1이라는 변수를 지정하였다.

컴파일하고 실행하게 되면 cin으로 num1을 받는데는 문제 없지만 getline함수가 무시되고 종료된다.

왜 이런일이 발생할까? 이유는 버퍼때문이다.

우리가 cin을 이용하여 정수를 입력하고 엔터를 치게된다. '\n' 말이다.

이 버퍼가 남아서 그다음 getline 함수에 영향을 끼친다.

따라서 getline함수 앞전에 cin.ignore를 선언해주면서 버퍼를 비워주면 위와같은 문제를 해결할 수 있다.

string str1; 
int num1; 

cin>>num1; 
cin.ignore(); 
getline(cin,str1);

이러한 이유때문에 getline함수를 사용함에있어 cin.ignore의 역할은 중요하다고 볼 수 있다.

마무리 하며

이 한문제로 오늘 하루를 고민하고 찾아보며 골머리를 앓았다.

C++을 시작한지 얼마 되지 않은 시점에서 가장 중요한건 스스로 고민하면서 문제를 해결해 나가는 것이라고 생각했다.

오류가 난 부분을 찾아가다보면 밑도 끝도 없는 구렁텅이에 빠진 기분이였고, 이 한문제로 하루를 고민했다는 점도 스스로를 힘들게 했다.

이 방법으로 공부하는게 맞을까? 하면서도 또 다른 방법들이 눈에 들어온다.

각 공부법의 장단점이 명확하다는 점에서 갈팡질팡하며 딜레마에 빠진다.

하지만 알고리즘은 효율적이여야 하며 간단명료하게 표현되어야 한다고 생각하게 됐다.

스스로 시도는 해보되 효율적인 알고리즘을 도입하여 능력을 발전시키는 방향이 맞겠다는 생각을 했다.

'코딩 > C++' 카테고리의 다른 글

[C++] Mutex  (1) 2024.01.21
[C++]Data structure alignment(데이터 구조 정렬)  (0) 2022.01.13