본문 바로가기

Programming/C

C언어 포인터 기본(C언어 basic pointer)

반응형

 민규최를 위한 포인터 글


변수(variable)란 무엇인가?

수학에서 변수는 변할 수 있는 수, 즉 상수(constant)와 반대 개념으로 사용이 된다.


프로그래밍에서도 변수의 성질은 마찬가지이지만, 

변수는 데이터를 저장할 수 있는 메모리 공간에 붙인 이름(혹은 그냥 메모리 공간 자체)을 의미한다.

(메모리 공간에 이름을 적어 놓았기에 그 메모리 공간의 위치를 찾을 수 있어 해당 공간안에 있는 데이터 값을 바꿀 수 있다. 라고 생각하면 편함)


int a; 라는 코드를 실행하면, 아래 그림과 같이 메모리 공간이 할당되고(아래 그림에서 네모), 그 공간의 이름을 a라고 명명한다.



만약 여기서 a = 10; 이라는 코드를 실행하면, 아래 그림과 같이 a라는 메모리 공간 안에 10 이라는 데이터 값을 넣게 된다. 




그런데 왜 포인터 얘기는 안 하고, 뜬금없이 변수 얘기를 하는 것인가?

포인터가 바로 변수의 일종이기 때문이다.

포인터는 메모리의 주소 값을 저장하기 위한 "변수"이다.


[포인터 선언 및 참조( *, & 연산자)]

1
2
3
4
5
6
7
8
9
10
int main()
{
    void *a; //void형 포인터 (차후 설명)
    char *b; //char형 변수/상수의 주소 값을 가질 수 있는 포인터 b
    int *c; //int형 변수/상수의 주소 값을 가질 수 있는 포인터 c
    double *d; //double형 변수/상수의 주소 값을 가질 수 있는 포인터 d
 
    return 0;
}
 
cs

꼴 : "포인터타입 변수명" 

포인터 타입은 "자료형 + *" 으로 구성되며 연산자 *를 사용한다. 

자료형(data type)

크기

정수형

char

1byte

short

2byte

int

4byte

long

4byte

실수형

float

4byte

double

8byte

long double

8byte


포인터 타입(pointer type)

크기

정수형

char *

4byte 혹은 8byte

short *

4byte 혹은 8byte

int *

4byte 혹은 8byte

long *

4byte 혹은 8byte

실수형

float *

4byte 혹은 8byte

double *

4byte 혹은 8byte

long double *

4byte 혹은 8byte

참고) int* a, int *a, int * a 모두 다 같다. 하지만 명심하자, (포인터)변수 명은 *a가 아닌, a이다! 


& 연산자는 주소 값을 알아내기 위해 사용된다.

1
2
3
4
5
6
7
int main()
{
    int a = 10;
    int *pointerA = &a;
 
    return 0;
}
cs

위 code를 실행하면 순서가 다음과 같이 된다.


1. int a = 10;

메모리상에 int형 공간을 할당하고 이름을 a라고 한다. 

(이 때 프로그램이 잡은 메모리 공간의 주소는 0x1000이라 하자.)  

그리고 a라는 공간에 10이라는 값을 넣는다.


2. int *pointerA = &a;

메모리상에 int형 포인터 공간을 할당하고 이름을 pointerA라고 한다. 

(주의!!!  *pointerA가 이름이 아니다!!! *pointerA는 다른 의미. 아래에서 설명)

(이 때 프로그램이 잡은 메모리 공간의 주소는 0x2000이라 하자.)

&a는 a라는 공간의 실제 메모리 상의 주소(즉, 0x1000)을 알려준다.

&연산자는 주소 값을 구할 때 사용하는 연산자이다.

우리가 a = 10 이라고 하는 것 처럼,

pointerA = 0x1000 값을 assign한다.

 


하나의 그림으로 다시 그려보면, 아래와 같다



pointerA라는 (포인터)변수는 변수 a를 가리킬 수 있다.(==변수 a에 접근할 수 있다) 왜? a라는 공간의 주소를 알고 있으니까!

즉 pointerA를 통해 a라는 공간에 무슨 값이 있는지 알아낼 수 있다.

우리가 포인터를 선언할 때 

"자료형type *변수명" 으로 선언할 때 사용했던 * 연산자가 포인터가 가리키는 메모리 값을 참조 할 때도 사용이 된다.

1
2
3
4
5
6
7
8
9
10
int main()
{
    int a = 10;
    int *pointerA = &a;
 
    printf("%d\n", pointerA);
    printf("%d\n"*pointerA);
 
    return 0;
}
cs


6번 째 줄은, (포인터)변수 pointerA라는 메모리 공간에 있는 값을 출력한다.

즉, 0x1000이 출력이 된다(a라는 메모리 공간의 주소)

7번 째 줄은 (포인터)변수 pointerA가 가리키는 공간에 있는 값을 출력한다.

현재 메모리 0x1000에 있는 값을 출력한다는 말이다.

즉, 10의 값이 출력된다.




[포인터 타입]

포인터 타입(pointer type)

크기

정수형

char *

4byte 혹은 8byte

short *

4byte 혹은 8byte

int *

4byte 혹은 8byte

long *

4byte 혹은 8byte

실수형

float *

4byte 혹은 8byte

double *

4byte 혹은 8byte

long double *

4byte 혹은 8byte

모든 포인터 타입은 4byte 혹은 8byte로  크기가 동일한데, 왜 여러개의 타입이 존재하는 것일까?

포인터 타입이 크기가 동일한 이유는, 포인터 변수는 메모리공간의 주소를 담기 때문이다. 

만약, char 변수를 선언을 하든, double 변수를 선언을 하든, 두 변수가 할당 받는 메모리의 주소는 4byte 혹은 8byte 로 

동일할 것이기 때문이다.

하지만 char는 1byte 공간이 할당되고, double은 8byte 공간이 할당되므로 

포인터를 이용하여 메모리를 참조할 때, 몇 바이트를 읽을지 결정을 해주어야 한다. 그래서 다양한 타입이 존재한다.


1
2
3
4
5
6
7
8
9
10
int main()
{
    unsigned char a = 0xff;
    unsigned char *pointerA = &a;
 
    unsigned int b = 0xffffffff;
    unsigned int *pointerB = &b;
 
    return 0;
}
cs

위 코드를 그림을 그려보면 다음과 같이 된다.





반응형