-목차-
1. 포인터 개념
2. 포인터 변수와 & 연산자
3. 포인터 변수와 주소의 이해
4. 포인터 활용
1. 포인터 개념
○ 메모리 구조와 변수
※ 메모리
- 메모리 셀이 연속해 나열되어 있는 구조
- 각 메모리 셀은 식별을 위한 주소를 가지며 셀 내에 이진 값을 저장할 수 있다
※ Variable
- 값을 저장하는 메모리 공간
- Identifier, Type, Value, Memory Size, Memory Address, Scope, Lifetime 등을 속성으로 가짐
ex) int num의 속성은?
식별자 : num, 타입 : int, 값 : 1852609611, 메모리 크기 : 4 bytes, 메모리 주소 : 0x1000
○ 포인터 : 지시자, 가리키는 자 (변수를 가르키는 변수)
나를 변수로 지정해본다면 식별자는 김태윤, 타입은 사람, 값(나이)는 21살, 주소는 부산광역시라고 할 수 있다. 나에 대한 포인터는 무엇일까?
포인터는 변수의 주소를 값으로 가지는 변수이기에 타입은 사람*, 값은 부산광역시, 주소는 포인터 고유의 주소이다.
2. 포인터 변수와 & 연산자
※ 포인터 변수 : 변수의 주소를 저장하는 변수
※ 포인터 변수의 타입 : 참조하는 변수의 자료형에 의해 결정
- 참조하는 변수의 자료형에 *을 추가하여 표현
ex) int *, double *, char *
#include <stdio.h>
int main(void) {
int nx = 36, ny;
int * pn; // 포인터 변수 pn은 int* 타입
ny = nx ; // nx value -> ny value
pn = &nx; // nx address -> pn value
return 0;
}
※ 포인터 변수의 선언
- 포인터 변수를 의미하는 *와 reference type 사이에 공백이 있어도 무방하다
- 한 선언에서 여러 개의 포인터를 선언할 경우 각 변수 앞에 *을 붙여야 한다
#include <stdio.h>
int main(void)
{
int* a;
int * b;
int * c;
int *d, e; // T(d) == int *
// T(e) == int
int *f, *g; // T(f) == int *
// T(g) == int *
return 0;
}
○ 포인터 연산자 ★★★
※ & : "Address of" 연산자
- 변수의 주소를 얻어오는 연산자
※ * : "Pointer Dereferene" 연산자
- 포인터 변수가 가르키는 변수의 값을 얻어오는 연산자
- 포인터 제1법칙 기억하기 !!!
○ 포인터 변수가 가지는 주소 값의 출력
※ %p : 주소를 printf로 출력할 때의 FSF
- 주소도 일종의 숫자 값으로 출력할 수 있다.
- 출력 값의 형식은 Hexa
※ 포인터 변수의 메모리 크기
- 포인터 변수의 메모리 크기는 시스템(실행환경)마다 4 or 8 bytes로 다름
※ 포인터 변수 또한 주소를 가진다
3. 포인터 변수와 주소의 이해 ★★★
#include <stdio.h>
int main(void){
int nx = 36;
int ny = 0;
int* pn = &nx; // nx address -> pn value
printf("ADDR:%p\n",&nx); // nx의 주소값 출력
printf("ADDR:%p\n",&ny); // ny의 주소값 출력
printf("ADDR:%p\n",pn); // pn의 값(nx의 주소값) 출력
printf("Size %d\n",sizeof(pn)); // pn의 메모리 크기 출력
printf("ADDR:%p\n",&pn); // pn의 주소값 출력
// ★★ 참고로 먼저 선언한 변수의 주소값은 나중에 선언한 변수의 주소값보다 위에 있다.( 메모리 주소의 숫자가 더 크다. )
ny = *pn; // pn이 가르키는 nx의 값 -> ny의 값
printf("ny : %d\n",ny); // 36
*pn = ny + 1; // ny + 1 -> pn이 가르키는 nx의 값
// 사실상 nx = ny + 1 과 동일
printf("pn : %d\n",*pn); // 37
printf("nx : %d\n",nx); // 37
nx = *pn + *(&ny); // pn이 가르키는 nx의 값(37) + ny의 값(36) -> nx의 값
printf("nx : %d\n",nx); // 73
printf("%d, %d, %d\n",nx,ny,*pn);
return 0;
}
4. 포인터 활용
○ Call by Address Value ★★★
- 변수의 포인터/주소를 알면 호출에 쓰인 변수의 값을 함수 내에서 변경할 수 있음
※ Call by value
- 변수의 값만 전달 가능하며 변수 자체를 함수로 전달할 수 없음
#include <stdio.h>
int foo(int a){
a = 3;
return 0;
}
int main(void){
int x = 2;
printf("%d\n",x); // 2
foo(x);
printf("%d\n",x); // 2
return 0;
}
※ Call by Address value
- 변수 x에 대한 주소 값을 가지는 포인터 변수가 매개 변수가 되는 경우
- 포인터 변수에 대한 * 연산, 즉 deferencing을 적용하면 변수 x에 접근할 수 있고 이를 통해 변수 x값을 변화시킬 수 있음
○ 포인터 매개 변수
#include <stdio.h>
void vswap(int x, int y){
printf(" x-[%p:%d], y-[%p:%d]\n", &x,x,&y,y);
int tmp = x;
x = y;
y = tmp;
}
void pswap(int *x, int *y){
printf("*x-[%p:%d], *y-[%p:%d]\n",x,*x,y,*y);
printf(" x-[%p:%p], y-[%p:%p]\n",&x,x,&y,y);
int tmp = *x;
*x = *y;
*y = tmp;
}
int main(void){
int a = 2, b = 3;
printf(" a-[%p:%d], b-[%p:%d]\n",&a,a,&b,b);
vswap(a,b);
printf(" a-[%p:%d], b-[%p:%d]\n",&a,a,&b,b);
pswap(&a,&b);
printf(" a-[%p:%d], b-[%p:%d]\n",&a,a,&b,b);
return 0;
}
※ vsawp()의 이해
- 값이 단순 복사되어 전달 ( Call by value )
- x,y의 변화가 a,b의 변화로 이어지지 않음
※ pswap()의 이해
- 매개 변수가 포인터 변수
- 함수 호출 시 &a, &b 연산을 통해 a,b의 주소 값을 복사
- 포인터 변수에 * 연산을 적용하여 원 변수에 접근하여 값을 바꿀 수 있다 ( Call by Address Value)
+) 한 개의 함수를 통해 하나 이상의 결과를 전달 받고자 할 때..
#include <stdio.h>
int project(int *a, int *b, int *sum, int *prod){
*sum = *a + *b;
*prod = (*a)*(*b);
return 1;
}
int main(void){
int a = 3, b = 7, sum = 0, prod = 0;
project(&a,&b,&sum,&prod);
printf("a+b = %d, a*b = %d\n",sum,prod);
return 0;
}
- 포인터 변수를 매개변수로 하여 값을 바꿔 마치 여러 개의 결과를 반환한 듯한 효과를 볼 수 있다.
'CS > C, C++' 카테고리의 다른 글
[C/C++] 09 - 1 구조체 기초 (0) | 2021.11.27 |
---|---|
[C/C++] 08 - 2 배열, 문자열과 포인터 (0) | 2021.11.17 |
[C/C++] 07 - 3 함수와 모듈러 프로그래밍 (0) | 2021.11.02 |
[C/C++] 07 - 2 표준 라이브러리 함수의 사용 (0) | 2021.10.29 |
[C/C++] 07 - 1 함수와 변수, 함수인자 (0) | 2021.10.27 |