공부했던 자료 정리하는 용도입니다.
재배포, 수정하지 마세요.
포인터
- 포인터
- 포인터 변수
- 포인터 변수의 선언
* 포인터 변수의 크기 - 포인터 형(type)
- 포인터 변수와 관련된 연산자
1. & 연산자
2. * 연산자 - null 포인터
- 포인터 대상의 const 선언
* 상수를 가리키는 포인터인 경우
* 포인터 자체가 상수인 경우
* 포인터가 상수이면서 상수를 가리키는 경우
- 포인터와 배열
- 포인터 연산
- 문자열의 선언방식
- 포인터 배열
* 문자열 배열
- 포인터와 함수
- 함수의 호출 방식
* Call-by-value
* Call-by-reference - 함수의 인자로 배열 전달
* 인자로 배열 전달 시 배열의 크기
- 함수의 호출 방식
- 이중 포인터(더블 포인터)
- 이중 포인터 선언과 사용
- 포인터 변수 대상의 Call-by-reference
- 포인터 배열과 포인터 배열의 포인터 type
- 다중 포인터 변수
- 다차원 배열과 포인터
- 2차원 배열의 이름과, 2차원 배열의 첫 번째 행
- 2차원 배열의 증감 연산
- 2차원 배열의 포인터
- 함수 인자로 2차원 배열 전달
- 다차원 배열에서 arr[i]와 *(arr + i)
- 배열 포인터와 포인터 배열
- main 함수의 인자
* 인자의 형성 과정
* char * argv[ ]
- 함수 포인터
- 함수 포인터 변수 선언
- 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 = #
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가지가 존재하게 된다.
- **dptr = 10.1;
- *ptr =20.2;
- *ptr2 = 30.3;
- 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 = # // 포인터 변수
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 |