공부했던 자료 정리하는 용도입니다.

재배포, 수정하지 마세요.

 

 


 포인터 

  1. 포인터
    • 포인터 변수
    • 포인터 변수의 선언
      * 포인터 변수의 크기
    • 포인터 형(type)
    • 포인터 변수와 관련된 연산자
      1. & 연산자
      2. * 연산자
    • null 포인터
    • 포인터 대상의 const 선언
      * 상수를 가리키는 포인터인 경우
      * 포인터 자체가 상수인 경우
      * 포인터가 상수이면서 상수를 가리키는 경우
  2. 포인터와 배열
    • 포인터 연산
    • 문자열의 선언방식
    • 포인터 배열
      * 문자열 배열
  3. 포인터와 함수
    • 함수의 호출 방식
      * Call-by-value
      * Call-by-reference
    • 함수의 인자로 배열 전달
      * 인자로 배열 전달 시 배열의 크기
  4. 이중 포인터(더블 포인터)
    • 이중 포인터 선언과 사용
    • 포인터 변수 대상의 Call-by-reference
    • 포인터 배열과 포인터 배열의 포인터 type
    • 다중 포인터 변수
  5. 다차원 배열과 포인터
    • 2차원 배열의 이름과, 2차원 배열의 첫 번째 행
    • 2차원 배열의 증감 연산
    • 2차원 배열의 포인터
    • 함수 인자로 2차원 배열 전달
    • 다차원 배열에서 arr[i]와 *(arr + i)
    • 배열 포인터와 포인터 배열
    • main 함수의 인자
      * 인자의 형성 과정
      * char * argv[ ]
  6. 함수 포인터
    • 함수 포인터 변수 선언
  7. void 포인터

 


 

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

  포인터 변수를 가리키는 또 다른 포인터 변수를 이중 포인터 또는 더블 포인터라 부른다. 포인터 변수는 종류에 상관없이 무조건 주소 값을 저장하는 변수인데, 어쨌든 변수이고 메모리에 할당되기 때문에 이를 대상으로도 ``&``연산이 가능하고, 이때 반환되는 주소 값은 더블 포인터 변수에 저장이 가능하다.

 

 

이중 포인터 선언과 사용

double num = 3.14;
double *ptr = #
double **dptr = &ptr;

*dptr = ... 	// *dptr은 포인터 변수 ptr을 의미
*(*dptr) = ... 	// *(*)dptr은 변수 num을 의미, **dptr로도 쓴다.

  더블 포인터는 싱글 포인터와 구분하기 위해서 ``*``를 2개 붙여 선언한다. 더블 포인터 이름에 ``*``을 하나만 붙이면 가리키는 싱글 포인터의 주소 값이 되고, ``**``처럼 두 개를 붙이면 해당 싱글 포인터가 가리키는 값이 된다. ``*(*dptr)``과같은 경우에는 괄호를 생략하고 ``**dptr``로 표현이 가능하며, 생략하는 것이 보다 일반적인 표현이다.

 

#include <stdio.h>

int main(void)
{
	double num = 3.14;
	double *ptr = &num;
	double **dptr = &ptr;
	double *ptr2;
	
	printf("%9p %9p \n", ptr, *dptr);
	printf("%9g %9g \n", num, **dptr);
	ptr2 = *dptr;	// ptr2 = ptr와 같은 문장
	*ptr = 10.99;
	printf("%9g %9g \n", num, **dptr); 
	
	return 0;
}

더블 포인터를 사용하는 예시이다.

 

포인터의 참조관계

12행까지 실행되면 포인터 변수의 참조 관계는 위와 같이 되며, 변수 ``num``에 접근하는 방법은 아래와 같이 총 4가지가 존재하게 된다. 

  1. **dptr = 10.1;
  2. *ptr =20.2;
  3. *ptr2 = 30.3;
  4. num = 40.4;

 

 

 

포인터 변수 대상의 Call-by-reference

#include <stdio.h>

void SwapIntPtr(int *p1, int *p2)
{
	int *temp = p1;
	p1 = p2;
	p2 = temp;
}

