포인터 변수: 메모리의 주소를 저장하는 변수
포인터를 통해 특정 메모리 주소로 이동해서 데이터를 참조하거나 수정할 수 있음
int* pInt; // 정수를 가리키는 포인터 변수
char* pChar; // 문자를 가리키는 포인터 변수
자료형 + * 변수명int*는 주소를 int로 해석하고, char*는 주소를 char로 해석포인터 변수 선언 및 초기화
int a = 10;
int* pInt = &a; // a의 주소를 pInt에 저장
& 연산자: 변수의 주소를 가져옴pInt는 a의 주소를 저장하고, 이 주소를 통해 a의 값을 참조할 수 있음포인터를 통한 값 접근
*pInt = 20; // 포인터를 통해 a의 값을 20으로 변경
printf("%d\n", a); // 출력: 20
* 연산자: 포인터가 가리키는 주소의 값을 참조100, 101, 102라면 이는 메모리 상에서 연속적인 1바이트 간격으로 나타냄int* 포인터는 4바이트(sizeof(int)) 단위로 이동pInt += 1은 다음 int 위치로 이동하며, 주소값은 sizeof(int)만큼 증가int arr[3] = {10, 20, 30};
int* pInt = arr;
std::cout << "초기 주소: " << pInt << std::endl; // arr[0]의 주소
pInt += 1; // 다음 int로 이동
std::cout << "1 증가 후 주소: " << pInt << std::endl; // arr[1]의 주소
std::cout << "1 증가 후 값: " << *pInt << std::endl; // 출력: 20
포인터 변수의 크기는 포인터가 가리키는 자료형과는 무관하며, 플랫폼(운영체제)에 따라 결정됨
int* pInt;
char* pChar;
printf("%zu\n", sizeof(pInt)); // 4 (32비트) 또는 8 (64비트)
printf("%zu\n", sizeof(pChar)); // 동일한 크기
메모리가 연속적인 구조이다
int iArr[10] 선언 시, 배열 iArr는 10개의 정수를 저장할 수 있는 연속된 메모리 공간을 할당받음sizeof(iArr[0])만큼의 간격을 가짐배열의 이름은 배열의 시작 주소이다
int iArr[10];에서 iArr는 &iArr[0]와 동일한 의미int iArr[10] = {};
*(iArr + 0) = 10; // 포인터 연산을 이용하여 iArr[0]에 접근
*iArr = 10; // 배열 이름 자체가 시작 주소이므로 동일한 표현
short sArr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pI = (int*)sArr;
int iData = *((short*)(pI + 2));
printf("1번 문제 정답 : %d\n", iData);
풀이
1. short sArr[10] 배열 선언
sArr는 short 타입(2바이트) 요소 10개로 구성 주소 값 (2진수로 표현)
0x00 00000000 00000001 (sArr[0] = 1)
0x02 00000000 00000010 (sArr[1] = 2)
0x04 00000000 00000011 (sArr[2] = 3)
0x06 00000000 00000100 (sArr[3] = 4)
0x08 00000000 00000101 (sArr[4] = 5)(주소는 2바이트 단위로 증가)int* pI = (int*)sArr
sArr를 int*로 강제 캐스팅했기 때문에, pI는 4바이트(2개의 short) 단위로 배열을 접근 pI[0] = 00000000 00000001 | 00000000 00000010 (1과 2 합침)
pI[1] = 00000000 00000011 | 00000000 00000100 (3과 4 합침)
pI[2] = 00000000 00000101 | 00000000 00000110 (5과 6 합침)pI + 2 접근
pI + 2는 sArr[4]와 sArr[5]를 포함한 4바이트 영역을 가리킴(short*)(pI + 2)로 캐스팅
pI + 2를 short*로 캐스팅하면, 다시 2바이트 단위로 접근하게 됨 *((short*)(pI + 2))는 sArr[4]를 가리킴결과
5 출력char cArr[2] = { 1, 1 };
short* pS = (short*)cArr;
iData = *pS;
printf("2번 문제 정답 : %d\n", iData);
풀이
char cArr[2] 배열 선언
cArr는 char 타입(1바이트) 요소 2개로 구성 주소 값 (2진수로 표현)
0x00 00000001 (cArr[0] = 1)
0x01 00000001 (cArr[1] = 1)short* pS = (short*)cArr
cArr를 short*로 캐스팅했기 때문에, pS는 2바이트 단위로 배열을 접근 pS는 cArr[0]와 cArr[1]를 합친 값을 가리킵니다.*pS 접근
pS가 가리키는 2바이트는 다음과 같이 결합: 00000001 | 00000001 (cArr[0]과 cArr[1] 결합)
= 00000001 00000001 (2진수)
= 257 (10진수)결과
257 출력cArr 배열이 {1, 2}로 변경되었을 때 결과가 258이 아니라 513인 이유cArr[0] 값이 하위 바이트로 먼저 저장되고, cArr[1] 값이 상위 바이트로 저장됨short* pS로 읽을 때, 메모리에서 하위 바이트부터 읽기 때문에 값이 513이 됨엔디언(Endian) 방식이란?
⦁ 리틀 엔디언 (Little Endian)
0x0201 (16진수 값) → 01 02 (메모리에 저장되는 순서)⦁ 빅 엔디언 (Big Endian)
0x0201 → 02 01cArr[2] = {1, 2}의 메모리 배치
⦁ 배열 선언
char cArr[2] = {1, 2};
short* pS = (short*)cArr;
int iData = *pS;
⦁ 메모리 상태 (리틀 엔디언 기준)
주소 값
0x00 00000001 (cArr[0] = 1)
0x01 00000010 (cArr[1] = 2)
⦁ short* pS 접근
바이트 순서: 00000010 | 00000001
(cArr[1]) (cArr[0])
결과: 0x0201 (16진수) = 513 (10진수)
빅 엔디언일 때
바이트 순서: 00000001 | 00000010
(cArr[0]) (cArr[1])
0x0102 (16진수) = 258 (10진수)