이중포인터 사용 이유 - ijungpointeo sayong iyu

이중포인터 사용 이유 - ijungpointeo sayong iyu

다중 포인터

어느 정도 포인터의 개념이 익숙해졌다면, 다중 포인터에 대하여 알아보겠습니다.

다중 포인터란 포인터를 담는 포인터의 개념입니다.  포인터를 정확하게 이해하고 있으면 다중 포인터의 개념을 이해하는 데는 문제가 없을 것입니다.

다중 포인터의 선언과 사용 해기 보기

다중 포인터는 포인터 변수를 선언하는 *의 개수로 몇 중 포인터인지 선언을 합니다. 

예를 들어 2중 포인터의 선언은 다음과 같습니다.

	int val;  // 일반 변수
	int* p;   // 1중 포인터 변수
	int** pp; // 2중 포인터 변수

3가지 변수에 대하여 특징을 다시 한번 정리해 보자면 다음과 같습니다.

  • 일반 변수 val
    • 일반 변수는 할당된 메모리 주소 안의 데이터를 사용할 수 있습니다.
  • 1중 포인터 변수 p
    • 포인터 변수 p 안에 메모리 주소의 정보를 저장할 수 있습니다.
    • *을 통해 포인터 변수 p안에 저장된 메모리 주소안의 데이터를 사용할 수 있습니다.
  • 2중 포인터 변수 pp
    • 포인터 변수 pp안에 메모리 주소의 정보를 저장할 수 있습니다.
    • *을 통해 포인터 변수 pp안에 저장되어 있는 메모리 주소 안의 데이터를 사용할 수 있습니다.
    • 만약 pp안에 포인터 변수가 저장되어있다면
      • **을 통해 pp안에 저장된 p안에 저장되어있는 메모리 주소 안의 데이터를 변경할 수 있습니다.
      • *을 통해 pp안에 저장되어있는 p안에 저장되어있는 메모리 주소를 변경할 수 있습니다.
이중포인터 사용 이유 - ijungpointeo sayong iyu
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>

int main()
{
	int val = 10;;  // 일반 변수

	int* p;   // 1중 포인터 변수
	int** pp; // 2중 포인터 변수

	p = &val;
	pp = &p;
	printf("*p로 val 접근: %d\n", *p);
	printf("**pp로 val 접근: %d\n", **pp);
	
	printf("pp에 저장된 메모리 주소 : %X\n", pp);
	printf("p의 메모리 주소 : %X\n", &p);
	printf("p에 저장된 메모리 주소 : %X\n", p);
	printf("val의 메모리 주소 : %X\n", &val);
}
이중포인터 사용 이유 - ijungpointeo sayong iyu

다중 포인터의 장점

포인터와 다중포인터의 개념을 이해했다면 왜 쓰는지 알아야 됩니다.

포인터의 경우 여러 지역변수를 다른 함수에서 제어할 수 있는 장점이 있다고 했습니다.

그렇다면 다중 포인터는 어떤 장점이 있을까요?

어떤 지역 내에 선언된 포인터 변수를 다른 함수에서 제어할 수 있게 됩니다. 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>


void swap(int** pp)
{
	int a;
	int* p;
	p = &a;
	printf("함수 안의 a의 주소 : %p\n", &a);

	//2중 포인터로 main함수안의 p 포인터 안에 저장된 메모리 값 수정
	*pp = &a;

}

int main()
{
	int val = 10;;  // 일반 변수

	int* p;   // 1중 포인터 변수
	p = &val;
	printf("val의 메모리 주소: %p\n", &val);
	printf("함수 실행 전 p안에 저장된 메모리 주소 : %p\n", p);
	swap(&p);
	printf("함수 실행 후 p안에 저장된 메모리 주소 : %p\n", p);

}

이해가 되셨나요? 2중 포인터를 함수의 매개변수로 사용한다면 다른 함수에 있는 포인터 변수에 저장된 메모리 주소를 제어를 할 수 있는 장점이 생깁니다. 이런 기능들을 이용해 함수와 함수 사이에서 조금 더 데이터를 원활하게 관리할 수 있습니다.

앞서 간단하게 포인터란 무엇인지, 예제를 통해 설명.

https://ansan-survivor.tistory.com/1237

