코딩과 디버깅에 관하여-1
코딩의 중요성을 간과하지 말라
프로그래밍 대회에서 성적에 가장 중요한 요인은 무엇일까?
- 아무리 강력한 알고리즘이라도 모든 문제에 적용할 순 없다.
- 반면 코딩 과정은 어떤 문제를 풀 때나 항상 필요하다.
-
디버깅을 위해 스파게티 코드가 아닌 읽기 쉬운 코드를 작성해야한다
- 최대한 간결하고 일관되게 작성하라
이 의견에 나도 동의한다 디버깅 뿐만 아니라 팀 단위로 코딩작업을 진행할 땐 이는 무척이나 중요하다. 42서울 프로젝트 중 변수명의 의미를 나만 알아 볼 수 있게 작성 하여 팀원이 디버깅할때 시간이 무척 오래 걸렸던 기억이 있다.
좋은 코드를 짜기 위한 원칙
좋은코드란?
- 실무에서 좋은 코드
간결한 코드를 작성하기
-
최대한 코드를 줄여서 작성하라 (숏코딩을 말하는게 아님, 가독성 있게 줄여야 함)
-
전역변수의 광범위한 사용을 지양하라.(프로그램의 흐름을 파악하기 어렵다.)
-
흑마법 - 매크로를 사용하여 단축시킬 수 있다.
-
ex)
-
#define FOR(i, n) for(int i = 0; i < (n); i++) bool hasDuplicate(const vector<int>& array) { FOR(i, array.size()) FOR(j,i) if(array[i] == array[j]) return true; return false; }
이러한 코드는 i와 j를 혼동하여 오류가 나는걸 막을 수 있지만 정말 신중하게 사용하여야 한다.
-
-
42서울에서 NORM때문에 모든 함수 25줄 제한, 전역변수 금지,, 매개변수 4개이하, 파일에 함수 5개이하.. 선언과 초기화 동시에 금지.. 등등 여러가지가 생각난다.
적극적으로 코드 재사용하기
- 같은 코드가 반복된다면 이를 모듈화하여라(함수나 클래스로 분리하라)
표준 라이브러리 공부하기
- STL은 이미 충분히 검증되었기 때문에 이 매뉴얼을 꼭 알아둬라 (실제 프로그래밍 대회에서 일일히 큐나 스택과같은 자료구조를 만들 시간이 없다.)
항상 같은형태로 프로그램을 작성하기
- 일관되게 코드를 작성하라(while문 do-while문, for문의 무분별한 사용, 함수의 파라미터 순서 등)
일관적이고 명료한 명명법 사용하기
- 함수와 변수명을 무슨 기능과 무슨역할을 하는지 알아볼 수 있게 작성하라
모든 자료를 정규화하여 저장하라
- 같은 자료를 두 가지 형태로 저장하지 마라
코드와 데이터 분리하기
- 데이터로 저장 할 수 있는건 함수가 아닌 자료구조로 저장하자
자주 하는 실수
산술 오버플로우
계산 과정에서 변수의 표현범위 벗어남
배열 범위 밖 원소에 접근
세그먼트 폴트이다.
int array[10], t;
array[10]에 값을 넣게되면 4가 바뀐다. 이는 런타임 에러도 내지 않고, 찾기 어려운 버그가 된다.
일관되지 않은 범위 표현 방식 사용하기
- 반 열린구간 (half-open interval)을 사용하자
Off-by-one 오류
- 계산에서 한개의 값을 빼먹는 경우, 이는 idx번호때문에 많이 발생한다.
컴파일러가 잡아주지 못하는 상수 오타
- 64비트 정수형 뒤에는 LL을 붙이자
- 문자열 상수에 오타를 쓰지 말자
스택 오버플로
- stack이 overflow된 경우, 재귀호출이 너무 깊을때 나타난다.
다차원 배열 인덱스 순서 바꿔쓰기
- 인덱스의 순서를 잘 알아둬야 한다. (나도 처음에 x, y의 순서가 헷갈렸다.)
잘못된 비교 함수 작성
1. a < a는 항상 거짓이다 이를 비반사성(irreflexivity)라고 한다.
2. a < b가 참이면 b < a는 거짓이다. 이를 비대칭성(asymerty)라고 한다.
3. a < b가 참이고 b < c가 참이면 a < c 도 참이다. 이를 전이성(transitiviy)라고 한다.
4. a < b 와 b < a가 모두 거짓이면 a == b가 참이다. 또한, a 와 b가 같고 b와 c 가 같다면
a와 c도 같아야 한다. 이를 상등 관계의 전이성(transitivity of equivalence)라 한다.
- 이를 유의하여 정렬함수를 잘 작성하자
최소, 최대 예외 잘못 다루기
- 최솟값과 최댓값이 예외가 되는 문제가 꽤 많으니 유의하자.
연산자 우선순위 잘못 쓰기
if (b & 1 == 0)
얼핏보면 b의 최하 비트가 0일 때 참인것으로 보인다.
하지만 &
연산자는 ==
연산자보다 우선순위가 낮다. 따라서 아래로 해석된다.
if (b & (1 == 0))
이는 항상 false가 나온다. 이를 유의하자
너무 느린 입출력 방식 선택
gets()와 cin 의 입출력 방식 차이가 두배 이상 차이가 날때가 있다. 입력으로 받거나 출력할 변수의 수가 1만개를 넘어가면 이를 유의하자
변수 초기화 문제
이전 입력에서 사용한 전역변수값을 초기화 하자
이를 알수 있는 방법은 같은 입력 예제를 동일하게 반복해 보는것이다.