프로그래밍 문제풀이 사이트에서 재미로 해 볼 만한 숏코딩 기법들.
소스코드의 바이트 수를 최대한 줄여보는 것이다.
특정 컴파일러에서만 되는 부분이 있기 때문에 문제풀이 사이트의 컴파일러 종류와 버전을 고려해서 해야 한다...
1. 컴파일러의 특성에 따라 코드를 최대한 생략한다.
gcc컴파일러에서는 #include <stdio.h>를 생략해도 되고,
main함수의 반환형이나 리턴을 생략해도 된다.
main(){printf("Hello Wolrd!");} |
2. 문자열 출력만 있는 경우 printf()대신 puts()함수를 사용한다.
2바이트를 더 줄일 수 있다.
main(){puts("Hello Wolrd!");} |
3. 반복문을 쓸 때 scanf()함수의 반환값을 이용한다.
scanf()함수는 EOF(end of file)가 입력되었을 때 0을 반환하므로
이것을 이용하여 for문을 작성한다.
for(;~scanf("%d",n);) |
4. 배열 입력을 받을 때 포인터를 사용한다.
첨자(subscript)연산자를 사용하는 것보다 1바이트를 더 줄일 수 있다.
경우에 따라 i를 0으로 초기화하는 구문이 필요할 수도 있다.
a[100],i; main(){ for(;~scanf("%d",a+i++);); } |
5. 배열을 전역변수로 선언한다.
이렇게 선언된 배열은 0으로 초기화되어 있어서 초기화하는 구문을 줄일 수 있다.
a[100];main(){} |
6. 변수를 main()함수 안에서 선언하는 대신 매개변수 자리에 쓴다.
세미콜론과 데이터형을 생략할 수 있다.
main(a,b,c,d){} |
7. 테스트 케이스 입력을 버린다.
3번에서처럼 scanf()의 반환값을 이용하면 테스트 케이스 입력을 버려도 되는 경우가 있다.
이 코드는 다른 메모리를 침범할 수 있는 위험이 있지만 Judge사이트에서 채점만 통과하면 그만이다...
main(T){ gets(&T); for(;~scanf("%d",n);){ //n처리 }} |
8. 문자열을 선형탐색할 때 널문자의 값이 0인 것을 이용한다.
널 문자('\0')는 정수로 0이기 때문에 for문 조건식에서 조건을 끝내는 데 사용할 수 있다.
char s[100]; gets(s); for(i=0;s+i++;){ //처리 } |
9. 한 테스트 케이스에 대한 결과출력을 for문 증감식에서 한다.
세미콜론을 생략함으로써 1바이트를 더 줄일 수 있다.
for문 안의 구문을 1행으로 만들 수 있으면 2바이트를 추가로 줄일 수 있다.
for(;~scanf("%d",a);printf("%d",b)){ //처리 } |
10. 3항 연산자(?:)를 사용한다.
가독성을 희생하여 짧은 코드를 얻을 수 있다.
puts(a%3?"Fizz":"Buzz"); |
min=d1<d2?(d1<d3?d1:d3):(d2<d3?d2:d3); |
11. 홀짝 판별과 동등비교시 비트 연산자를 사용한다.
홀수/짝수 판별을 할 때 &(AND)연산자를 사용하여 2바이트를 줄일 수 있고,
동등비교를 할 때 != 대신 ^(XOR)연산자를 사용하여 1바이트를 줄일 수 있다.
전자는 연산자우선순위가 아래 예시와 같을 때 해당한다.
if(a&1) //a가 홀수일 때 참이 됨 |
if(a^b) //a!=b일때 참이 됨 |
12. 특정 컴파일러에 의존적인 함수를 찾는다.
예를 들어 엔디안을 변환하는 POSIX 라이브러리 함수로 이런 문제를 63바이트 이내로 코딩할 수 있다.
13. 효율적인 알고리즘으로 문제를 푼다.
이 방법이 근본적으로 코드 길이를 줄일 수 있는 방법이다.
1부터 n까지의 정수를 모두 더하는 코드를 작성할 때 반복문을 사용하는 대신 n*(n+1)/2 로 계산하면 더 짧다.
한 원소만 제외하고 같은 원소가 2개씩 들어있는 배열 ex) {5, 3, 2, 4, 1, 4, 5, 1, 3} 에서 단독으로만 존재하는 원소가 무엇인지 찾으려면, 반복문을 돌릴 필요 없이 모든 원소를 XOR로 누적하면 된다.
이 밖에도 기계어를 사용하는 등 여러 가지 재미있는 방법들이 많다..