C++ (11) - 포인터
본 내용은 어소트락 무료 강의 <C/C++ 무료강의>을 기반으로 공부한 내용을 정리한 것이다. 틀린 내용이 있을 수도 있음.
포인터 변수
포인터 변수 : “주소를 저장하는 기능을 수행하는 변수”
주소 : 메모리 영역에 할당된 값들의 위치
int* pInt = nullptr; // nullptr => 0. 초기화를 했다고 생각. 즉 해당 포인터가 아무것도 가르키지 않는다는 뜻.
int i = 100;
int* pInt = &i; // &i => i 변수의 주소값을 가져온다.
(*pInt) = 100; // 포인터 변수에 저장된 주소값(i)으로 접근해서 i값을 설정.
포인터 변수가 데이터를 처리하는 방식?
포인터 변수가 데이터를 처리하는 방식은 무엇일까? 정수형? 실수형?
일단 주소의 단위를 알아야 함. 주소를 표현하는 방식은 정수형.
주소의 단위 = “Byte” -> Bit 단위까지는 주소를 보유할 수 없음. 이를테면 100번지 주소와 102번지 주소 사이에는 101번지가 있고 100~101사이 1Byte, 101~102사이 1Byte해서 2Byte가 존재한다.
포인터가 해당 주소로 접근 후 얼마를 가는가? = 해당 포인터 변수 앞 자료형에 따라 다르다.
즉, 포인터 앞 자료형은 포인터가 가리킬 데이터의 타입을 의미한다. 답정너 느낌!
똑같은 Byte인 float로 주소를 본다면? 주소를 받을 수 있을까?
int i = 100;
float f = 3.f;
int* pInt = (int*)&f; // (int*) => 강제로 접근할 수 있게끔 한다.
i = *pInt; // int로 접근 -> 그러나 실체는 float
// 실수형을 정수형으로 보게 됨. i가 매우 큰 값을 가짐.
앞서 정수형 & 실수형 자료형을 배우면서 가장 중요했던 것이있다. 바로
“메모리 안에 데이터는 똑같은데 관점에 따라 다르게 해석한다”라는 것이다.
자료형 + * 변수명 = 해당 포인터에게 전달된 주소를 해석하는 단위이다.
이 부분을 이해하면 포인터는 거의 90% 했다고 보면 된다.
포인터 배열
64비트와 32비트 운영체제
우리가 사용하는 운영체제는 거의 64비트 운영체제를 사용한다고 생각하자.
그렇다면 포인터 변수의 크기는 8 Byte라고 할 수 있다. (앞에 어떤 자료형이 붙어도 동일!!)
옛날 시절로 돌아가서 32비트 운영체제를 생각해보자.
32비트 = 2^32 = 약 42억 -> Giga Byte환산 시 약 4GB이다. 때문에 컴퓨터에 RAM을 16GB를 꽂든 32GB를 꽂든 운영체제의 GB 한계로 4GB 언저리의 주소값까지밖에 가지 못한다.
포인터변수 크기와 증감단위
int iSize = sizeof(Int* or pInt); // sizeof를 이용해 포인터 변수 크기가 8 byte임을 확인 (64비트 기준)
int i = 0; // i 값 초기화
pInt = &i; // i 값 주소를 불러옴 -> 포인터 변수 pInt에 저장
pInt += 1; // 포인터 변수에 저장된 주소값이 자료형 만큼 (int) 증가
이때 저장된 주소값의 증감 단위는 포인터 변수의 자료형을 따른다!
예시로 위 코드에서 pInt의 증감 단위는 1이 아니라 4(int)이다.
정리하면 pInt는 int* 변수이기 때문에 가리키는 곳을 int로 해석한다.
따라서 주소값을 1 증가하는 의미는 다음 int 위치로 접근하기 위해서 sizeof(int) 단위로 증가하게 된다.
저번에 배울 때 배열은 메모리가 연속적인 것이 특징이라고 했다. 배열을 제대로 알려면 포인터가 필수!
배열과 포인터의 상관관계
int iArray[10] = {}; // 특징 : 1. 메모리가 연속적인 구조이다.
// 특징 : 2. 배열의 이름은 배열의 시작 주소이다.
*(iArr + (정수)); // 포인터를 이용해 배열의 특정 위치를 접근할 수 있다.
*(iArr + 0) = 10; // 배열의 시작 주소. 배열의 Index가 0부터 시작하는 이유!!
*(iArr + 1) = 10; // 배열의 시작 주소로 부터 1칸 (int 단위로) 다음인 2번째 Index에 10을 넣겠다.
iArr[0] = 10; // 위의 코드를 간단하게 나타낸 코드.
iArr[1] = 10;; // 배열 자체가 포인터 접근의 축약의미이다.
연습문제
#include <stdio.h>
int main()
{
// 문제 1.
short sArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10 };
int* pI = (int*)sArr;
int iData = *((short*)(pI + 2));
printf("The Answer is : %d\n", iData);
// 문제 2.
char cArr[2] = { 1, 1 };
short* pS = (short*)cArr;
iData = *pS;
printf("The Answer is : %d\n", iData);
return 0;
}
문제 1 정답 : 5 문제 2 정답 : 257
문제1 해설
short 배열에 10개의 Index가 있다. 각각 2 Byte를 가지고 있으며
그곳에 int 자료형으로 포인터 접근을 시도. 본래 배열이 short이므로 강제 캐스팅
Index를 int 자료형으로 2칸 이동 -> 총 8 byte만큼 주소값이 이동하므로 배열의 처음 주소로 부터 short Index 4칸이 이동한 셈이 된다. 이때 int 만큼 더 접근을 하게 되면 원하는 값을 찾기 어려우므로 short 강제 캐스팅을 더해주면 문제의 답인 5가 나온다.
문제2 해설
char 배열에 2개의 Index가 있다. 각각 1 Byte를 가지고 있으며
그곳에 short 자료형으로 접근하려 한다. 이때 배열이 char 이므로 short 강제 캐스팅
그러면 포인터로 해당 배열 주소를 가르켰을때, 1 Byte = 8 Bit 이므로 총 16 Bit를 하나의 이진수 자료형태로 접근한다. 따라서 00000001 | 00000001 인 배열이 하나의 이진수 자료형인 0000000100000001이 되므로 계산을 통해 256+1 = 257이 나온다. |