int main(void)
{
	int num1 = 10, num2 = 20;
	int *ptr1, *ptr2;
	ptr1 = &num1, ptr2 = &num2;
	printf("*ptr1, *ptr2 : %d %d \n", *ptr1, *ptr2);
	
	SwapIntPtr(ptr1, ptr2);
	printf("*ptr1, *ptr2 : %d %d \n", *ptr1, *ptr2);
	
	return 0;
}

  함수를 이용해서 싱글 포인터 변수의 값을 변경하는 경우 같은 싱글 포인터 변수를 사용하면 값을 변경하지 못한다. 위와 같은 경우에는 ``ptr1``과 ``ptr2``로 ``num1``과 ``num2``의 주소 값을 넘겨주었지만 함수를 실행하면 ``ptr1``과 ``ptr2``자체의 주소같이 넘어가는 게 아니라 이들 안에 저장된 값(``num1``과 ``num2``의 주소)과 같은 주소 값을 가진 포인터 변수 ``p1``, ``p2``가 새로 생겨난다. 그래서 ``p1``, ``p2``끼리는 값이 바뀌어도 원래의 포인터들인 ``ptr1``과 ``ptr2``의 주소 값은 바뀌지 않는다.

 

실행 결과



#include <stdio.h>

void SwapIntPtr(int **p1, int **p2)	// 더블 포인터 변수 선언
{
	int *temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

int main(void)
{
	int num1 = 10, num2 = 20;
	int *ptr1, *ptr2;
	ptr1 = &num1, ptr2 = &num2;
	printf("*ptr1, *ptr2 : %d %d \n", *ptr1, *ptr2);
	
	SwapIntPtr(&ptr1, &ptr2);	// 싱글 포인터 변수의 주소값을 함수의 인자로 사용
	printf("*ptr1, *ptr2 : %d %d \n", *ptr1, *ptr2);
	
	return 0;
}

호출되는 함수의 매개변수를 더블 포인터 변수로 바꾸고, 인자로 싱글 포인터 자체의 주소 값을 넘겨야 값이 제대로 변환된다.

 

실행 결과



 

 

포인터 배열과 포인터 배열의 포인터 type

#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;	// 포인터 배열을 가리키는 더블 포인터(포인터 배열의 자료형과 같음)
	
	printf("%d %d %d \n", *(ptrArr[0]), *(ptrArr[1]), *(ptrArr[2]));
	printf("%d %d %d \n", *(dptr[0]), *(dptr[1]), *(dptr[2]));	// 포인터 변수도 배열의 이름처럼 사용 가능
	
	return 0;
}

  배열의 포인터가 배열의 자료형과 같았던 것처럼 포인터 배열도 1차원 배열이기 때문에 포인터 배열의 자료형에 따라 포인터 형이 결정된다. 또한 14행처럼 포인터의 이름도 배열처럼 사용 가능하다.

 

실행 결과



 

 

다중 포인터 변수

#include <stdio.h>

int main(void)
{
	int num = 100;
	int *ptr = &num;	// 포인터 변수
	int **dptr = &ptr;	// 이중 포인터 변수
	int ***tptr = &dptr;	// 삼중 포인터 변수
	
	printf("%d %d \n", **dptr, ***tptr);
		
	return 0;
}

  포인터 변수를 선언할 때 ``*``연산자가 2개 이상 사용되는 포인터 변수를 다중 포인터 변수라고 한다. 보통 ``*``이 ``n``개 사용된 ``n``중 포인터라면 ``n - 1``중 포인터 변수를 가리키고, ``n - 1``중 포인터 변수의 주소 값을 저장하는 용도로 사용된다. 삼중 포인터부터는 사용되는 곳이 그렇게 많지 않기 때문에 삼중 포인터를 사용해야 하는 경우 포인터의 오용 및 남용은 아닌지, 잘못된 방식으로 접근하고 있는 것은 아닌지 확인해볼 필요가 있다.

 

 

 

'기타 > C' 카테고리의 다른 글

[C] 함수 포인터, void 포인터  (0) 2020.05.22
[C] 다차원 배열과 포인터  (0) 2020.05.19
[C] 포인터와 배열, 함수  (0) 2020.05.07
[C] 포인터  (0) 2020.05.05
[C] 배열 (1차원 배열, 다차원 배열, 가변 길이 배열)  (1) 2020.04.28

+ Recent posts