C언어/C언어 이론

[C언어] 7주차 포인터의 활용

renne 2022. 6. 26. 15:54

포인터 배열

 - 주소를 저장하는 배열

 

포인터 배열의 선언

데이터형	*배열이름[배열크기];
int	*arr1[10];
char	*arr2[20];
double	*arr3[30];
STUDENT	*arr4[40];	//구조체

 

포인터 배열의 사용

#include <stdio.h>
int main(){
    int a = 10, b = 20, c = 30;
    int *arr[3] = {&a, &b, &c};	//포인터 배열의 각 원소로 변수의 주소를 저장

    for (int i = 0; i < 3; i++){
        printf("원소: %d, ", arr[i]);
        printf("원소가 가리키는 변수: %d\n", *arr[i]);	//간접 참조 연산자 * 사용
    }
    return 0;
}

<실행 결과>
원소: 6487576, 원소가 가리키는 변수: 10
원소: 6487572, 원소가 가리키는 변수: 20
원소: 6487568, 원소가 가리키는 변수: 30
#include <stdio.h>
int main(){
    int x[3] = {1, 2, 3};
    int y[3] = {4, 5, 6};
    int z[3] = {7, 8, 9};
    int *arr[3] = {x, y, z};	//포인터 배열의 각 원소로 배열의 시작 주소를 저장

    for (int i = 0; i < 3; i++){
        for (int j = 0; j < 3; j++){
            printf("%d ", arr[i][j]); //arr[i][j]와 *(arr[i]+j)는 같은 의미다.
        }
        printf("\n");
    }
    return 0;
}

<실행 결과>
1 2 3 
4 5 6 
7 8 9

 

구조체 포인터 배열

구조체 포인터 배열의 필요성

 - 구조체 배열:  메모리를 많이 사용하므로 비효율적이다.

typedef struct student{
    char name[20];
    int kor, eng, math;
    double average;
} STUDENT;

int main(){
    STUDENT std[100];	//STUDENT 구조체가 100개 할당되므로 40*1000바이트가 필요하다.
}

 

 - 구조체 포인터 배열: 구조체는 동적 메모리에 할당하고, 그 주소만 포인터 배열에 넣어두고 사용할 수 있다.

typedef struct student{
    char name[20];
    int kor, eng, math;
    double average;
} STUDENT;

int main(){
    STUDENT s1 = {"시리우스", 80, 90, 100, 0.0};
    STUDENT s2 = {"레귤러스", 90, 85, 90, 0.0};
    STUDENT *std[2] = {&s1, &s2};	//구조체 포인터 배열의 선언 및 초기화
    
    for (int i = 0; i < 2; i++){
        std[i] -> average = (double)((std[i] -> kor) + (std[i] -> eng) + (std[i] -> math)) / 3;
        printf("%s의 평균: %5.2f\n", std[i] -> name, std[i] -> average);
    }
    return 0;
}

<실행 결과>
시리우스의 평균: 90.00
레귤러스의 평균: 88.33

 

구조체 포인터 배열의 메모리 구조

 

배열 포인터

 - 배열 전체를 가리키는 포인터

 

배열 포인터의 선언

데이터형	(*포인터이름)[배열크기];
int	(*p1)[10];
char	(*p2)[20];
double	(*p3)[30];
STUDENT	(*p4)[40];	//구조체

 

배열 포인터의 사용

 - 배열 포인터에는 배열 전체의 주소를 저장한다.

 - 배열 포인터에는 크기가 같은 주소만 저장할 수 있다.

#include <stdio.h>
int main(){
    int arr[5] = {1, 2, 3, 4, 5}; //배열 포인터에는 크기가 같은 주소만 저장할 수 있다.
    int (*p)[5] = &arr;	//배열 포인터에 배열 전체의 주소를 저장한다.

    for (int i = 0; i < 5; i++){
        printf("%d %d %d\n", (*p)[i], p[0][i], *((*p)+i));
    }
    return 0;
}

<실행 결과>
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5

 

*p와 p[0]

 - p는 배열 전체의 주소이고, *p는 p가 가리키는 배열이 된다.

 - *p는 배열 이름처럼 사용할 수 있으므로, p가 가리키는 배열의 i번째 원소에 접근하려면 (*p)[i]를 사용한다.

 - *p는 p[0]이므로, (*p)[i]는 p[0][i]와 같다.

 

배열 포인터와 이차원 배열

 - 배열 포인터는 이차원 배열의 한 묶음을 가리키는 용도로 사용된다.

 - 배열 포인터는 이차원 배열에 접근하기 위한 용도로 사용된다.

#include <stdio.h>
int main(){
    int arr[2][4] = {{1, 2, 3, 4}, {10, 20, 30, 40}};
    int (*p)[4] = &arr[0];	//&arr[0] 대신 arr로 초기화할 수도 있다.

    for (int i = 0; i < 2; i++){
        for (int j = 0; j < 4; j++){
            printf("%2d ", p[i][j]);	//p가 마치 이차원 배열명인 것처럼 사용한다.
        }
        printf("\n");
    }
    return 0;
}

<실행 결과>
 1  2  3  4
10 20 30 40

 

배열 포인터와 배열의 원소를 가리키는 포인터

  배열 포인터 배열의 원소를 가리키는 포인터
선언할 때 데이터형 *(포인터명)[배열크기]; 데이터형 *(포인터명);
초기화할 때 이차원 배열의 주소로 초기화 일차원 배열의 주소로 초기화
사용할 때 이차원 배열처럼 사용 일차원 배열처럼 사용
증가할 때 이차원 배열의 제2크기만큼 증가 원소형 1개 크기만큼 증가

 

함수에 대한 포인터

 - 함수의 주소를 저장하는 포인터

 - 함수는 컴파일 및 링크 후에 메모리의 특정 번지에 할당된다.

 - 실행 파일은 크게 코드 영역(함수들)과 데이터 영역(변수들)으로 나눠진다.

 

함수에 대한 포인터 변수의 선언

리턴형	(*포인터명)(매개변수);	//예시 함수
int	(*p1)(int);		//int Factorial(int n);
char	(*p2)(double, int);	//char Grade(double avg, int rank);

//아직 가리키는 포인터가 없으면 널 포인터로 초기화한다.
int (*p3)(int) = NULL;

 

함수의 주소 구하기

//포인터명 = &함수명
p1 = &Factorial;

//포인터명 = 함수명
p1 = Factorial;

 

함수에 대한 포인터로 함수 호출하기

(*포인터명)(인자);
(*p1)(5);	//p1이 가리키는 Factorial(5)를 호출한다.

포인터명(인자);
p1(5);		//p1이 가리키는 Factorial(5)를 호출한다.
#include <stdio.h>
int Factorial(int n){
    if (n < 2) return 1;
    else return n * Factorial(n-1);
}

double Add(double x, double y){
    return x + y;
}

int main(){
    int (*p1)(int) = &Factorial;
    double (*p2)(double, double) = Add;

    int num;
    scanf("%d", &num);

    printf("%d! = %d\n", num, (*p1)(num));
    printf("1.9 + 7.1 = %f", p2(1.9, 7.1));
    return 0;
}

<실행 결과>
5
5! = 120
1.9 + 7.1 = 9.000000