티스토리 뷰

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 |