카테고리 없음

[혼공C] 6주차. Ch.9 포인터

H 기록 2024. 8. 17. 21:07

09-1. 포인터의 기본 개념

포인터 : 메모리 주소 값을 저장하는 자료형. 

 

[메모리]

: 데이터 저장, 추출을 하기 위해 사용되는 공간. 

함수, 변수 등을 '선언'할 때 특정 크기의 메모리가 할당되고, 할당된 메모리 내에서 데이터를 처리할 수 있음.

 

어떤 함수를 선언한 후 해당 함수 내부에 여러 가지 변수를 선언할 경우, 변수에 할당되는 메모리는 처음 함수 선언 시 할당된 메모리의 일부. > 같은 이름의 변수를 사용하더라도 선언된 함수의 위치가 다르면 다른 변수로 사용될 수 있으며, '변수명'만으로 다른 함수의 메모리 공간에 접근할 수 없음. 

- 메모리주소

: 함수나 변수를 선언할 때 할당되는 메모리 공간의 위치를 나타내는 값. 자료형의 크기에 따라 메모리 공간이 할당되고, 2바이트 이상의 변수는 여러 개의 주소 값에 걸쳐 할당됨. 한 변수(혹은 함수)에 대하여 할당된 메모리 전체는 변수(혹은 함수)의 이름으로 사용될 수 있음.

* 주소 연산자 (&, 엠퍼센트) : 변수 앞에 붙이면, 해당 변수에 할당된 메모리 공간의 주소를 나타내는 주소 값이 됨. 4

** 주소를 출력할 때는 "%p" 를 사용

 

[포인터]

: 메모리 주소 값을 저장하는 변수 자료형. 변수 앞에 *만 붙이면 포인터 변수로 선언할 수 있음.

< 자료형 *변수명;>

 포인터 변수에는 '주소 값'만 저장할 수 있음. 포인터 변수 pa에 변수 a의 주소를 저장하면, '포인터 변수 pa가 변수 a를 가리킨다.' 라고 표현.

 ** 포인터를 화살표로 생각하면 이해하기 쉬움!!

 

- 간접 참조 연산자(*) : 포인터 변수에 저장된 변수 주소에 접근하여 데이터를 추출, 저장 등 데이터 처리가 가능한 연산자. 포인터 변수를 선언할 때는 <자료형 *변수명>의 형태로 선언하고, 간접 참조할 때는 자료형을 제외하고 <*변수명>의 형태로 사용함.

 

[const 포인터]

: const는 constant, 상수라는 뜻으로, 선언하면서 저장된 값을 변경할 수 없도록 함. const로 선언된 포인터 변수의 경우, 해당 포인터 변수를 통해 저장된 메모리 공간에 접근하여 값을 변경할 수 없다는 것을 의미함! > 데이터 변경 시도 시 에러 메시지 출력.

 

09-2 포인터 완전 정복을 위한 포인터 이해

* 포인터 ? 주소를 저장하는 일정한 크기의 메모리 공간. 다른 주소 저장, 포인터의 대입이 가능함. 

 

[주소와 포인터의 차이]

주소 : 변수에 할당된 메모리 저장 공간의 시작 주소 값. 상수이므로 다른 값을 대입하거나 변경이 불가함.

포인터 : 변수에 할당된 메모리 저장 공간의 시작 주소 값, 즉 주소를 저장하는 또 다른 메모리 공간. const로 선언되지 않는 이상 변수이므로 다른 값을 대입하거나 변경이 자유로움. 

 

즉, 프로그램 내에서 선언된 변수에 할당되는 메모리 공간의 주소는 코드가 실행된 이후로 절대 그 값이 바뀌지 않지만, 포인터 변수를 선언할 경우 코드를 어떻게 짜는지에 따라 저장된 주소 값이 바뀔 수 있음. 즉, 가리키는 변수(포인터 변수가 가리키는 메모리 공간 위치)가 달라질 수 있음.

 

[주소와 포인터의 크기]

