C pointer
Sunrin/Layer7

C pointer

처음 들었을 때 생각났던 것은 발표할 때 사용하는 프레젠테이션 레이저 포인터였다.
레이저 포인터는 발표 자료 등을 가리키는 역할을 한다.
C 포인터도 무언가를 가리키는 역할을 하지 않을까 싶다.

I. 포인터(Pointer)

먼저 주소값은 무엇인가?

데이터의 주소값은 어느 데이터가 저장된 메모리의 처음 시작하는 주소를 말한다.

int형 데이터로 예시를 들어보았다.
아래 예시에서는 메모리의 시작하는 주소인 0x11이 데이터의 주소값이 된다.
int형 데이터는 4바이트의 크기를 가지기 때문에 0x10~0x13의 메모리를 차지한다.
C에서는 주소값을 1바이트 크기의 메모리 공간으로 나누기 때문에
4byte는 네 칸으로 표현된다.


포인터는 무엇인가?

C에서 포인터는 메모리의 주소값을 저장하는 변수이다.
포인터는 데이터의 주소값을 가리키는 역할을 한다.

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
int main() {
    int a = 17;
    int *ptr1 = &a; //ptr1 포인터변수에 a의 데이터의 주소값을 저장한다.
    printf("a의 데이터의 주소값 : 0x%x\n",&a);
    printf("a의 데이터의 주소값 : 0x%x\n",ptr1);
 
    return 0;
}
 
cs

 

실행결과를 통해서 알 수 있는 것 처럼 &a는 ptr1이다.


포인터 변수는 *(역참조 연산자)와 &(주소 연산자)를 사용해서 선언한다.

아래 세 개의 방법 중 어떤 것으로 해도 상관없다.

1
2
3
4
5
int a = 17;
int *ptr1 = &a;
int* ptr2 = &a;
//int * ptr3 = &a;
 
printf("ptr1 : 0x%x\nptr2 : 0x%x",ptr1,ptr2);
cs

 

실행결과는 똑같다.

II. 포인터 연산

- 연산하는 값이 메모리 주소이므로 곱하거나 나누는 연산은 의미가 없다.
한다고 해도 컴파일 에러가 발생한다.
- 포인터 연산은 포인터 자료형의 크기만큼 더하거나 뺀다.

1. 포인터의 덧셈

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main(){
    int arr[4= {1,2,3,4};
    int *ptr1 = &arr[0];
    printf("ptr1   = 0x%x, 요소 : %d\n" , ptr1 ,*ptr1);
    printf("ptr1+1 = 0x%x, 요소 : %d\n" , ptr1 + 1 , *ptr1+1);
    printf("ptr1+2 = 0x%x, 요소 : %d\n" , ptr1 + 2 , *ptr1+2);
 
    return 0;
}
cs

 

배열을 선언, 초기화했다.
ptr1이 arr[0]의 주소값을 담고 있다.

ptr1에 1을 더하는거니까 ptr1+1이 0x61fe01이 되어야 할 것 같다.
하지만 포인터는 자료형의 크기만큼 연산한다.
위에 있는 예시로 다시 정리하면,
ptr1이 int형 변수(4바이트)이기 때문에 ptr1에서 4 증가하여 0x61fe04가 된 것이다.

이해를 돕기 위한 그림으로 주소값은 위에서 작성한 코드와 무관함.



2. 포인터의 뺄셈

1
2
3
4
5
6
7
8
9
#include <stdio.h>
    int arr[4= {1,2,3,4};
    int *ptr2 = &arr[3];
    printf("ptr2   = 0x%x, 요소 : %d\n" , ptr2 ,*ptr2);
    printf("ptr2-1 = 0x%x, 요소 : %d\n" , ptr2 - 1 , *ptr2-1);
    printf("ptr2-2 = 0x%x, 요소 : %d\n" , ptr2 - 2 , *ptr2-2);
    
    return 0;
}
cs

 

뺄셈도 덧셈과 같은 방법으로 이해할 수 있다.

III. 포인터 활용

1. Call by value (값에 의한 호출)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
 
    void swap(int num1, int num2) {
        int tmp;
        tmp = num1;
        num1 = num2;
        num2 = tmp;
        printf("<swap한 후 함수안>\nnum1 : %d, num2 : %d\n",num1, num2);
        //매개변수는 바뀜
    }
 
    int main(){
        int num1=111, num2=222;
        printf("<swap하기 전>\nnum1 : %d, num2 : %d\n",num1, num2);
        swap(num1, num2);
        printf("<swap한 후 main안>\nnum1 : %d, num2 : %d\n",num1, num2);
        //원래 변수인 num1과 num2는 바뀌지 않음
        return 0;
    }
cs


Call by value는 함수에서 값을 복사해서 전달하는 방식으로, 인자값을 함수의 매개변수에 복사한다.
이때 인자로 전달한 변수와는 다른 변수가 되고 매개변수를 변경해도 원래 변수에 영향을 미치지 않는다.

2. Call by reference (참조에 의한 호출)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
 
void swap(int *num1, int *num2) {
    //num1, num2는 주소값
    //(swap 전의)*num1, *num2는 각각 111,222
    int tmp;
    tmp = *num1;
    *num1 = *num2;
    *num2 = tmp;
    printf("<swap한 후 함수>\nnum1 : %d, num2 : %d\n",*num1, *num2); //바뀜
 
}
 
int main(){
    int num1=111, num2=222;
    printf("<swap하기 전>\nnum1 : %d, num2 : %d\n",num1, num2);
    swap(&num1, &num2);
    printf("<swap한 후 main>\nnum1 : %d, num2 : %d\n",num1, num2); //바뀜
    return 0;
}
cs

포인터를 사용해서 call by reference를 구현할 수 있다.
Call by reference는 call by value와 다르게 변수를 복사만 하는 것이 아니라 변수의 값도 변경할 수 있다.

'Sunrin > Layer7' 카테고리의 다른 글

Webhacking Project - PHP와 MySQL  (0) 2020.08.12
Dreamhack - Introduction of Webhacking 정리  (0) 2020.08.07
Stack Frame  (0) 2020.07.10
Python 문법  (0) 2020.07.08
C Pointer 실습  (0) 2020.07.03