포인터
point에 er을 붙인 것이다. pointer을 직역하면 '가르키는 것'이 되는데, 변수의 주소를 가지고 있는 변수이다. 즉, int i = 4이렇게 변수에 데이터를 저장했다고 가정했을때, 포인터는 변수i가 저장되어있는 메모리상 주소를 가진다.
주소 연산자 &
그렇다면 변수의 주소를 어떻게 알 수 있을까?
주소 연산자인 &를 사용하면된다. 간단한 예제를 살펴 보자.
1
2
3
4
5
6
7
8
9
|
#include<stdio.h>
int main(void)
{
int a = 10;
printf("%u", &a);//%u는 주소를 십진수로 출력
return 0;
}
|
cs |
이 예제에선, 변수 a를 선언하고 10을 저장했다. 그렇다면 이 변수 a가 저장되어 있는 메모리상 주소가 있을 것이다. &는 주소 연산자로써 &a를 하면 a가 저장된 메모리의 주소를 알 수 있다.

변수 a가 저장되어있는 주소가 나왔다!
포인터의 선언
그렇다면 포인터 변수의 선언은 어떻게 할까?
일단 포인터 선언은 int *p; 이렇게 한다. 이것도 예제를 통해서 알아보자.
1
2
3
4
5
6
7
8
9
10
11
|
#include <stdio.h>
int main(void)
{
int a = 10;
int *p;//int형의 변수를 가르키는 포인터변수 p의 생성
p = &a;
printf("%u", p);
return 0;
}
|
cs |
설명) 일단 변수 a를 선언하고 10을 저장한다. 그리고 포인터 변수p를 선언한다. 여기서 int형으로 포인터 변수를 선언했는데, 이 포인터가 가르킬 변수가 int형이기 때문이다.
p = &a를 보면 포인터 변수 p에 a의 주소를 저장한 것이다. 포인터는 주소를 가르키는 것이고, &는 주소 연산자이기 때문이다. 즉, 주소를 저장하는 변수p에 &a의 변수를 넣은 것이라고 보면된다.
이것도 변수 a의 주소가 출력된다!
간접 참조 연산자 *
포인터는 주소만 저장할 수 있는게 아니라, 주소로 가서 데이터를 가져올 수 있다. 그러려면 포인터변수 p앞에 *를 붙여서 *p를 하면 된다. 그러면 포인터 변수 p가 가르키고 있는 변수의 데이터를 가져온다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <stdio.h>
int main(void)
{
int i = 3000;
int *p = NULL;
p = &i;
printf("i = %d\n", i);//변수 i의 데이터
printf("&i = %u\n", &i);//변수 i의 주소
printf("*p = %d\n", *p);//포인터 변수 p가 가르키고 있는 변수의 데이터
printf("p = %d\n", p);//포인터 변수에 저장되어있는 주소
return 0;
}
|
cs |
설명)
i=3000이고 *p는 i가 저장되어있는 주소로 가서 데이터인 3000을 가져온다. &i는 i의 주소이고 포인터변수인 p도 i의 주소이다. 따라서 i와 *p는 같으며, &i와 p는 같다.

포인터 연산
포인터에서도 사칙 연산이 적용 될까? 덧셈과 뺄셈만 가능하다! 만약 포인터 p의 값이 1000이다. 여기서 p를 하나 증가시키면 1001이 될 것만 같다. 즉, p++를 하면 1001이 될 것 같지만, 포인터p가 어떤 자료형을 가르키는지에 따라서 다르다. 포인터p가 int자료형을 가르키고 있다면 4씩 증가한다. 즉 p++을 하면 1000에서 1004가 된다. int 자료형은 4byte이고, 포인터는 4byte씩 읽어들인다. 뺄셈도 마찬가지다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <Stdio.h>
int main(void)
{
char *pc;
int *pi;
double *pd;
pc = (char *)10000; //이렇게 포인터에 직접 값을 대입하는건 좋지 않다
pi = (int *)20000; //정확학 설명을 위해 하는 것임.
pd = (double *)30000;
printf("증가 전 : pc = %u pi = %u pd = %u\n", pc, pi, pd);
pc++;
pi++;
pd++;
printf("증가 후 : pc = %u pi = %u pd = %u\n", pc, pi, pd);
return 0;
}
|
cs |
이 코드는 포인터를 증가시키면 얼마씩 증가되는지 알아보기 위해서 작성한 코드이다. char형 포인터는 1씩, int는 4씩, double은 8씩 증가 한 것을 볼 수 있다.

