이 게시글은
서울대학교 데이터사이언스대학원
조요한 교수님의
데이터사이언스 응용을 위한 컴퓨팅 강의를
학습을 위해 재구성하였습니다.
이번시간에는 c언어의 꽃이라고 할 수 있는
포인터에 대해서 배운 내용을 정리해보려한다
포인터는 c언어의 꽃이지만
강의 내용이 c++로 이루어지기에
c++과 함께 포인터 변수에 대한 내용을 정리하고
c++에만 있는 reference에 대해서도
배운 내용을 정리해보려한다
c나 c++에서는 변수가 선언이 될 때
그 변수를 위한 공간이 메모리에 생성이된다
메모리에 특정 변수를 위한 공간이 생성이되면
그 공간에 대한 정보인 주소가 존재할텐데
이 주소를 변수의 이름과 associate를 해서
변수 이름을 이용해 그 메모리 주소를
찾아갈 수 있도록 하는 것이다
이러한 것을 변수 선언이라고 부른다
위의 ppt에 있는 코드를 보면
x라는 변수가 선언되면
메모리의 stack에 x를 위한 공간이 할당되고
0x7ff7b...어쩌구 하는 메모리 주소가 존재한다
이 메모리 주소를 x라는 변수명과
associate하는 것이다
그렇게 되면 앞으로는
x라는 변수 명으로 해당 주소에
접근을 할 수가 있게 된다
int x = 5;에 대해서
앞에 &를 붙여
&x를 출력하면
변수명과 assoicate된 메모리주소를
반환한다
pointer 변수
많은 사람들이 포인터 변수에 대해서
포인터가 나오면 굉장히 어려워하는데
반드시 기억해야할건
포인터는 int나 char와 같은
그냥 평범한 변수라는 것이다
int가 숫자, char가 문자 한 개를 갖고있다면
포인터는 메모리의 주소를 들고있는 변수이고
그 크기는 8바이트이다
데이터타입 뒤에 *를 붙인
T*로 포인터변수를 정의하는데
이는 해당 포인터 변수가 갖고있는
메모리 주소로 접근했을 때
T 타입의 데이터가 들어있다는 뜻이다
int* 로 포인터변수를 정의하면
포인터 변수 안에 있는 주소로 가면
숫자 데이터가 들어있다는 소리이다
이렇게 포인터변수 안에 있는
메모리 주소로 접근해서
해당 주소에 있는 데이터를
사용하는 것을
dereference라고 부른다
그리고 이는 포인터변수의 이름 앞에 *를
붙인형태로 주로 사용한다
이게 무슨 말이냐하면
5가 저장된 메모리 주소를 담고있는
포인터변수 ptr이 있다고하면
포인터 변수 ptr에 담겨있는
메모리 주소에 접근해 5를 가져오는 것을
dereference라고 하고
*ptr이라고 하면 dereferencing을 해서
5가 나오게 된다
*ptr = 5를 출력하게 되는 것이다
그렇다면 위 ppt 코드에서
포인터 변수들이 각각
어떻게 출력되는지 보자
int x = 5;
가 정의되었고 밑에
int *ptr = &x;
라는 포인터 변수가 정의되었다
일반 변수 앞에 &를 붙이면
해당 변수가 저장된 메모리주소를 반환한다고
이전 ppt에서 말했으므로
포인터변수 ptr에는 int변수 x가 저장된
메모리 주소가 저장되어있게된다
cout << &x << endl;
에서 &x는 x가 들어있는 주솟값이므로
x가 들어있는 주솟값이 출력되게된다
cout << ptr << endl;
은 뭐가 출력이 될까?
위에서 강조했지만 포인터변수는
그냥 단순한 변수임을 기억해야한다
메모리 주소를 담는 단순한 변수이기때문에
아무것도 없이 그냥 ptr만 나온다면
이는 당연히 ptr이 담고있는
메모리 주솟값을 반환한다
그리고 이는 x의 주솟값이므로
&x와 동일한 값이 출력될 것이다
cout << &ptr << endl;
그렇다면 &ptr은 뭐가 출력이되게 될까?
차근차근 생각을 해보면 쉽다
앞에서 변수명 앞에 &가 붙으면
해당 변수가 저장된 메모리주소를 반환하다고 했다
그럼 &ptr은 ptr이라는 포인터변수가
저장된 메모리 주소를 가리킬 것이다
포인터변수도 단순한 변수이기때문에
포인터변수의 데이터를 저장하고있는
메모리 공간이 존재한다
이 주소를 찾으면된다
위 ppt에 보면 x의 메모리 주소를 담고있는
ptr변수가 stack의 위에 정의되어있다
이 메모리 주솟값을 반환할 것이다
cout << *ptr << endl;
마지막으로 이것은 무엇을 반환할까?
앞에서 말했듯
*ptr은 dereferencing이다
ptr변수에 저장된 메모리 주소에 접근해
그 데이터를 가져온다
따라서 *ptr은 당연히 5를 출력할 것이다
ptr앞에 *이 붙은 *ptr은
마치 변수의 이름처럼 사용할 수 있다
위 사진을 잘 보자
포인터변수 ptr은 7번방에 위치해있고
15라는 주솟값을 갖고있다
그렇다면 *ptr을 쓰게되면
ptr이 갖고있는 15번방에 접근해
15번방에 들어있는 50이라는
데이터를 반환하게 되는 것이다
*ptr을 15번방에 있는 50이라는
데이터의 이름처럼 취급하는 것이다
따라서
*ptr = *ptr + 5를 하게 된다면
*ptr은 50이라는 데이터의 변수명처럼
사용되므로
50에서 5를 더한 55가
15번방에 저장되게 되는 것이다
Dynamic Memory Allocation
동적 메모리 할당에 대해 알아보자
프로그램이 실행되는 runtime에
메모리를 할당하는 것을
dynamic memory allocation
한국어로는
동적 메모리 할당이라고 한다
메모리에는 대표적으로
Heap과 Stack이 있는데
Heap이 dynamic allocation을 할때
저장하는 부분으로
프로그래머가 작성할 수 있다
stack은 로컬변수같은 것들을
컴파일 할 때 컴파일러가
메모리를 할당하는 곳이다
그렇다면 코드상에서
어떻게 동적 메모리 할당을 하는지 알아보자
왼쪽이 c언어이고 오른쪽이 c++이다
c언어에서는 malloc을 통해서
heap에 동적으로 메모리를 할당해준다
만약 malloc이 제대로 작동을했다면
array 변수에는 메모리의 첫번째 주소가 출력되고
그렇지 않다면 NULL이 반환되게 된다
그런 다음 사용이 끝나면
free로 할당을 해제해준다
이 과정을 c++에서 해보자
c++에서는 header에 new를 선언해주고
malloc대신 new로 동적 할당을 해준다
array = new int[n] 으로 정의할 때
n은 size이다
그리고 delete[] array;
와 같은 방식으로
메모리 할당을 해제해준다
제대로 할당이 되지 않더라도 error를 띄우지않고
그냥 Null pointer를 반환하기 때문에
반드시 if문으로 nullptr 여부를 체크해줘야한다
할당 해제에 관한 부분인데
변수에 대한 사용이 끝났으면
반드시 delete를 통해
메모리할당 해제를 해주어야한다
해제를 해주지 않으면
계속 그 공간을 잡고있기때문에
memory leak 방지를 위해
메모리 공간을 해제해줘야
계속해서 재사용할 수 있다
class pointer에 관한 내용이다
어떤 class를 포인터 변수로 정의했을 때
class 내부 메소드에는 어떻게 접근할까?
위 ppt 코드 예시를 보면
vector<int>* myVector = new vector<int>();
와 같은 방식으로
빈 int vector object를 dynamic하게
myVector라는 변수명에 할당시켰다
vector는 하나의 object인데
이를 포인터변수로 정의하면
어떻게 사용할 수 있을까
방법은 크게 2가지가 있는데
1. *myVector
2. myVector
로 이용하는 방법이다
위에서 말했듯이
*myVector와 같은 방식으로쓰면
그 변수의 이름처럼 쓰이기 때문에
class object에 있는 메소드들을 바로 사용 가능하다
따라서 (*myVector)[0]과 같은 방식으로
vector의 첫번째 원소에
접근가능하다
또한 (*myVector)은 .(dot)으로
class의 메소드를 이용할 수 있다
두 번째는 myVector다음에 ->(화살표)로
접근하는 방식이다
myVector -> push_back(10);
이렇게 vector값에 element를 추가해줄 수 있다
첫 번째와 두 번째가 다른 점은
두 번째 방법으로 하면
[0]와 같이 index로 vector에 접근한다던가
++ 메소드는 쓰지못한다
포인터 변수를 dereferencing 할 때는
포인터변수의 타입이 매우 중요해진다
왜냐하면 메모리 주소로 가서 타입에 따라
몇 바이트를 가져올지가 중요해지기 때문이다
이게 무슨 소리인가하면
int pointer라고 하면
메모리 주소로 가서 4바이트만 읽을 것이다
string이라고 하면 시작주소부터를
string으로 취급할 것이다
특히 pointer 산술연산을 할 때
매우 중요해진다
intPtr + 2 라고 하면
int는 한 개에 4바이트이기때문에
2개를 더하면 8바이트를 더한 값을 반환한다
charPtr + 2라고 하면
char이 1바이트이기 때문에
2개를 더하면 2바이트를 건너뛴 위치를 반환한다
int *aPtr = new int(5);
로 heap에 4바이트의 int 공간에
5라는 값을 할당했다
이런 상황에서 다양하게 출력을 해보자
aPtr은 포인터변수가 담고있는 주솟값
즉, 5가 저장되어있는 값을 출력할 것이다
*aPtr은 당연히 주솟값이 담고있는
변수인 5를 출력할 것이다
&aPtr은 aPtr이라는 포인터변수가
저장된 주솟값을 출력할 것이다
'강의 > computer science' 카테고리의 다른 글
[ComputerScience] c++의 pointer와 reference 3편 (Call by Value, Call by Reference, Reference) (1) | 2024.09.30 |
---|---|
[ComputerScience] c++의 pointer와 reference 2편 (Dynamic Array, Static Array, Smart Pointers) (0) | 2024.09.30 |
[ComputerScience] c++의 map과 set (1) | 2024.09.23 |
[ComputerScience] c++와 list (0) | 2024.09.23 |
[ComputerScience] c++의 vector (1) | 2024.09.23 |