메모리의 주소를 가지고 있는 변수입니다. 컴퓨터의 메모리에는 바이트 단위로 주소가 매겨져있는데 이 주소를 이용하여 접근이 가능합니다.

포인터를 알아보기 전에 변수의 주소에 대해서 알아보겠습니다.



변수는 컴퓨터 메모리에 저장된다.


지금까지 우리는 변수를 만들어서 사용해 왔습니다. 이런 변수는 모두 메모리에 만들어집니다. 이러한 메모리에는 각 바이트마다 고유한 주소가 존재합니다. 우리는 이 주고를 이용하여 메모리 바이트에 접근이 가능합니다. 만약 시스템이 20바이트의 메모리를 가지고 있다면, 첫 번째 바이트의 주소는 0부터 시작해서 19까지의 주소가 존재합니다.


프로그램에서 변수를 만들면 컴파일러에 의해여 메모리 공간을 차지합니다. 전에 배웠듯이 변수에 따라서 메모리공간이 다른건 아실껍니다.



주소 연산자 &


C언어에서는 변수의 주소를 계산하는 연산자 &가 존재합니다. 주소 연산자 &는 변수의 이름을 받아서 변수의 주소를 반환합니다.

예를 들어서

1
int i; 라고 정의하였으면, 변수 i의 주소는 &i를 하면 알 수있다. 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
 
int main()
{
    int i = 10;
    char c = 69;
    double f = 12.3;
    
    printf("i의 주소: %u\n"&i);
    printf("c의 주소: %u\n"&c);
    printf("f의 주소: %u\n\n"&f);
 
    printf("i의 주소: %x\n"&i);
    printf("c의 주소: %x\n"&c);
    printf("f의 주소: %x\n"&f);
}
cs



포인터의 선언


point + er 가리키는 것입니다.. 포인터는 변수의 주소를 가지고 있는 변수입니다. 같은 변수이지만 저장하고 있는 것은 데이터가 아닌 메모리의 주소입니다. 이것뺴고는 변수와 거의 동일하기 때문에 초기화를 해줘야합니다.


포인터를 선언하려면 포인터가 가리키게되는 대상을 쓰고 *을 붙인 다음, 포인터의 이름을 씁니다. 수식과는 아무 상관이 없습니다.

1
2
3
4
5
int *p;
 
int == 정수를
* == 가리키는
== 포인터 p
cs



포인터의 초기화


1
2
3
int i = 10// 정수 변수i가 선언되고 10으로 초기화된다/.
int *p; // 정수 포인터가 선언된다.
= &i; //포인터p에 i의 주소가 저장된다.
cs

이런식으로 해주면 됩니다. 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
 
int main()
{
    int i = 10;
    double f = 12.3;
    int *pi = NULL;
    double *pf = NULL;
 
    pi = &i;
    pf = &f;
    printf("%u %u\n", pi, &i);
    printf("%u %u\n", pf, &f);
    return 0;
}
cs

컴퓨터 마다 주소는 달라지지만 포인터를 이용하여 정상적으로 주소를 출력한 것을 볼수 있습니다.



간접 참조 연산자 *


앞서 &는 주소를 반환한다고 말했습니다. 간접 참조 연산자*는 p가 가리키는 주소에 저장된 내용을 읽어옵니다.

1
2
3
4
int i = 10// 정수 변수i가 선언되고 10으로 초기화된다/.
int *p; // 정수 포인터가 선언된다.
= &i; //포인터p에 i의 주소가 저장된다.
printf("%d \n"*p);  //10이 출력된다.
cs

*p는 p가 가리키는 위치에 있는 데이터를 가져오라는 의미입니다. p는 p가 가리키는 위치에 무엇이 있는지 모르기때문에, p가 int형 포인터라면 4바이트를 읽어들입니다. 포인터의 타입이 없다면, 포인터를 이용하여 데이터를 읽어 들일 때 몇개의 바이틀르 읽어야 할지 알 수 없게 됩니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*변수와 포인터를 연결한 후에 변수의 주소와 포인터의 값을 출력.*/
 
#include <stdio.h>
 
int main()
{
    int i = 3000;
    int*= NULL;
 
    p = &i;
 
    printf("p=%u\n", p);
    printf("&i=%u\n\n"&i);
 
    printf("i=%d\n", i);
    printf("*p=%d\n\n"*p);
 
 
    return 0;
}
cs

사용자마다 메모리 주소는 다릅니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*변수와 포인터를 연결한 후에 변수의 주소와 포인터의 값을 출력.*/
 
#include <stdio.h>
 
int main()
{
    int i = 3000;
    int*= NULL;
 
    p = &i;
 
    printf("p=%u\n", p);
    printf("&i=%u\n\n"&i);
 
    printf("i=%d\n", i);
    printf("*p=%d\n\n"*p);
 
 
    return 0;
}
cs



포인터 사용지 주의할 점


-초기화 하지 않기

쓰레기 값을 가지기때문에 꼭 초기화를 해줘야 합니다.



-NULL포인터의 사용

포인터가 아무것도 가리키고 있지 않을 때는 NULL로 설정해주세요. NULL은 0을 뜻합니다.


-포인터 타입과 변수의 타입은 일치해야한다.

포인터도 여러가지 타입이 존재하는데 포인터의 타입에 따라 메모리를 얼만큼 읽어들이는지 달라지기때문에 꼭 일치해야합니다.


- 절대 주소 사용

윈도우에서는 절대 주소를 사용하지 말아주세요.,




포인터의 연산


덧셈과 뺼셈 연산

포인터에서 p++하게되면 포인터의 정수형 만큼 ++가 됩니다. int 형이면 1이 늘어나는것이 아닌 4만큼 늘어나고, 

double형이면 8만큼 늘어나게 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
 
int main()
{
    char *pc;
    int *pi;
    double *pd;
 
    pc = (char *)10000;
    pi = (int *)10000;
    pd = (double *)10000;
 
    printf("증가 전 pc = %d , pi = %d , pd = %d\n", pc, pi, pd); // 현재 값
 
    pc++;
    pi++;
    pd++;
    printf("증가 후 pc = %d , pi = %d , pd = %d\n", pc, pi, pd); // 1씩 더한 값
 
    printf("      pc+2 = %d , pi+2 = %d , pd+2 = %d\n", pc + 2, pi + 2, pd + 2); // 2씩 더한 값
 
    return 0;
}
cs