이번
장에서
학습핝
내용
.포인터란?
.변수의주소.포인터의선언.간접참조연산자.포인터연산.포인터와배열.포인터와함수이번장에서는포인터의기초적인지식을학습한다.
포인터란?
.
포인터(pointer): 주소를
가지고
있는
변수
1001
1002
1003
1004
1005
1006
1007
영화관포인터(pointer)
메모리의
구조
.
변수는
메모리에
저장됨
.
메모리는
바이트
단위로
액세스됨
.
0번지, 100 번즞
변수와
메모리
.
변수의
크기에
따라서
차지하는
메모리
공간이
다륽
.
char 형: 1 바이트; int 형: 4 바이트; …
int i = 10;
char c = 69;
float f = 12.3F;
변수값
변수명
주소
10
i
12.3
f
69
c
주소
연산자
&
.
& : 변수의
주소를
계산하는
연산자
.
변수
i의
주소
: &i
변수값
변수명
주소
10
i
12.3
f
69
c
&i &c &f
변수의
주소
int main(void)
{
int i = 10;
char c = 69;
float f = 12.3F;
printf("i 의
주소
: %u\n", (unsigned)&i); // 변수
i의
주소
출력
printf("c의
주소
: %u\n", (unsigned)&c); // 변수
c의
주소
출력
printf("f의
주소
: %u\n", (unsigned)&f); // 변수
f의
주소
출력
return 0;
}
i의주소: 1245024
c의주소: 1245015
f의주소: 1245000
포인터
변수
.
inti = 10;
.
int *p; // 정수
포인터
변수
선언
p = &i; //p 는
i를
가리킴
.
int*p = &i; // 정수
포인터
변수
선언
및
초기화
포인터
변수
char c = 'A'; // char 형
변수
c
float f = 36.5F; // float 형
변수
f
double d = 3.141592; // double 형
변수
d
char *pc = &c; // char 형을
가리키는
포인터
변수
pc
float *pf = &f; // float 형을
가리키는
포인터
변수
pf
double *pd = &d; // double 형을
가리키는
포인터
변수
pd
pc
pf
pd
A
36.5
3.141592
d
f
c
간.
참조
연산자
*
.
* : 포인터가가리키는대상을참조하는연산자
inti =10;
int *p = &i;
printf("%d", *p);
& 연산자와
* 연산자
포인터
예제
#include
int main(void)
{
int i = 3000;
p
int *p = &i; // 변수와
포인터
연결
printf("i = %d\n", i); // 변수의
값
출력
printf("&i = %u\n", (unsigned)&i); // 변수의
주소
출력
printf("*p = %d\n", *p);
printf("p = %u\n", (unsigned)p); // 포인터의
값
출력
return 0;
}
// 포인터를통한간접참조값출력
i = 3000
&i = 1245024
*p = 3000
p = 1245024
3000
i
터
예제
#include
20
y
p
10
x
int main(void)
{
int x = 10, y = 20;
int *p;
p = &x;
printf("p = %u\n", (unsigned)p);
printf("*p = %d\n\n", *p);
p = &y;
printf("p = %u\n", (unsigned)p);
printf("*p = %d\n", *p);
return 0;
}
p = 1245052
*p = 10
p = 1245048
*p = 20
포인터예제
i = 10
i = 20
포인터예제
i = 10
i = 20
#include
int main(void)
{
int i = 10, *p;
p = &i;
printf("i = %d\n", i);
*p = 20;
printf("i = %d\n", i);
return 0;
}
포인터 사용시 주의점
.
초기화되지 않은 포인터를 사용하면 안 됨
int *p; // p 는
초기화되어
있지
않음
*p = 100; // 위험!
.
NULL 포인터: 아무것도 가리키고 있지 않는 포인터
.
#define NULL 0
.
아무것도 가리키고 있지 않을 경우 , 포인터를 NULL 로 설정
.
p = NULL;
p = 0;
.
if (p == NULL) … // p 가 아무것도 가리키지 않으면
if (p == 0) …
if (!p) …
.
if (p != NULL) … // p 가 무엇이든 가리키고 있으면
if (p != 0) …
if (p) …
포인터
사용시
주의.
.
포인터의
타입과
변수의
타입은
일치해야
함
#include
int main(void)
{
int i;
double *pd;
i int
pd
double *
pd = &i;
*pd = 36.5;
// double 형
포인터에
int 형
변수의
주소
대입
// 형변환: int * .
double * --C: warning, C++: error
}
return 0;
포인터
연산
.
포인터++, 포인터--, 포인터
±
정수
: 포인터가
가리키는
대상의
크기(포인터
타입의
크기
)만큼
증감
/덧셈/뺄셈
수행
포인터타입++연산후증가되는값char 1
short 2
int 4
float 4
double 8
100 p++ 104
p: int*
100 p++ 108
p: double *
100 p + 2 108
p: int*
100 p + 2 116
p: double *
100 p--96
p: int*
100 p--92
p: double *
포인터
연산
.
pi-1
pc-2 .
pc-1 .
pc .
.
pi
pc + 1 .
pc + 2 .
.
pi + 1
.
pi + 2
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
char *pc
int *pi
포인터
연산
#include
int main(void)
{
char *pc; int *pi; double *pd;
pc = (char*)10000; pi = (int*)10000; pd = (double*)10000;
printf("증가
전
pc = %d, pi = %d, pd = %d\n", (int)pc, (int)pi, (int)pd);
pc++; pi++; pd++;
return 0;
}
printf("증가후pc = %d, pi = %d, pd = %d\n", (int)pc, (int)pi, (int)pd);
증가전pc = 10000, pi = 10000, pd = 10000
증가후pc = 10001, pi = 10004, pd = 10008
간.
참조
연산자와
증감
연산자
.
*p++ .
*(p++) : p 를
나중에
증가
.
(*p)++ : *p 를
나중에
증가
, p 가
가리키는
값
증가
.
v = *p++; .
v = *p; p++; // p 를
나중에
증가
.
v = (*p)++; .
v = *p; (*p)++; // *p 를
나중에
증가
.
v = *++p; .
++p; v = *p; // p 를
먼저
증가
.
v = ++*p; .
++(*p); v = *p; // *p 를
먼저
증가
간.
참조
연산자와
증감
연산자
#include
int main() {
int i = 10;
int *pi = &i;
printf("i = %d, pi = %p\n", i, pi);
(*pi)++;
printf("i = %d, pi = %p\n", i, pi);
printf("i = %d, pi = %p\n", i, pi);
*pi++;
printf("i = %d, pi = %p\n", i, pi);
i = 10, pi = 0012FF60
i = 11, pi = 0012FF60
i = 11, pi = 0012FF60
i = 11, pi = 0012FF64
return 0;
}
포인터의
형변환
#include 명시적으로
포인터
타.
변경
가능
int main() {
double d, *pd = &d;
char buffer[8];
int *pi = (int*)pd;
double *pd; (주의: 위험)
int *pi;
pd = (double*)buffer; // char * .
double *
*pd = 3.14;
printf("%f\n", *pd);
pi = (int*)buffer; // char * .
int *
*pi = 123;
*(pi + 1) = 456;
printf("%d %d\n", *pi, *(pi + 1));
3.140000
123 456
return 0;
}
포인터와
배엱
.
배열과
포인터는
아주
밀접한
관계를
가지고
있음
.
배열읁
포인터처럼
사용
가능
.
배열의
이름은
배열읁
가리키는
포인터로
사용
가능
.
int a[5];
.
a .
&a[0]
.
a +1 .
&a[1]
.
*(a + 1) .
a[1]
.
포인터를
배열처럼
사용
가능
.
포인터에
인덱스
표기법
사용
가능
.
int a[5], *p = a;
.
p[1] .
*(p + 1) .
a[1] 배열
포인터
포인터와
배엱
#include
int main() {
int a[] = { 10, 20, 30, 40, 50 };
printf("&a[0] = %u\n", (unsigned)&a[0]);
printf("&a[1] = %u\n", (unsigned)&a[1]);
printf("&a[2] = %u\n", (unsigned)&a[2]);
printf("a = %u\n", (unsigned)a);
return 0;
}
&a[0] 1245008
&a[1] 1245012
&a[2] 1245016
a 1245008
배열읁
포인터처럼
사용
#include
int main(void)
{
int a[] = { 10, 20, 30, 40, 50 };
printf("a = %u\n", (unsigned)a);
printf("a + 1 = %u\n", (unsigned)(a + 1));
printf("*a = %d\n", *a);
printf("*(a + 1) = %d\n", *(a + 1));
return 0;
}
a = 1245008
a + 1 = 1245012
*a = 10
*(a + 1) = 20
#include
int main() {
int a[] = { 10, 20, 30, 40 };
int *p;
p = a;
printf("a[0]=%d a[1]=%d a[2]=%d \n", a[0], a[1], a[2]);
printf("p[0]=%d p[1]=%d p[2]=%d \n\n", p[0], p[1], p[2]);
p[0] = 60; p[1] = 70; p[2] = 80;
printf("a[0]=%d a[1]=%d a[2]=%d \n", a[0], a[1], a[2]);
printf("p[0]=%d p[1]=%d p[2]=%d \n", p[0], p[1], p[2]);
포인터를배열처럼사용
a[0]=10 a[1]=20 a[2]=30
p[0]=10 p[1]=20 p[2]=30
a[0]=60 a[1]=70 a[2]=80
p[0]=60 p[1]=70 p[2]=80
return 0;
}
포인터와
배열의
유사.
.
int a[5]; .
int a[5], *p = a;
.
*(a + i) .
a[i] .
a[i] ≡ p[i] ≡ *(a + i) ≡ *(p + i)
.
a +i .
&a[i] .
&a[i] ≡ &p[i] ≡ a + i ≡ p + i
.
a .
a +0 .
&a[0]
.
int *p;
.
p[i] .
*(p + i)
.
&p[i] .
p +i
포인터와
배열의
차이.
.
배엱
이름은
상수
.
함수의
인자에서는
배열처럼
.
int a[5], *p; 선언됙
것도
실제로는
포인터
.
void f(int a[10]) { int *p; … }
.
p =a; //O, p =&a[0]
.
void f(int *a) { int *p; … }
.
p++; // O
.
a = p; //O
.
Cf.) intn; n =3; n++; //O
.
a++; // O
.
a =p; //X
.
a++; // X .
sizeofa :4 ( 또는
8)
.
Cf.) int n; 3 =n; 3++; // X
.
sizeof a : 20
.
sizeofp :4 ( 또는
8)
포인터의
관계
연산과
산술
연산
a[0] a[1] a[2] a[3] a[4] a[5]
.
p, q 가
같은
타입의
포인터이고
.
inta[5], *p = a + 1, *q = a + 5;
n이
정수읹
경욪
.
!p, p == NULL, p != NULL
.
p ==q, p !=q p p+2 q
.
p >q, p >=q, p
void print_reverse(const int a[ ], int n);
int main( ) {
int a[ ] = { 10, 20, 30, 40, 50 };
print_reverse(a, sizeof a / sizeof a[0]);
return 0;
50
40
30
20
10
}
void print_reverse(const int a[ ], int n) {
const int *p = a +n-1; // 마지막
원소를
가리키도록
초기화
while (p >= a)
printf("%d\n", *p--); // *(p--)
}
인자
전달
: call-by-value
.
형식인자는
실인자와
별도로
존재
.
함수
호출
시
실인자의
값
.
메모리
사용과
실행
속도
측면에서
비효율적.
.
형식인자를
변경해도
실인자는
바뀌즞
않음
.
부작용(side effect) 이
없음
.
C는
call-by-value 방식만
지원
복사
x = 1;
f(x);
// x = 1
void f(int y) {
y++;
}
1
x
1 .2
y
인자
전달
: call-by-reference
.
형식인자는
실인자는
동읹
.
함수
호출
시
실인자의
값읁
.
메모리
사용과
실행
속도
측면에서
효율적.
.
형식인자를
변경하면
실인자도
바뀜
.
부작용(side effect) 이
있음
.
C++는
call-by-value 와
call-by-reference 방식
모두
지원
x = 1; void f(int &y) {
f(x); y++;
복사하즞
않음
//x=2 }
x ≡ y
1 .2
포인터
인자
.
포인터
인자를
사용하면
.
call-by-value 방식에서도
call-by-reference 효과
유발
가능
.
side effect 유발
가능
.
실인자가
배열인
경욪
: 시작
포인터를
형식인자로
전달
.
int a[5];
.
f(a) .
f(&a[0])
x = 1; void f(int *p) {
f(&x); (*p)++;
//x=2 }
p
100
1 .2
x
100
#include
void swap(int *px, int *py);
int main() {
int a = 100, b = 200;
printf("a=%d b=%d\n", a, b);
swap(&a, &b);
printf("a=%d b=%d\n", a, b);
return 0;
}
swap 함수
void swap(int *px, int *py) {
int tmp;
printf("*px=%d *py=%d\n", *px, *py);
tmp = *px; *px = *py; *py = tmp;
printf("*px=%d *py=%d\n", *px, *py);
}
&a
&b
px
py
100
200
a
b
a=100 b=200
*px 100 *py 200
*px 200 *py 100
a=200 b=100
scanf() 함수
.
변수에
값읁
저장하기
위하여
변수의
주소
전달
인자를
통해
2개
이상의
결과
반환
#include
// 기울기와y절편계산int get_line_parameter(int x1, int y1, int x2, int y2, float *slope, float *yintercept) {
if (x1 == x2) return -1;
*slope = (float)(y2 -y1) / (float)(x2 -x1);
*yintercept = y1 -(*slope) * x1;
return 0;
}
int main(void) {
float s, y;
if (get_line_parameter(3, 3, 6, 6, &s, &y) == -1)
printf("에러\n");
else
printf("기울기는%f, y 절편은%f\n", s, y);
return 0;
}
기울기는1.000000, y 절편은0.000000
기울기와y절편을인자를통해반환
배엱
인자
#include
void sub(int b[ ], int n);
int main( ) {
int a[3] = { 1, 2, 3 };
printf("%d %d %d\n", a[0], a[1], a[2]);
sub(a, 3);
printf("%d %d %d\n", a[0], a[1], a[2]);
return 0;
}
void sub(int b[ ], int n) {
b[0] = 4;
b[1] = 5;
b[2] = 6;
}
1 2 3
4 5 6
포인터
반환
int *f(int x, int y) {
int result;
result = x + y;
return &result;
} // (X) local auto 변수
주소
반환
…
int *p = f(3, 4);
int n = *p; // 존재하즞
않는
메모리
참조
int g = 1;
int *f( ) {
return &g;
} // global static 변수
주소
반환
…
int *p = f( );
int n = *p; // n = 1
*f( ) = 2; // g = 2
int *f( ) {
static int s = 1;
return &s;
} // local static 변수
주소
반환
…
int *p = f( );
int n = *p; // n = 1
int *f(int *q) {
*q = 1;
return q;
} // 포인터
인자
반환
…
int n;
int m = *f(&n); // n = 1, m = 1