티스토리 뷰

BackEnd/C

[12일차] 포인터

JINSUKUKU 2021. 2. 23. 20:01

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 = &num;

  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
댓글
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
최근에 올라온 글
글 보관함
Total
Today
Yesterday