C & C++, 일반

[C/C++] 헷갈리기 쉬운 기초 문법들

그레이트쪼 2016. 8. 19. 17:15

 ▪ freopen

- 파일을 stdin, stdout으로 출력할 때에 freopen 사용하면 된다

1
2
freopen("input.txt""r", stdin);
freopen("output.txt""w+", stdout);


 ▪ 출력 flushing

- 샘플 입력을 처리하는 도중에 timeout 발생하면 앞의 출력까지도 하지 못하는 상황이 발생하는데 이를 막기 위해 출력을 바로 바로 하는 옵션이다.

1
setbuf(stdout, NULL);

- 문제는 출력이 많은 경우 이러한 방식으로 출력하면 printf() 수행하는 데만도 많은 시간을 쏟게 된다. 이럴 경우 아래와 같이 옵션을 고쳐줄 있다.

1
2
char buffer[32767];
setvbuf(stdout, buffer, _IOFBF, sizeof(buffer));


 ▪ MAX_INT, MIN_INT

- 가장 작은 정수인 MIN_INT 부호 bit 1이고 나머지는 0이다.

1
const long long MIN_INT = 1 << 63;

- 가장 정수인 MAX_INT 부호 bit 0이고 나머지는 1이다.

1
const long long MAX_INT = ~(1 << 63);

참고로 이는 음수 표현을 "2의 보수법"을 사용하기 때문인데 "1의 보수법"이 양수값의 모든 bit를 반전시키고 "2의 보수법"은 반전시킨 bit에 1을 더하는 방식이다. 1이 0000…0001이니까 "1의 보수법"으로는 -1이 1111…1110이고 "2의 보수법"으로는 1111…1111이다. 

- 1의 보수법 대신 2의 보수법을 사용하는 이유는 0이 하나밖에 없고 덧셈을 할 때 한번에 가능하기 때문이다. 예를 들어, -1과 1이 더해져 0이되는 과정을 보자. 1의 보수법에서는 0000…0001 + 1111…1110 = 1111…1111이 되고 여기에 end around carry가 더해져 결국 0000…0000이 되는데 2의 보수법에서는 이것을 무시하므로 0000…0001 + 1111…1111 = 0000…0000이 되어버린다.  



 ▪ System time 출력

1
2
3
4
5
6
7
8
9
10
11
12
#include <windows.h>
 
LARGE_INTEGER li1, li2, liFreq;
 
QueryPerformanceFrequency(&liFreq);
QueryPerformanceCounter(&li1);
 
// do write your code
 
QueryPerformanceCounter(&li2);
 
printf("time: %ld / %ld\n", (double)(li2.QuadPart - li1.QuadPart), (double)liFreq.QuadPart);


 ▪ Structure 선언법

1
2
3
4
typedef struct {
    int val;
    struct node* next;
} node;

- typedef 활용하고, self pointer struct라는 키워드도 함께 붙여야 한다.


 ▪ Heap allocation and deallocation

1
2
node* aNode = (node*malloc(sizeof(node));
free(aNode);

- malloc free 사용하면 된다


 ▪ 배열의 생성과 접근

- [] * 자유롭게 호환된다

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
void test(char* input)
{
    printf("%s\n", input);
    printf("%c\n", input[3]); // 다시 index로 접근해도 무방하다
}
 
int main() {
    char string[] = "Hello World"// 선언 방식 유심히 기억하기
    test(string); // char* 형으로 넘겨줘도 된다.
    return 0;
}

- heap allocation시에는 포인터로만 선언 가능하다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <stdlib.h>
 
void test(int* input)
{
    printf("%d\n", input[3]); // 다시 index로 접근해도 무방하다
}
 
int main() {
    int* ptr = (int*malloc(sizeof(int)*5); // 선언 방식 유심히 기억하기
    for (i = 0; i < 5; i++) {
        ptr[i] = i; // index로 접근해도 무방하다
    }
    test(ptr);
    return 0;
}



 ▪ 함수 포인터

- 함수 이름 앞에 *가 붙는 형태, return type은 일반 함수처럼 있고 input param은 type만 있고 이름은 없는 형태이다. 

1
int (*FuncPtr) (intint);

- 함수의 대입은 리턴 타입과 input param의 타입이 일치하는 함수에만 가능하다. 

1
2
3
4
5
6
int add (int first, int second) {
    ...
}
 
FuncPtr = add;
FuncPtr = &add;        // this is also allowed

- typedef를 이용하여 타입 선언을 재활용할 수 있다. 

1
2
3
4
typedef int (*FuncPtr)(intint);
 
FuncPtr func = NULL;
func = add;

- 전형적인 사용 패턴

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
 
typedef int (*CalcFuncPtr)(intint);
 
int plus (int first, int second) {
    return first + second;
}
 
int minus (int first, int second) {
    return first - second;
}
 
int calculator (int first, int second, CalcFuncPtr func) {
    return func(first, second);
}
 
int main(int argc, char** argv) {
    CalcFuncPtr calc = NULL;
    int a, b;
    char op;
    int result = 0;
 
    scanf ("%d %c %d"&a, &op, &b);
 
    switch (op) { 
    case '+'
        calc = plus;
        break;
    case '-':
        calc = minus;
        break;
    }
 
    result = calculator (a, b, calc);
    printf ("result : %d", result);
 
    return 0;