[C언어] 포인터란? 포인터에 대해 쉽게 이해하기. (포인터 변수 사용하기, 포인터로 값 변경하기,

(알아두기) 컴퓨터는 32비트와 64비트를 많이 사용한다. 이는 1번 처리에 사용할 수 있는 메모리의 크기이다. 만약 32비트(4byte) PC라면, 8 byte를 할당해도 저장할 수 있는 공간은 4byte 뿐이다. 나머지

ansan-survivor.tistory.com

이중포인터 사용 이유 - ijungpointeo sayong iyu

보통 일반적으로 많이 사용되는 것은, * 하나만을 사용하는 "싱글포인터"이다.

때로는 필요에 의해 포인터에서 또다른 포인터로 참조를 하는 더블포인터, 또 더 참조하면 트리플포인터 까지 사용된다.

이중포인터 사용 이유 - ijungpointeo sayong iyu

위와 같은 다중포인터에 대한 예제.

 1. double* ptr = &num;  => ptr의 타입은 double* 으로 num의 주소값을 저장.

 2. double* *dptr = &ptr;   => dptr은 double* 타입인 ptr이 대입되므로, *을 하나 더 붙여 double** 으로 만듦

#include <stdio.h>

/*
	포인터의 포인터에 대한 이해.
	변수의 주소값을 저장하기 위해서 * 을 추가 하기만 하면 된다.
*/

int main()
{
	double num = 3.14;
	double* ptr = &num;

	// ptr의 타입이 double* 이므로 dptr을 포인터 선언하기 위해서는 *를 더 붙인다.
	double** dptr = &ptr;
	// dptr의 타입이 double** 이므로 tptr을 포인터 선언하기 위해서는* 를 더 붙인다.
	double*** tptr = &dptr;

	/*
		위에 포인터의 정의를 통해, (참조관계)
		tptr -> dptr -> ptr -> num  이런식으로 포인터가 가리키고 있다.
	*/
	printf("num값: %f\n", num);
	printf("ptr값: %f\n", *ptr);
	printf("dptr값: %f\n", **dptr);
	printf("tptr값: %f\n", ***tptr);

	return 0;
}
이중포인터 사용 이유 - ijungpointeo sayong iyu

위와 같은 참조 관계가 구성되어있기 때문에, num의 값을 새로운 포인터변수로 바꿔주면 모두 바뀌게 된다.

이중포인터 사용 이유 - ijungpointeo sayong iyu
새로운 ptr2를 선언해서 num의 주소값을 넣고 값을 5.2를 대입해보기
#include <stdio.h>

/*
	포인터의 포인터에 대한 이해.
	변수의 주소값을 저장하기 위해서 * 을 추가 하기만 하면 된다.
*/

int main()
{
	double num = 3.14;
	double* ptr = &num;

	// ptr의 타입이 double* 이므로 dptr을 포인터 선언하기 위해서는 *를 더 붙인다.
	double** dptr = &ptr;
	// dptr의 타입이 double** 이므로 tptr을 포인터 선언하기 위해서는* 를 더 붙인다.
	double*** tptr = &dptr;

	// 새로운 ptr2선언
	double* ptr2 = NULL;
	ptr2 = &num;
	*ptr2 = 5.2;

	/*
		위에 포인터의 정의를 통해, (참조관계)
		tptr -> dptr -> ptr -> num  이런식으로 포인터가 가리키고 있다.
	*/
	printf("num값: %f\n", num);
	printf("ptr값: %f\n", *ptr);
	printf("dptr값: %f\n", **dptr);
	printf("tptr값: %f\n", ***tptr);

	return 0;
}
이중포인터 사용 이유 - ijungpointeo sayong iyu
모두 num을 참조하기 때문에 다 바뀌게 되었다.

가리키고 있는 대상의 주소값을 확인하기

#include <stdio.h>

/*
	포인터의 포인터에 대한 이해.
	변수의 주소값을 저장하기 위해서 * 을 추가 하기만 하면 된다.
*/

int main()
{
	double num = 3.14;
	double* ptr = &num;

	// ptr의 타입이 double* 이므로 dptr을 포인터 선언하기 위해서는 *를 더 붙인다.
	double** dptr = &ptr;
	// dptr의 타입이 double** 이므로 tptr을 포인터 선언하기 위해서는* 를 더 붙인다.
	double*** tptr = &dptr;

	// 새로운 ptr2선언
	double* ptr2 = NULL;
	ptr2 = &num;
	*ptr2 = 5.2;

	/*
		위에 포인터의 정의를 통해, (참조관계)
		tptr -> dptr -> ptr -> num  이런식으로 포인터가 가리키고 있다.
	*/
	printf("num값: %f\n", num);
	printf("ptr값: %f\n", *ptr);
	printf("dptr값: %f\n", **dptr);
	printf("tptr값: %f\n", ***tptr);


	// 모두 가리키는 대상은 num의 주소값
	printf("num주소: %9p\n", &num); // ptr은 num의 주소값을 가리킴
	printf("ptr이 가리킴: %9p\n", ptr); // ptr은 num의 주소값을 가리킴
	printf("dptr이 가리킴: %9p\n", *dptr);
	printf("tptr이 가리킴: %9p\n", **tptr);
	
    return 0;
}
이중포인터 사용 이유 - ijungpointeo sayong iyu
모두 한곳을 가리키고 있다.

포인터 변수 연산 이해 과정.

아래와 같이 괄호를 활용해서 연산 순서를 이해해보면 더 이해를 잘할 수 있다.

이중포인터 사용 이유 - ijungpointeo sayong iyu