1. 포인터의 기본 개념
변수 = 메모리 공간 / 변수명 = 공간 식별 이름
단, 서로 다른 함수(블럭)에 존재하면 전혀 다른 변수로 사용이 된다.
이러한 경우에도 데이터를 공유할 수 있게 하기 위해 포인터 를 사용한다.
- 메모리의 주소
메모리 = 데이터를 넣고 꺼내는 공간으로 찬장과 같다고 하자.
우리는 이 찬장의 위치를 알아야지 찬장에 있는 물건(데이터)를 꺼낼 수 있다.
프로그램에서는 사용하는 메모리의 위치를 주소 값으로 식별할 수 있다.
이러한 주소값은 byte(바이트) 단위로 구분 된다.
메모리 ( 주소 1개당 1byte 할당 )
2. 주소 연산자 &
주소 = 변수가 할당된 메모리 공간의 시작 주소
주소 연산자 & 를 사용해서 구현하며, 원하는 위치부터 변수의 크기만큼 메모리 사용이 가능하다.
#include <stdio.h>
int main(void)
{
//변수 선언문 실행
int a; // int형 변수선언
double b; // double형 변수 선언
char c; // Char형 변수 선언
printf("int형 변수의 주소 : %u\n", &a); [^1]:주소 연산자로 주소 계산
printf("double형 변수의 주소 : %u\n", &b);
printf("char형 변수의 주소 : %u\n", &c);
return 0;
}
>> int형 변수의 주소 : 15727976
double형 변수의 주소 : 15727960
char형 변수의 주소 : 15727951
변수 선언문이 실행되면, 각 자료형의 크기만큼 메모리에 저장 공간이 할당된다.
이때, 주소연산자& 를 사용하면 변수가 할당된 메모리 공간의 시작 주소 값을 알 수 있다.
&변수명
변수에 할당된 메모리의 시작 주소를 확인하고,
시작 주소에 변수의 크기를 더하면 변수의 메모리의 할당 범위를 알 수 있다.
3. 간접참조연산자 ( * )
앞에서는 단지 메모리의 주소를 출력하는 법을 알아보았다.
하지만, 필요할 때마다 계속 주소 연산을 수행하는 것은 불편하기에 한 번 구한 주소를 저장해서 사용하는법을 알아보자.
포인터
변수의 메모리 주소를 저장하는 변수로 일반 변수와 마찬가지로 선언 후 사용한다.
다만, 선언할 때 변수 앞에 * 만 붙여주면된다.
#include <stdio.h>
int main(void)
{
int a; //일반 변수 선언
int* pa; // 포인터 변수
pa = &a; // 포인터에 a의 주소 대입
*pa = 10; // 포인터로 변수 a에 10대입
printf("포인터로 a값 출력 : %d\n", *pa);
printf("변수명으로 a값 출력 : %d\n", a);
// 변수 a 값 출력
return 0;
}
>> 포인터로 a값 출력 : 10
변수명으로 a값 출력 : 10
자료형 *변수명;
포인터 이름을 짓고, 변수명 앞에 *를 붙인다.
여기서 *는 포인터임을 표시하는 기호이다.
포인터의 자료형은 변수의 자료형을 적어준다.
여기서, 포인터 자료형은 저장할 주소가 어떤 변수의 주소인지 그 변수의 자료형을 적는다.
int *pa;
포인터 변수가 할당되면, 일반 변수와 마찬가지로 메모리 저장공간이 할당되고, 이후에는 변수명으로 사용할 수 있다.
pa = &a; //포인터에 a의 주소 대입
pa ← a 포인터 pa는 변수 a를 가리킨다.
즉, *pa로 변수 a를 사용할 수 있다. ( *pa == a)
*pa = 10
printf("a의 값은 : %d", a);
>> a의 값은 : 10
이렇게 배운 포인터를 이용한 사용법을 알아보자.
- 포인터를 사용한 두 정수의 합과 평균
#include <stdio.h>
int main(void)
{
int a = 10, b = 15, total; //변수 선언과 초기화
double avg; // 평균을 저장할 변수
int *pa, *pb; // 포인터 동시 선언
int *pt = &total; // 포인터 선언과 초기화
double *pg = &avg; // double형 포인터 선언과 초기화
pa = &a; //포인터 pa에 변수 a의 주소 대입
pb = &b; //포인터 pb에 변수 b의 주소 대입
*pt = *pa + *pb; // total = a + b 와 같음
*pg = *pt / 2.0; // avg = total / 2.0
printf("두 정수의 값 : %d, %d\n", *pa, *pb);
printf("두 정수의 합 : %d\n", *pt);
printf("두 정수의 평균 :%.1lf\n", *pg);
return 0;
}
>> 두 정수의 값 : 10, 15
두 정수의 합 : 25
두 정수의 평균 :12.5
4. const를 사용한 포인터
const = 가리키는 변수의 값을 바꿀 수 없다.
라는 의미로, 이렇게되면 변수이 사용하는 것과는 다른 의미를 가진다.
#include <stdio.h>
int main(void)
{
int a = 10, b = 20;
const int *pa = &a; //*pa는 변수 a를 가리킨다
printf("변수 a값 : %d\n", *pa); // 포인터를 간접 참조하여 a 출력
pa = &b; // 포인터가 변수 b를 가리키게 된다.
printf("변수 b값 : %d\n", *pa); //포인터를 간접 참조하여 b 출력
pa = &a; // 포인터가 다시 변수 a를 가리킨다
a = 20; // a를 직접 참조하여 값을 바꾼다.
printf("변수 a값 : %d\n", *pa);
// 포인터로 간접 참조하여 바뀐 값 출력
return 0;
}
>> 변수 a값 : 10
변수 b값 : 20
변수 a값 : 20
const int *pa = &a;
에서 *pa를 선언할 때 const로 상수화 하였다.
만약, const가 일반 변수처럼 포인터 값을 고정시킨다면, pa = &b;
에서 pa는 다른 변수의 주소를 저장 할 수 없다.
하지만 출력 결과에서 pa는 const의 사용과 무관하게 변수 b의 주소를 저장하고, 간접 참조해 출력하고 있다.
왜 이런걸까?
const int *pa = &a;
여기서 사용된 const의 의미는
*pa가 가리키는 변수 a는 pa를 간접 참조해서 바꿀수 없다.
그렇기에, *pa = 20;
처럼 pa의 값을 통해 a를 바꾸려고 하면 에러가 발생한다.
- 응용 문제 ( 한번 생각해보고 실행해보자)
#include <stdio.h>
int main(void)
{
int a = 10, b = 20;
const int *pa = &a; // 포인터가 가리키는 곳의 데이터를 상수화 ( 주소변경 O)
int* const pb = &b; // 포인터 자체가 상수화 ( 주소변경 X )
printf("변수 a값 : %d\n", *pa);
pa = &b;
b = 50;
printf("변수 b값 : %d\n", *pa);
pa = &a;
a = 20;
printf("변수 a값 : %d\n", *pa);
printf("변수 b값 : %d\n", *pb);
return 0;
}
>> 변수 a값 : 10
변수 b값 : 50
변수 a값 : 20
변수 b값 : 50
[ 중간 정리 ]
- 포인터는 메모리를 사용하는 또 다른 방법이다.
- 주소 연산자 & 로 변수가 할당된 메모리의 위치를 확인한다.
- 포인터로 가리키는 변수를 사용할 때 *간접 참조 연산자 * * 를 사용한다.
- 주소 연산자 ( 변수가 할당된 메모리의 시작 주소 값 구함)
int a;
& a
- 포인터 ( 시작 주소 값을 저장하는 변수, 가리키는 자료형을 표시하여 선언한다. )
char *pc;
int *pa
double *pd
- 간접 참조 연산자 ( 포인터에 사용, 포인터가 가리키는 변수를 사용 )
*pi = 10;
'Language > C' 카테고리의 다른 글
C_Char13-1. 변수 사용 영역 (0) | 2021.05.10 |
---|---|
C_Char09.포인터(이해) (0) | 2021.05.09 |
C_Char08.배열 (0) | 2021.05.09 |
C_Char07.함수 (0) | 2021.05.09 |