포인터 소개 (Introduction to pointer)
변수는 값을 보유하고 있는 메모리 조각의 이름이라는 것을 배웠다. 프로그램이 변수를 인스턴스화 할때 사용 가능한 메모리 주소가 변수에 자동으로 할당되고, 변수에 할당된 값은 이 메모리 주소에 저장된다.
int x;
CPU가 위 문장을 실행하면 RAM의 메모리 조각이 따로 설정된다. 예를 들어 변수 x에 메모리 위치 140이 할당되었다고 가정해보자. 프로그램에서 변수 x를 표현식 또는 명령문으로 접근할 때마다 값을 얻으려면 메모리 위치 140을 찾아야 한다.
변수의 좋은 점은 우리가 어떤 특정한 메모리 주소가 할당되는지 걱정할 필요가 없다는 것이다. 지정된 식별자로 변수를 참조하면 컴파일러에서 이 이름을 할당된 메모리 주소로 변환한다.
하지만 이 접근법에는 몇 가지 제한 사항이 있으며, 이에 대해서는 앞으로 배울 내용에서 살펴보겠다.
주소 연산자 (&) (The address-of operator (&))
주소 연산자 &를 사용하면 변수에 할당된 메모리 주소를 확인할 수 있다.
#include <iostream>
int main()
{
int x = 5;
std::cout << x << '\n'; // print the value of variable x
std::cout << &x << '\n'; // print the memory address of variable x
return 0;
}
// prints:
// 5
// 0027FEA0
역참조 연산자 (*) (The dereference operator (*))
변수의 주소를 얻는 것 자체로는 그다지 유용하지 않다.
역참조 연산자(*)를 사용하면 특정 주소에서 값에 접근할 수 있다.
#include <iostream>
int main()
{
int x = 5;
std::cout << x << '\n'; // print the value of variable x
std::cout << &x << '\n'; // print the memory address of variable x
std::cout << *&x << '\n'; /// print the value at the memory address of variable x
return 0;
}
// prints:
// 5
// 0027FEA0
// 5
포인터 (Pointer)
주소 연산자(&)와 역참조 연산자(*)와 함께 이제 포인터에 관해 이야기할 수 있다.
포인터는 어떠한 값을 저장하는 게 아닌 메모리 주소를 저장하는 변수다.
포인터(pointer)는 C++ 언어에서 가장 혼란스러운 부분 중 하나로 여겨지지만, 알고 보면 놀랍게도 간단한다.
간단하게 포인터에 대해서도 알아 보았으니 밑으로는 함수형과 구조체에서 간단하게 포인터를 사용하는 예제를 알아보자.
#include <iostream>
#include <cstddef>
void doSomething(double *ptr) // 메모리의 값이 복사됨
{
std::cout << "address of pointer varaibable in doSomething()" << &ptr << std::endl;
if (ptr != nullptr) {
// do something useful
std::cout << *ptr << std::endl;
}
else {
// do nothing with ptr
std::cout << "NULL ptr, do nothing" << std::endl;
}
}
int main()
{
double *ptr{ nullptr }; // modern c++ memoery1
doSomething(ptr);
doSomething(nullptr);
double d = 123.4;
doSomething(&d);
ptr = &d;
doSomething(ptr);
std::nullptr_t nptr;
// null pointer만 넣을 수 있음 혹시나 null pointer만 받아야하는 경우 사용하게 될 것 같음
std::cout << "address of pointer varaibable in main()" << &ptr << std::endl;
// 현재 여기서 사용하는 메모리 주소와 위의 주석처리 되어 있는 memory1의 메모리주소와 다름
// 복사되어서 사용하기 때문에 값은 같으나 엄연히 메모리 주소가 다르다.
return 0;
}
#include <iostream>
using namespace std;
//void printArray(int array[])
// array처럼 보이지만 내부적으로는 포인터로 동작
void printArray(int *array)
// array처럼 보이지만 내부적으로는 포인터로 동작
{
cout << sizeof(array) << endl;
cout << *array << endl;
*array = 100;
}
int main()
{
int array[5] = { 9, 7, 5, 3, 1 };
//cout << array[0] << " " << array[1] << endl;
//cout << array << endl;
//cout << &array[0] << endl;
//cout << *array << endl;
////char name[] = "jackjack";
////cout << *name << endl;
////
int *ptr = array;
//cout << &ptr << endl;
//cout << ptr << endl;
//cout << *ptr << endl;
cout << sizeof(array) << endl; // 20
cout << sizeof(ptr) << endl; // 20
printArray(array); // 8
cout << array[0] <<" "<< *array << endl;
// 함수 안에서 포인터 변수값을 변경해주면 함수 밖에서도 영향을 미침
return 0;
}
구조체와 함수를 활용한 예시
#include <iostream>
using namespace std;
struct MyStruct
{
int array[5] = { 9,7,5,3,1 };
};
void doSomething(MyStruct ms)
{
cout << sizeof(ms.array) << endl;
}
void pdoSomething(MyStruct *ms)
{
cout << sizeof((*ms).array) << endl;
}
int main()
{
MyStruct ms;
cout << ms.array[0] << endl;
cout << sizeof(ms.array[0]) << endl;
cout << sizeof(ms.array) << endl;
doSomething(ms);
pdoSomething(&ms);
return 0;
}
'c++(언어)' 카테고리의 다른 글
c++ 패키지 관리 vcpkg (0) | 2021.06.27 |
---|