본문 바로가기
프로그래밍 언어/c(일반)

포인터(5) - 다중 포인터(이중포인터 위주)

by [Akashic Records] 개발의선지자 2024. 7. 12.

※ 해당 글은 개인 공부 기록을 남겨놓는 것이 목적임으로 오류가 발생할수 있습니다.

    오류 또는 업데이트된 사항이 있다면 댓글로 알려주시면 감사하겠습니다.

이중 포인터(더블 포인터)

이중 포인터 : 포인터 변수를 가리키는 또 다른 포인터 변수 

 

선언 방법 : 자료형 ** 이중포인터 변수명

 

예제1

#include <stdio.h>

int main()
{
    
    double num = 3.14;
    double * ptr = &num;
    double **dptr = &ptr;
    double *ptr2;
    
    printf("%p %p\n", ptr, *dptr);
    printf("%f %f\n", num, **dptr);
    ptr2 = *dptr // ptr2 = ptr;
    *ptr2 = 10.99;
    printf("%f %f\n", num, **dptr);

    return 0;
}

 

이중 포인터가 가리키는 대상을 바꾸는 Swap 함수 구현

Call by Address 방식으로 인자로 변수의 주소값을 넘기고, 매개변수는 주소를 저장할 포인터 변수

 

출력 결과 

1. *ptr1, *ptr2 : 10 20
2. *ptr1, *ptr2 : 20 10
3. *ptr1, *ptr2 : 10 20

#include<stdio.h>

void swapPtr(int* a, int * b)
{
    int temp; 
    temp = *a;
    *a = *b;
    *b = temp;
}

void swapDptr(int **dp1, int **dp2)
{
	int *temp = *dp1;
    *dp1 = *dp2;
    *dp2 = temp;
}

int main(void)
{
	int num1 = 10, num2 = 20;
    int *ptr1,*ptr2;
    ptr1 = &num1, ptr2 = &num2;
    printf("1. *ptr1, *ptr2 : %d %d\n", *ptr1, *ptr2);
    
    swapDptr(&ptr1, &ptr2);
    printf("2. *ptr1, *ptr2 : %d %d\n", *ptr1, *ptr2);
    
    swapPtr(ptr1, ptr2);
    printf("3. *ptr1, *ptr2 : %d %d\n", *ptr1, *ptr2);
    
    return 0;
}

 

포인터 배열과 포인터 배열의 포인터형 

배열명은 자료형 포인터이다. 

1차원 배열 int arr[]에서 배열명 arr는 int형 싱글 포인터이다.

포인터 배열 int * arr[]에서 배열명 arr은 int형 더블 포인터이고, 각 배열 요소는 int형 싱글 포인터이다.

 

출력 결과

10 20 30 
10 20 30 

 

#include <stdio.h>

int main(void)
{
	int num1 = 10, num2 = 20, num3 = 30;
    int *ptr1 = &num1; int *ptr2 = &num2; int *ptr3 = &num3; 
    
    
    int *ptrArr[] = {ptr1, ptr2, ptr3};
    int **dptr = ptrArr;
    
    for(int i=0; i<3; i++){
    	printf("%d ", *(ptrArr[i]));
    }
    printf("\n");
	
    for(int i=0; i<3; i++){
    	printf("%d ", *(dptr[i]));
    }
    printf("\n");
}

 

2차원 배열 이름의 포인터형

 

2차원 배열명이 가리키는 것은? 인덱스 기준으로 [0][0]에 위치한 첫번째 요소를 가리키면서 배열 전체 의미 

주의!!!! 2차원 배열의 이름은 더블 포인터형이 아니다.

 

배열명[i] : 첫번째 요소 가리키되 (i+1)행만 의미 

 

예제1)

출력 결과
542267728 
542267728 
542267728 

542267740 
542267740 

542267752 
542267752 

sizeof(arr2d) : 36  // 4 * 9  , 배열 전체 크기
sizeof(arr2d[0]) : 12  // 4 * 3 , 1행의 크기
sizeof(arr2d[1]) : 12  // 4 * 3,  2행의 크기
sizeof(arr2d[2]) : 12  // 4 * 3,  3행의 크기

#include <stdio.h>