- sizeof 연산자를 통해 구할 수 있음. 포인터와 주소의 경우, 메모리 공간의 특정 위치가 저장되므로 포인터의 크기와 변수의 주소 크기는 동일하지만, 해당 주소가 가리키는 변수의 크기는 달라질 수 있음! 

 

[포인터 대입 규칙]

: 포인터는 크기가 모두 같지만, 포인터가 가리키는 변수의 형태가 같을 때만 대입이 가능함. > 일반 변수와 비슷함!

  *형 변환을 사용한 포인터의 대입은 가능.

 

[포인터 사용 이유]

: 함수 안에 선언된 변수명은 사용 범위가 함수 내부로 제한되므로, 다른 함수에서 선언된 변수에 접근하거나 데이터를 처리할 수 없음. > 서로 다른 함수에서 선언된 변수에 접근해서 다양한 데이터 처리를 하기 위해 포인터가 필수!! 

 

 

< 예제 코드 >

1. 

#include <stdio.h>

int main(){
    int a;
    double b;
    char c;

    printf("int형 변수의 주소 : %u\n", &a);
    printf("double형 변수의 주소 : %u\n", &b);
    printf("char형 변수의 주소 : %u\n", &c);
}
int형 변수의 주소 : 6422300 
double형 변수의 주소 : 6422288
char형 변수의 주소 : 6422287

 

2.

#include <stdio.h>

int main(){
    int a;
    int *pa;

    pa = &a;
    *pa = 10;

    printf("포인터로 a값 출력 : %d\n", *pa);
    printf("변수명으로 a값 출력 : %d\n", a);
}

 

 

3. 

#include <stdio.h>

int main(){
    int a = 10, b = 15, total;
    double avg;
    int *pa, *pb;
    int *pt = &total;
    double *pg = &avg;

    pa = &a;
    pb = &b;

    *pt = *pa + *pb;
    *pg = *pt / 2.0;

    printf("두 정수의 값 : %d, %d\n", *pa, *pb);
    printf("두 정수의 합 : %d\n", *pt);
    printf("두 정수의 평균 : %.1lf\n", *pg);
}

 

 

 

5. 

#include <stdio.h>

int main(){
    char ch;
    int in;
    double db;

    char *pc = &ch;
    int *pi = &in;
    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));
}

 

char형 변수의 주소 크기 : 4
int형 변수의 주소 크기 : 4
double형 변수의 주소 크기 : 4
char * 포인터의 크기 : 4
int * 포인터의 크기 : 4
double * 포인터의 크기 : 4
char * 포인터가 가리키는 변수의 크기 : 1
int * 포인터가 가리키는 변수의 크기 : 4
double * 포인터가 가리키는 변수의 크기 : 8

 

 

6. 

#include <stdio.h>

void swap(int* pa, int* pb);

int main(){
    int a = 10, b = 20;

    swap(&a, &b);
    printf("a : %d, b : %d\n", a, b);

}

void swap(int* pa, int* pb){
    int temp;

    temp = *pa;
    *pa = *pb;
    *pb = temp;
    
}

* 포인터를 활용하면 외부 함수에서 메인 함수에 선언된 변수 메모리에 접근하여 그 안의 값을 수정할 수 있음!!

 

 

7. 도전 실전 예제

#include <stdio.h>

void swap(double *pa, double *pb);
void line_up(double *maxp, double *midp, double *minp);

int main(){
    double max, mid, min;

    printf("실수값 3개 입력 : ");
    scanf("%lf%lf%lf", &max, &mid, &min);
    line_up(&max, &mid, &min);
    printf("정렬된 값 출력 : %.1lf, %.1lf, %.1lf\n", max, mid, min);

}

void swap(double *pa, double *pb){
    double temp;
    temp = *pa;
    *pa = *pb;
    *pb = temp;
}

void line_up(double *maxp, double *midp, double *minp){
    if(*maxp < *midp){
        swap(maxp, midp);
    }

    if(*maxp < *minp){
        swap(maxp, minp);
    }

    if(*midp < *minp){
        swap(midp, minp);
    }
}
실수값 3개 입력 : 2.7 1.5 3.4
정렬된 값 출력 : 3.4, 2.7, 1.5