주소는 변수에 할당된 메모리 저장 공간의 시작 주소 값 자체이고,
포인터는 그 값을 저장하는 또 다른 메모리 공간이다.
int a, b; // 일반 변수 선언
int *p; // 포인터 선언
p =&a; // p가 a를 가리키도록 설정
p =&b; // p가 변수 b를 가리키도록 바꿈
위의 경우 변수 a와 변수 b는 각각의 주소값을 갖고있다. 프로그램 실행 중에는 그 값이 바뀌지 않는 것이 특징이다
포인터도 저장공간이기 때문에, 크기가 존재한다.
포인터의 크기는 저장할 주소의 크기에 따라 결정되는데, 크기가 클수록 더 넓은 범위의 메모리를 사용할 수 있다.
모든 주소와 포인터는 (가리키는 자료형에 관계없이) 크기가 같다!
#include <stdio.h>
int main(void)
{
char ch;
int in;
double db;
char *pc = &ch;
int *pi = ∈
double *pd = &db;
printf("char형 변수의 주소 크기 : %d\n", sizeof(&ch));
printf("int형 변수의 주소 크기 : %d\n", sizeof(&in));
printf("double형 변수의 주소 크기 : %d\n", sizeof(&db));
printf("char * 포인터의 크기 : %d\n", sizeof(pc));
printf("int * 포인터의 크기 : %d\n", sizeof(pi));
printf("double * 포인터의 크기 : %d\n", sizeof(pd));
printf("char * 포인터가 가리키는 변수의 크기 : %d\n", sizeof(*pc));
printf("int * 포인터가 가리키는 변수의 크기 : %d\n", sizeof(*pi));
printf("double * 포인터가 가리키는 변수의 크기 : %d\n", sizeof(*pd));
return 0;
}
주소란?
변수가 할당된 메모리 공간의 시작 주소를 의미한다.
시작 주소를 알면 그 위치부터 변수의 크기만큼 메모리를 사용할 수 있다
#include <stdio.h>
int main(void)
{
int a; // int형 변수 선언
double b; // double형 변수 선언
char c; // char형 변수 선언
printf("int형 변수의 주소 : %u\n", &a); // 주소 연산자로 주소 계산
printf("double형 변수의 주소: %u\n", &b);
printf("char형 변수의 주소 : %u\n", &c);
return 0;
}
주소 연산자 &를 사용하면 변수가 할당된 메모리 공간의 시작 주소 값을 알 수 있다.
#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;
}
일반 변수명을 만드는 규칙에 따라 포인터 이름을 짓고, 변수명 앞에 *를 붙인다.
*는 포인터임을 나타내는 기호이다. 포인터의 자료형은 변수의 자료형을 적는다.
포인터 pa는 변수 a가 메모리 어디에 할당되어 있는지 그 위치를 기억한다.
포인터가 어떤 변수의 주소를 저장하는 경우 ‘가리킨다’라고 표현하며, “pa → a” 라고 표현할 수 있다.
“pa → a” 가 의미하는 바: 포인터 pa는 변수 a를 가리킨다.
*pa = 10;
여기서, 포인터 pa는 a를 가르키므로 *pa에 10을 대입하면 결국 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; // a의 값과 b값을 더해 total 저장
*pg = *pt / 2.0; // total 값을 2로 나눈 값을 avg에 저장
printf("두 정수의 값 : %d, %d\n ", *pa, *pb); // a 값과 b값 출력
printf("두 정수의 합: %d\n", *pt); // total 값 출력
printf("두 정수의 평균 : %.lf\n", *pg); // avg 값 출력
return 0;
}
1번 경우 (맞는 사례)
printf("두 정수의 값 : %d, %d\n ", *pa, *pb); // a 값과 b값 출력
printf("두 정수의 합: %d\n", *pt); // total 값 출력
printf("두 정수의 평균 : %.lf\n", *pg); // avg 값 출력
2번 경우(잘못된 사례)
printf("두 정수의 값 : %d, %d\n ", *pa, *pb); // a 값과 b값 출력
printf("두 정수의 합: %d\n", &total); // total 값 출력
printf("두 정수의 평균 : %.lf\n", *pg); // avg 값 출력
나의 경우 total 값을 출력하면 된다기에 2번의 경우처럼
[ printf("두 정수의 합: %d\n", &total); ] 이런 식으로 코드를 작성했다. 하지만 내가 작성한 코드의 경우
total의 주소값을 물어보는 것이기에 원래 원하던 값과는 다른 값이 나오게된다.
int *pt = &total;
위와 같은 경우일지라도,
💡 &는 주소 연산자이기에 결국에는 주소값을 가져온다는 것을 잊지 말자!!int pa, pb 이 경우에는 pa 와 pb모두 int형 변수의 주소를 저장하는 포인터로 인식된다.
하지만,
int pa, pb 이 경우에는 pa는 포인터로 정상 인식되지만, pb는 오직 int형 변수로만 인식된다.
const 예약어를 포인터에 사용하면 이를 가리키는 변수의 값을 바꿀 수 없다는 것이다.
#include <stdio.h>
int main(void)
{
int a = 10, b = 20;
const int *pa = &a; // 포인터 p는 변수 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;
}
pa가 가리키는 변수 a는 pa를 간접 참조하여 바꿀 수 없다는 것이다.