int main(void)
{
	int arr2d[3][3];

    printf("%d \n", arr2d);
    printf("%d \n", arr2d[0]);
    printf("%d \n\n", &arr2d[0][0]);

    printf("%d \n", arr2d[1]);
    printf("%d \n\n", &arr2d[1][0]);

    printf("%d \n", arr2d[2]);
    printf("%d \n\n", &arr2d[2][0]);


    printf("sizeof(arr2d) : %d \n", sizeof(arr2d));
    printf("sizeof(arr2d[0]) : %d \n", sizeof(arr2d[0]));
    printf("sizeof(arr2d[1]) : %d \n", sizeof(arr2d[1]));
    printf("sizeof(arr2d[2]) : %d \n", sizeof(arr2d[2]));

    return 0;
}

 

예제2)

2차원 배열이름 증가 연산 예제

 

출력 결과

arr1 : 0x7ffe23434aa0 
arr1+1 : 0x7ffe23434aa8 
arr1+2 : 0x7ffe23434ab0 

arr2 : 0x7ffe23434ac0 
arr2+1 : 0x7ffe23434acc 

 

#include <stdio.h>

int main(void)
{
	int arr1[3][2];
    int arr2[2][3];
    
    printf("arr1 : %p \n", arr1);
    printf("arr1+1 : %p \n", arr1+1);
    printf("arr1+2 : %p \n\n", arr1+2);
    
    printf("arr2 : %p \n", arr2);
    printf("arr2+1 : %p \n", arr2+1);
    return 0;
}

 

 

int arr[3][4];

 

다음 배열이름의 포인터형은 

배열이름 arr이 가리키는 대상은 "int형 변수"이고, arr의 값을 1 증감시 , "sizeof(int) * 4(열의 크기)"만큼 주소 값이 증감하는

"포인터형"이다

 

배열 포인터 변수 

 

int (*ptr)[4] 같이 2차원 배열을 가리키는 용도로만 사용되는 포인터 변수

int (*ptr)[4]  -> 포인터

int (*ptr)[4]  -> int형 변수를 가리키는 포인터

int (*ptr)[4] -> 포인터 연산 시 4칸씩 건너띄는 포인터

 

예제3

 

출력 결과

1 2
3 4

1 2
3 4
5 6

1 2
3 4
5 6
7 8

#include <stdio.h>

int main(void)
{
	int arr1[2][2]= {
    	{1, 2}, {3, 4}
    };
    
    int arr2[3][2]= {
    	{1, 2}, {3, 4}, {5, 6}
    };

	int arr3[4][2]= {
    	{1, 2}, {3, 4}, {5, 6}, {7, 8}
    };

    int (*ptr)[2];
    int i;
    ptr = arr1;
    for(int i=0; i<sizeof(arr1)/sizeof(arr1[0]); i++) printf("%d %d\n", ptr[i][0], ptr[i][1]);
    printf("\n");
    ptr = arr2;
    for(int i=0; i<sizeof(arr2)/sizeof(arr2[0]); i++) printf("%d %d\n", ptr[i][0], ptr[i][1]);
    printf("\n");
    ptr = arr3;
    for(int i=0; i<sizeof(arr3)/sizeof(arr3[0]); i++) printf("%d %d\n", ptr[i][0], ptr[i][1]);
    printf("\n");
    
    return 0;   
}

 

 

배열 포인터와 포인터 배열

 

배열 포인터와 포인터 배열의 외형 차이점은 소괄호의 유무

ex) 

int * arrA[4]; //포인터 배열

int (*arrB)[4]; //배열 포인터

 

arrA는 int형 포인터 변수로 이뤄진 int형 포인터 배열

arrB는 가로길이(열)가 4인 int형 2차원 배열을 가리키는 용도의 포인터 변수

 

배열 포인터와 포인터 배열 비교 예제

 

출력 결과

10 20 30 40 
1 2 3 4 
5 6 7 8 

#include <stdio.h>

int main(void)
{
	int num1 = 10, num2 = 20, num3 = 30, num4 = 40;
    int arr2d[2][4] = { {1,2,3,4}, {5,6,7,8} };
    
    int * whoA[4] = {&num1, &num2, &num3, &num4};
    int (*whoB)[4] = arr2d;
    
    for(int i=0; i<4; i++) printf("%d ", *whoA[i]);
    printf("\n");
    
    for(int i=0; i<sizeof(arr2d) / sizeof(arr2d[0]); i++){
        for(int j=0; j<sizeof(arr2d[0]) / sizeof(int); j++){
        	printf("%d ", whoB[i][j]);
        }
        printf("\n");
    }
	return 0;
}

 

 

2차원 배열을 함수의 인자로 전달

반환값자료형 함수이름(자료형 매개변수[][가로크기])
{
}

반환값자료형 함수이름(자료형 (*매개변수)[가로크기])
{

 

 

다음 포스팅에서는 void 포인터에 대해 포스팅할 예정이다.