34.3 다양한 자료형 포인터 & void 포인터
📖 다양한 자료형 포인터
#include <stdio.h>
int main()
{
long long *numPtr1; // long long형 포인터 선언
float *numPtr2; // float형 포인터 선언
char *cPtr1; // char형 포인터 선언
long long num1 = 10;
float num2 = 3.5f;
char c1 = 'a';
numPtr1 = &num1; // num1의 메모리 주소 저장
numPtr2 = &num2; // num2의 메모리 주소 저장
cPtr1 = &c1; // c1의 메모리 주소 저장
printf("%lld\n", *numPtr1); // 10
printf("%f\n", *numPtr2); // 3.500000
printf("%c\n", *cPtr1); // a
return 0;
}
C언어에서 사용할 수 있는 모든 자료형은 포인터로 만들 수 있다. 하지만, 포인터 자료형을 따로 만들지 않고 자료형마다 포인터를 선언하도록 하였다. 그 이유는 무엇일까?
- 포인터에 저장되는 메모리 주솟값은 __정수형으로 동일하다.
- 하지만 선언하는 자료형에 따라 메모리에 접근하는 방법이 다르다.
- 역참조시 선언한 자료형의 크기에 맞춰 값을 가져오거나 저장한다.
즉, long long 포인터는 8바이트 크기만큼 값을 가져오거나 저장하고, char 포인터는 1바이트 크기만큼 값을 가져오거나 저장한다.
변수의 자료형과 포인터를 역참조한 자료형이 다르다면?
상수와 포인터
포인터에도 const 키워드를 붙일 수 있다. const의 위치에 따라 특성이 달라진다.
1. 상수를 가리키는 포인터 (pointer to constant)
=> 역참조로 값 변경 불가능const int num1 = 10; // int형 상수 const int *numPtr; // int형 상수를 가리키는 포인터. int const *numPtr도 같음 numPtr = &num1; *numPtr = 20; // 컴파일 에러. num1이 상수이므로 역참조로 값을 변경할 수 없음
즉, pointer to constant는 메모리 주소에 저장된 값을 변경할 수 없다는 뜻이다.
2. 포인터 자체가 상수 (constant pointer)
=> 포인터가 가리키는 메모리 주소 변경 불가능, 역참조로 값 변경은 가능int num1 = 10; // int형 변수 int num2 = 20; // int형 변수 int * const numPtr = &num1; // int형 포인터 상수 numPtr = &num2; // 컴파일 에러. 포인터(메모리 주소)를 변경할 수 없음
numPtr은 포인터 자체가 상수이므로 다른 포인터(메모리 주소)를 할당할 수 없다. 즉, constant pointer는 메모리 주소를 변경할 수 없다는 뜻이다.
또한, 포인터 자체가 상수이므로 선언과 동시에 초기화를 해주어야 한다.
3. 포인터가 상수면서 상수를 가리키는 상황 (constant pointer to constant)
=> 역참조로 값 변경도 불가능하고, 포인터의 메모리 주소 변경도 불가능하다.
- 포인터를 선언하는 자료형에도 const를 붙이고
*
뒤에도 const를 붙인다.const int num1 = 10; // int형 상수 const int num2 = 20; // int형 상수 const int * const numPtr = &num1; // int형 상수를 가리키는 포인터 상수 // int const * const numPtr도 같음 *numPtr = 30; // 컴파일 에러. num1이 상수이므로 역참조로 값을 변경할 수 없음 numPtr = &num2; // 컴파일 에러. 포인터(메모리 주소)를 변경할 수 없음
numPtr을 역참조한 뒤 값을 변경하려고 해도 num1이 상수이므로 컴파일 에러가 발생한다. 그리고 numPtr 자체도 상수이므로 num2의 주소를 넣으려고 하면 컴파일 에러가 발생한다. ⭐ 즉, constant pointer to constant는 메모리 주소도 변경할 수 없고 메모리 주소에 저장된 값도 변경할 수 없다는 뜻이다.
void 포인터
void 포인터 선언하기
자료형이 정해지지 않은 포인터도 있다.
void 포인터는 void 키워드
와 *
로 선언한다.
#include <stdio.h>
int main()
{
int num1 = 10;
char c1 = 'a';
int *numPtr1 = &num1;
char *cPtr1 = &c1;
void *ptr; // void 포인터 선언
// 포인터 자료형이 달라도 컴파일 경고가 발생하지 않음
ptr = numPtr1; // void 포인터에 int 포인터 저장
ptr = cPtr1; // void 포인터에 char 포인터 저장
// 포인터 자료형이 달라도 컴파일 경고가 발생하지 않음
numPtr1 = ptr; // int 포인터에 void 포인터 저장
cPtr1 = ptr; // char 포인터에 void 포인터 저장
return 0;
}
- 기본적으로 C언어는 자료형이 다른 포인터끼리 메모리 주소를 저장하면 컴파일 경고가 발생
- void 포인터는 자료형이 정해지지 않은 특성 때문에 어떤 자료형으로 된 포인터든 모두 저장
- 반대로, 다양한 자료형으로 된 포인터에도 void 포인터를 저장
이런 특성 때문에 void 포인터는 범용 포인터
라고 하며, 직접 자료형을 변환하지 않아도 암시적으로 자료형이 변환된다.
단, void 포인터는 자료형이 정해지지 않았으므로 값을 가져오거나 저장할 크기도 정해지 않았다. 따라서 void 포인터는 역참조 할 수 없다.
ptr = numPtr1; // void 포인터에 int 포인터 저장
printf("%d", *ptr); // void 포인터는 역참조할 수 없음. 컴파일 에러
ptr = cPtr1; // void 포인터에 char 포인터 저장
printf("%c", *ptr); // void 포인터는 역참조할 수 없음. 컴파일 에러
void 키워드로 변수를 선언할 수도 없다.
void v1; // void로는 변수를 선언할 수 없음. 컴파일 에러
void 포인터를 사용하는 이유
역참조도 할 수 없는 void 포인터는 왜 사용할까?
C언어에서는 실제로 다양한 형태로 사용되고 있다.
예를 들면,
- 함수에서 다양한 자료형을 받아들일 때
- 함수의 반환 포인터를 다양한 자료형으로 된 포인터에 저장할 때
- 자료형을 숨기고 싶을 때 사용한다.
unit 58, 61, 63 참고
출처
https://dojang.io/mod/page/view.php?id=277
https://dojang.io/mod/page/view.php?id=277
Author And Source
이 문제에 관하여(34.3 다양한 자료형 포인터 & void 포인터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@shuajjjjj/다양한-자료형-포인터-선언하기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)