while (1): study();

[C언어]특별한 포인터 본문

학습/C, C++

[C언어]특별한 포인터

전국민실업화 2021. 12. 11. 20:01
728x90

여기서는 이중 포인터, 배열 포인터, 함수 포인터, 그리고 void 포인터의 의미와 용례를 살펴본다.

 

1. 이중 포인터

 

이중 포인터란 포인터의 주소를 저장하는 포인터이다. 일반적으로 깊이가 3 이상인 (포인터의 포인터의 포인터부터) 다중 포인터라고 부르는데, 가독성 문제로 잘 사용되지는 않는다.

// 이중 포인터 선언
int **ppi;

포인터 선언에서 중요한 것은 포인터가 가리키는 자료형포인터 자신의 자료형이다. 따라서 다음 선언문은 다음과 같이 분해할 수 있다. 정수포인터를 가리키는 포인터 변수임을 쉽게 알 수 있다.

// int*형을 가리키는 포인터
int* (*ppi);

이중 포인터는 다음과 같이 함수의 매개변수를 받을때 유의미하게 사용할 수 있다.

 

활용1. 포인터 값을 바꾸는 함수의 매개변수

#include <stdio.h>

void swap_prt(char **ppa, char **ppb);

int main(void)
{
    char *pa = "success";
    char *pb = "failure";
    
    printf("pa -> %s, pb -> %s\n", pa, pb);
    swap_prt(&pa, &pb);
    printf("pa -> %s, pb -> %s\n", pa, pb);
    
    return 0;
}

void swap_ptr(char **ppa, char **ppb)
{
    char *pt;
    
    pt = *ppa;
    *ppa = *ppb;
    *ppb = pt;
}

 

활용2. 포인터 배열을 매개변수로 받는 함수

#include <stdio.h>

void print_str(char **pps, int cnt); 

int main(void)
{
    char *ptr_ary[] = {"eagle", "tiger", "lion", "squirrel"};
    int count;
    
    count = sizeof(ptr_ary) / sizeof(ptr_ary[0]_;
    print_str(ptr_ary, count);
    
    return 0;
}

void print_str(char **pps, int cnt)
{
     int i;
     
     for (i = 0; i < cnt; i++)
     {
     	printf("%s\n", pps[i]);
   	 }
}

 

2. 배열 포인터

 

 배열 포인터는 배열의 주소를 저장하는 변수이다. 포인터를 선언할 때 중요한 것 중 하나는 포인터가 가리키는 변수의 자료형이라고 하였다. 다음과 같은 이차원 배열의 주소를 포인터 변수로 받고자 할때, 포인터 변수는 전체 배열의 주소를 할당받으며, 자료형은 서브배열의 자료형이다.

int ary[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
int (*pa)[4]; // int[4] 배열을 저장하는 포인터

pa = ary;

ary가 길이 4의 정수형 배열로 이루어진 이차원 배열이므로 위와 같이 배열 포인터를 선언한다.

 

3. 함수 포인터

 

 함수 포인터는 함수의 주소를 저장하는 변수이다. 함수 포인터의 선언은 배열 포인터와 다소 유사하므로 생략한다. 한 가지 알아둬야 할 것은 함수명은 컴파일 시 함수가 올려진 메모리의 첫 주소가 된다는 점이다. 따라서  함수를 포인터에 저장하고자 하면 함수명 그대로 할당하면 된다.

#include <stdio.h>

void func(int (*fp)(int, int));
int sum(int, int);
int mul(int, int);
int max(int, int);

int main(void)
{
	int sel;

	printf("01 두 정수의 합\n");
	printf("02 두 정수의 곱\n");
	printf("03 두 정수 중에서 큰 값 계산\n");
	printf("원하는 연산을 선택하세요 : ");
	scanf("%d", &sel);
	switch (sel)
	{
	case 1: func(sum); break;
	case 2: func(mul); break;
	case 3: func(max); break;
	}

	return 0;
}

void func(int (*fp)(int, int))
{
	int a, b;
	int res;

	printf("두 정수의 값을 입력하세요 : ");
	scanf("%d%d", &a, &b);
	res = fp(a, b);
	printf("결과값은 : %d\n", res);
}

int sum(int a, int b)
{
	return (a + b);
}

int mul(int a, int b)
{
	return (a * b);
}

int max(int a, int b)
{
	if (a > b) return a;
	else return b;
}

 

4. void 포인터

 

 자료형에 관계없이 주소를 저장할 경우 void 포인터를 사용한다. void 포인터는 다음과 같이 선언한다.

void *vp;

 단, void 포인터를 사용할 경우 형변환하여 사용한다. 형변환하지 않고 사용할 수는 있으나, 명시적으로 항상 형변환하는 것이 가독성이나 디버깅 측면에서 용이하다. 밑은 그 예시이다.

#include <stdio.h>

int main(void)
{
	int a = 10;
	double b = 3.5;
	void* vp;

	vp = &a;
	printf("a : %d\n", *(int*)vp);

	vp = &b;
	printf("b : %.1f\n", *(double*)vp);

	return 0;
}

void 포인터는 자료형에 대한 정보가 내재되어 있지 않으므로 간접 참조 연산과 정수 연산이 불가능하다는 것을 참고하자.

728x90

'학습 > C, C++' 카테고리의 다른 글

성적 처리 프로그램  (0) 2021.12.14
소수 계산 프로그램  (0) 2021.12.13
프로필 교환 프로그램  (0) 2021.12.12
가로 세로의 합 구하기  (0) 2021.12.09
[C언어] 변수의 종류  (0) 2021.12.08
Comments