티스토리 뷰
2021.02.22.월
포인터를 사용하는 이유
✔ 변수는 선언된 위치에 따라 사용할 수 있는 범위가 결정된다.
✔ 매개변수로 받아오는 경우 값을 복사해 함수 내부에서 새로운 변수로 선언된다.
✔ 그렇기 때문에 아래와 같이 main함수 내부에서 선언 및 초기화된 변수는 인자로 다른 함수에 전달해 수정하더라도 main함수 내부의 값에는 영향을 주지 않는다.
#include <stdio.h>
int test(int number){
number = 20;
return number;
}
int main(void){
int number = 10;
test(number);
printf("%d", number);
return 0;
}
✔ 만약 main함수 내부의 변수에 접근해서 값을 수정하고 싶다면 어떻게 해야 할까?
✔ 주소 연산자 & 를 사용해 변수의 주소를 매개 변수로 전달하고, 함수 내부에서는 간접 참조 연산자 *를 사용해 값을 수정하자.
#include <stdio.h>
void test(int *number){
*number = 20;
}
int main(void){
int number = 10;
test(&number);
printf("%d", number);
return 0;
}
포인터의 선언과 초기화
#include <stdio.h>
int main(void){
int num = 10;
int * ptr = &a;
printf("%p\n", ptr); //ptr에 저장된 a의 주소 출력
printf("%d\n", *ptr); //ptr이 가리키는 a의 값 출력
}
✔ 포인터 변수 역시 변수이므로 변수와 같은 방법으로 선언 및 초기화를 한다.
✔ 다만 포인터 변수임을 표시하기 위해 자료형과 변수명 사이에 *을 사용하고
✔초기화할 때에는 변수의 주소를 저장하기 위해 주소 연산자 &를 사용한다.
✔ 포인터 변수에는 변수의 주소가 저장되고 주소에 저장된 값에 접근할 때에는 간접 참조 연산자 *을 사용한다
포인터 사용해보기
#include <stdio.h>
int main(void){
int num1 = 10, num2 = 20;
//포인터 변수에 변수 주소 저장
int *p1 = &num1;
int *p2 = &num2;
//변수의 주소 출력
printf("num1의 주소 : %p\n", &num1);
printf("num1의 주소 : %p\n\n", p1);
//변수의 값 출력
printf("num1에 저장된 값 : %d\n", num1);
printf("num1에 저장된 값 : %d\n\n", *p1);
//연산
printf("num1 + num2 = %d\n", num1+num2);
printf("num1 + num2 = %d\n", *p1+*p2);
return 0;
}
포인터의 크기
#include <stdio.h>
int main(void){
printf("> 자료형 크기\n");
printf("int의 크기\t : %lu byte\n", sizeof(int)); //4
printf("char의 크기\t : %lu byte\n", sizeof(char)); //1
printf("double의 크기\t : %lu byte\n", sizeof(double)); //8
printf("float의 크기\t : %lu byte\n\n", sizeof(float)); //4
printf("> 포인터 크기\n");
printf("int*의 크기\t : %lu byte\n", sizeof(int*)); //8
printf("char*의 크기\t : %lu byte\n", sizeof(char*)); //8
printf("double*의 크기\t : %lu byte\n", sizeof(double*)); //8
printf("float*의 크기\t : %lu byte\n", sizeof(float*)); //8
}
✔ 시스템이 32bit인지 64bit인지에 따라 포인터의 크기가 달라진다.
✔ 32bit 주소 체계에서는 포인터 변수가 32bit의 크기를 가지므로, sizeof 함수를 사용하면 4byte를 반환한다.
✔ 32bit 주소 체계에서는 포인터 변수가 64bit의 크기를 가지므로, sizeof 함수를 사용하면 8byte를 반환한다.
✔ 포인터 변수는 자료형과 상관없이 항상 일정한 크기를 가진다. 주소를 저장하기 위한 변수이기 때문.
const를 사용한 포인터
✔ 포인터 변수에 상수를 의미하는 예약어 const를 사용하면, 이는 포인터 변수가 가리키는 변수의 값을 바꿀 수 없다는 의미.
✔ 포인터 변수가 가리키는 주소는 변경할 수 있다.
#include <stdio.h>
int main(void){
int a = 10;
int b = 20;
const int *p = &a;
p = &b; //가리키는 주소의 변경 가능
*p = 30; //가리키는 주소에 저장된 값에는 접근 불가능 error
return 0;
}
포인터의 대입 규칙
✔ 포인터의 자료형과 가리키는 변수의 자료형이 동일해야 한다.
#include <stdio.h>
int main(void){
int n1 = 10;
int *pi = &n1;
double n2 = 3.14;
double *pd = &n2;
return 0;
}
✔ 자료형이 다른 변수를 가리키는 경우는 의도하지 않은 결과가 발생한다.
✔ 메모리의 시작 주소는 잘 전달되지만, 메모리의 크기가 다르기때문.
✔ int형 포인터 변수에 간접 참조 연산자 * 을 사용하면 시작 주소로부터 4byte만큼 메모리를 읽어오고
✔ double형 포인터 변수에 간접 참조 연산자 * 을 사용하면 8byte만큼의 메모리를 읽어 온다.
✔ double형 포인터 변수가 int 변수를 가리키는 경우, 변수의 크기를 초과하는 8byte를 읽어오기 때문에 쓰레기 값이 출력된다.
#include <stdio.h>
int main(void){
int num=10;
double *pd = #
printf("%lf",*pd);
return 0;
}
포인터 변수의 형 변환
✔ 포인터의 자료형과 가리키는 변수의 자료형이 동일해야 한다.
✔ 서로 다른 자료형을 사용하고자 한다면 형 변환하면서 대입할 수 있다.
✔ 형 변환해서 변수의 주소를 포인터 변수에 저장한다면, 읽어올 데이터의 크기와 읽어오는 방법만 달라진다.
✔ 예를 들어 double형 포인터 변수에 int형 변수를 형변환해서 주소를 저장했다면 변수의 값은 그대로 int형인데 반해,
✔ 변수에 접근하는 방법은 double형을 따르므로 예상한 값과 다른 결과가 출력된다.
#include <stdio.h>
int main(void)
{
double a = 3.4;
double *pd = &a;
int *pi;
int *test = (int *)pd;
pi = (int *)pd;
printf("%d\n", *pi); // 실행 결과: 858993459
printf("%d\n", *test); // 실행 결과: 858993459
return 0;
}
* 의 역할
✔ 포인터 변수를 선언할 때, 일반 변수가 아닌 포인터 변수임을 알리기 위해 사용.
✔ 간접 참조 연산자로, 포인터 변수에 저장된 주소가 가리키는 값에 접근하기 위해 사용.
✔ 두 가지 용도로 구분되니까 구분해서 기억하자.
#include <stdio.h>
#include <stdlib.h>
int main(void){
int size;
scanf("%d",&size);
int *arr = (int *)malloc(sizeof(int)*size);
for(int i=0; i<size; i++){
scanf("%d", (arr+i)); //연산자 &와 *이 필요없음
}
// printf("%d\n",arr); //오류 발생
printf("%p\n",arr);
printf("****\n");
printf("%d\n",*arr);
// printf("%p\n",*arr); //오류 발생
free(arr);
return 0;
}
[참고] 한빛미디어-혼자 공부하는 C언어 유튜브 강의 / 엘리스 트랙-혼자 공부하는 C언어 / 길벗-C언어 코딩 도장 / 위키백과
'BackEnd > C' 카테고리의 다른 글
[13-14일차] 문자/문자열 (0) | 2021.02.25 |
---|---|
[13일차] 배열과 포인터 (0) | 2021.02.23 |
[11일차] 함수/배열 복습 (0) | 2021.02.23 |
[10일차] 제어문 복습 (0) | 2021.02.20 |
[8일차] 포인터의 선언과 사용 (0) | 2021.02.17 |