포인터에서 쓰이는 간접 참조 연산자와 증감 연산자를 알아보자.
*p++와 (*p)++의 차이가 뭘까?
*p++ : p가 가르키는 위치에서 값을 가져온 다음에, p를 증가시킨다.
(*p)++ : p가 가르키는 값을 증가시킨다.
예제로 확인해 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <stdio.h>
int main(void)
{
int i = 10;
int *pi = &i;
printf("i = %d pi = %u\n", i, pi);
(*pi)++; //pi가 가르키는 곳에서 가져온 값을 증가한다.
printf("i = %d pi = %u\n", i, pi);
printf("i = %d pi = %u\n", i, pi);
*pi++; //pi가 가르키는 곳에서 가져온다음 pi를 증가한다.
printf("i = %d pi = %u\n", i, pi);
return 0;
}
|
cs |

포인터와 배열
배열이름이 포인터라면 포인터도 배열처럼 사용할 수 있다. 간단한 예제를 보자.
1
2
3
4
|
int a[] = {10, 20, 30, 40, 50};
int *p
p = a;
|
cs |
배열 a를 선언, 포인터 p를 선언하고 포인터 p가 배열 a가르키도록 만든다.(배열의 이름은 배열의 주소) 그리고, 배열 a와 포인터 p를 배열처럼 사용해서 출력해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <stdio.h>
int main(void)
{
int a[] = {10, 20, 30, 40, 50};
int *p;
p = a;
printf("a[] = ");
for(int i=0; i < 5;i++){ //배열 a를 출력
printf("%d ", a[i]);
}
printf("\n");
printf("p[] = ");
for(int i=0; i < 5; i++){ //포인터 p를 배열처럼 출력
printf("%d ", p[i]);
}
return 0;
}
|
cs |

포인터도 배열처럼 사용해서 출력했을때, 배열 a와 동일하다는 것을 알 수 있다. 즉, 포인터도 배열처럼 사용가능하다.
포인터와 함수(값에 의한 호출, 참조에 의한 호출)
함수에서 배열을 매개변수로 할 때, 장소를 할당하는게 아니라 주소를 저장하는 포인터로 생성됨. why? 배열은 크기가 크면 문제가 생길 수 있음.
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
|
#include <stdio.h>
void func(int b[]);
int main(void)
{
int a[3] = {1, 2, 3};
for(int i=0; i < 3; i++){
printf("%d ", a[i]);
}
printf("\n");
func(a); //인수로 배열 a의 주소를 전달
for(int i=0; i < 3; i++){
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
void func(int b[]) //배열을 가르키는 포인터가 생성된다.
{
b[0] = 5;
b[1] = 6;
b[2] = 7;
}
|
cs |
설명) func함수에서 배열 a의 주소가 인수로 전달된다. func함수에서는 받은 매개변수(배열 a의 주소)로 가서 값을 수정한다. 주소로 가서 값을 수정하는 것이기 때문에, 배열 a의 값을 출력해보면 변경된 것을 알 수 있다.

포인터를 사용하는 반환값
함수의 인수로 포인터를 받는 형태도 있지만, 함수의 반환값으로 포인터를 사용할 수 있다. 주의!! 함수가 종료되더라도 남아 있는 주소를 반환해야 한다. why? 지역변수의 경우 함수가 종료되면 변수가 사라지기 때문에 그 사라진 변수의 주소를 반환하면 안된다.!
'C프로그래밍 > 개인 공부' 카테고리의 다른 글
C언어 - 구조체와 포인터 (0) | 2022.12.10 |
---|---|
C언어 - 문자열을 정수로, 정수를 문자열로 바꾸기 (0) | 2022.12.10 |
C언어 - 스트림과 파일 입출력 기초(쓰기와 삭제) (0) | 2022.11.02 |
C언어 - 10진수를 2진수로 바꾸기(재귀함수) (1) | 2022.10.13 |
C언어 - 구조체와 포인터 (0) | 2022.08.09 |