C++ 포인터
주소 연산자 & 주소 연산자 & 를 사용하면 변수에 할당된 메모리 주소를 확인할 수 있다.
#include <iostream>
using namespace std;
int main() {
int x = 5;
cout << x << '\\n';
cout << &x << '\\n';
return 0;
}
역참조 연산자 * 변수의 주소를 얻는 것 자체로는 그다지 유용하지 않다. 역참조 연산자 * 를 사용하면 특정주소에서 값에 접근할 수 있다.
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
int x = 5;
printf("%d\\n", x);
cout << &x << '\\n'; //x변수의 메모리 주소 값
cout << *&x << '\\n'; //x 변수의 메모리 주소값에 할당되어있는 값
return 0;
}
포인터 (Pointer) 주소 연산자 7와 역참조 연산자 *와 함께 이제 포인터에 관해 이야기할 수 있다. 포인터는 어떠한 값을 저장하는 게 아닌 메모리 주소를 저장하는 변수다. 포인터(Pointer) 는 C++ 언어에서 가장 혼란스러운 부분 중 하나로 여겨지지만, 알고 보면 놀랍게도 간단하다.
포인터 선언 (Declaring a pointer) 포인터 변수는 일반 변수처럼 선언되며, 자료형과 변수 이름 사이에 *가 붙는다
자료형 *포인터 이름;
int* iPtr; //int형 포인터
double* dPtr; //double형 포인터
int* iPtr2, *iPtr3; //int형 두 개의 포인터 선언
여러 포인터 변수를 선언하는 경우 별표가 각 변수에 포함되어야 한다.
int* iPtr4, iPtr5 //iPtr4는 int에 대한 포인터지만 iPtr5는 단순한 int다.
일반 변수와 마찬가지로 포인터는 선언 시 초기화되지 않는다. 초기화되지 않은 값은 쓰레기다. int 포인터 라고 말하면 int형에 대한 포인터를 의미한다.
포인터에 값 할당 포인터는 메모리 주소만 저장하므로, 포인터에 값을 할당할 때 그 값은 주소여야 한다. 포인터로 하는 가장 흔한 작업은 다른 변수의 주소를 저장하는 것이다. 변수의 주소를 얻으려면 주소 연산자 & 를 사용한다. 포인터 = &변수;
int value = 5; int *ptr = &value; //변수값의 주소로 ptr 초기화
ptr은 값으로 value 변수 값의 주소를 가지고 있다. 그러므로 ptr은 value 변수를 가르키는 값이라고 할 수 있다.
#include <iostream>
int main()
{
int value = 5;
int *ptr = &value; // 변수 값의 주소로 ptr 초기화
std::cout << &value << '\\\\n'; // value 변수의 주소 출력
std::cout << ptr << '\\\\n'; // ptr 변수 값 출력
return 0;
}
// 0012FF7C // 0012FF7C
포인터 변수의 자료형은 가리키는 변수의 자료형과 같아야 한다.
int iValue = 5;
double dValue = 7.0;
int *iPtr = &iValue; // ok
double *dPtr = &dValue; // ok
iPtr = &dValue; // wrong -- int 포인터는 double 변수의 주소를 가리킬 수 없다.
dPtr = &iValue; // wrong -- double 포인터는 int 변수의 주소를 가리킬 수 없다.
다음 사항도 올바르지 않다.
int *ptr = 5;
포인터가 주소만 보유할 수 있고 정수 리터럴 5에는 메모리 주소가 없기 때문이다. 위 코드를 시도하면 컴파일러는 정수를 정수 포인터로 변환할 수 없으므로 오류가 발생한다.
C++에서는 포인터에 리터럴 메모리 주소를 직접 할당할 수 없다.
double *dPtr = 0x0012FF7C; // not okay (정수 리터럴을 할당하는 것으로 취급된다.)
주소 연산자 &는 피연산자의 주소를 리터럴로 반환하지 않는다. 대신 피연산자의 주소가 들어있는 포인터를 반환한다.
포인터는 여러 가지 경우에서 유용하다.
배열은 포인터를 사용하여 구현된다. 포인터는 배열을 반복할 때 사용할 수 있다. (배열 인덱스 대신 사용 가능) C++에서 동적으로 메모리를 할당할 수 있는 유일한 방법이다. (가장 흔한 사용 사례) 데이터를 복사하지 않고도 많은 양의 데이터를 함수에 전달할 수 있다. 함수를 매개 변수로 다른 함수에 전달하는 데 사용할 수 있다. 상속을 다룰 때 다형성을 달성하기 위해 사용한다. 하나의 구조체/클래스 포인터를 다른 구조체/클래스에 두어 체인을 형성하는 데 사용할 수 있다. 이는 연결리스트 및 트리와 같은 고급 자료구조에서 유용하다.
포인터는 내가 컴퓨터의 메모리에 보다 직접적으로 접근해서 이를 제어할 수 잇도록 해주는 도구. 비유하자면 기다란 집게이다.
변수에 입력된 값들은 메모리의 어딘가에 저장된다. 한정된 공간 안아세 변수나 함수들의 값들이 필요에따라 쓰이고 치워지고 하면서 프로그램이 돌아간다 프로그램을 짜다 보면 어느 변수에 지정한 값을 다른 여러곳에 써야 할 때가 있다.
c에서의 어느 함수에 '변수가 인자로 주어질 때는그 값이 복사되어서 , 즉 베껴 적어져서 넘어가게 된다. 복사가 된다는건 메모리의 값이 어딘가의 그 크기만큼 중복된 값이 차지한다. 그렇게 메모리를 낭비하지 않고 페이지 번호만 적어서 보내줄 수 있도록 하는게 포인터 이다.
메모리의 모든 칸에는 각각의 주소가 있다. 위치를 가르킨다는 말은 충분하지 않다. 시작하는 페이지와 줄을 줬으면 어디서 끝나는지도 알아야한다. 변수에 쓰이는 메모리는 어떤 자료형이냐에 따라 크기가 다르다. 정수는 1이든 100이든 천만자리수든 4바이트(32비트)를 차지한다. double도 1.0이란 값에도 8바이트를 차지한다 컴퓨터의 데이터는 수많은 0과 1, 즉 On, OFF로 나뉜다. 메모리의 칸 하나하나가 ON, OFF가 되어 2진수를 만든다
int num = 1;
int y = 100;
int* p1 = #
printf("p1 %d \\n", *p1); //일때는 1값이 나오고
p1++ //이렇게 포인터에 정수값을 더하면 자로형의 크기 곱하기 그 값만큼
//오른쪽으로 메모리의 값이 이동하게 된다.
//그러면 y값이 나와야 하지 않겠느냐 라고 생각하겠지만
//전혀 다른 값이 나와버린다
p1-- //다시 포인터의 값을 --해주면 원래대로 돌아온다.
int number[] = {1, 2, 3, 4, 5, 6, 7}
int* p2 = &numbers[0];
printf("p2 %d \\n", *p2); //일때는 배열의 1번째 즉 1의 값이 나온다.
p2++; //포인터 값을 증가시키면
printf("p2 %d \\n", *p2); //일때는 배열의 2번째 즉 2의 값이 나온다.
포인터는 이런식으로 배열과 연계되어서 사용될 수 있다.