주의) 이건 초보자 강좌가 아닙니다. C / C++의 함수 부분까지 이해한 사람이 읽기를 추천드립니다.
안녕 개붕이들아
오늘은 C++ 기초중에 가장 ㅈ같은걸로 유명한걸 알아보자 ㅎㅎ
(참고로 C에서도 같은 원리이기 때문에 포인터가 어려우면 읽어보는걸 추천해)
바로 포인터야.
영어로는 Pointer 라고 하는데
사전에 있는것처럼 무언가를 가리키는걸 뜻해.
근데 뭘 가리키는걸까..?
바로 변수의 주소야.
주소가 뭔 소리냐고?
이 변수는 메모리 (RAM) 라는 공간에 저장돼.
이 메모리 공간에는 각각 번호가 붙어있고,
이 번호가 바로 변수의 주소값이야.
사진으로 쉽게 설명해보자.
이게 우리의 램 공간이야.
여기에 int age = 34;
라는 명령어가 실행되면 무슨 일이 일어날까?
컴퓨터는 여기서, 자동으로 램에 빈 공간을 찾아.
그 다음에 그 빈 공간에다가 34라는 값을 저장하는 거지.
봐바!
우리의 똑똑한 친구 컴퓨터가 0x01 ~ 0x04에 34라는 값을 저장했어!
age = 53; 같은 명령을 실행시켜주면 저 34라는 값이 53이라는 값으로 바뀌는거야!
(여기서 age 변수가 메모리 공간을 4개나 차지한 이유는, int 자료형의 크기가 4바이트여서 그래.)
그럼 포인터는 뭘까?
포인터 변수는 바로 주소값을 저장할 수 있는 변수야.
일단 예시로 한번 알아보자.
int* pointer = &age;
일반적인 변수 선언같았는데, 자료형 뒤에 별이 붙어있지?
이렇게 별을 자료형 뒤에 붙이고 변수 이름을 적어주면 포인터 변수가 생성돼.
즉,
가리키고_싶은_자료형* 변수이름;
형식이야.
그럼 이 변수에 넣고있는 값인 &age는 뭘까?
&는 레퍼런스 라고 불러.
사전에서 말하는 것 처럼, 참조라는 뜻이야.
근데 참조한다는게 뭔 소리냐고?
정말 간단해.
레퍼런스(&) 기호를 변수 이름 앞에 붙이면 그 변수의 주소값을 알려주는거야.
예를 들어서 std::cout << &age << std::endl; 이라는 명령어를 실행하면,
age의 주소값인 0x01 이 출력되겠지.
std::cout << age << std::endl; 을 했을 때 34라는 age 변수에 저장된 값이 출력되는거랑은 다르게 출력되는게 보이지..?
그럼 이 포인터 변수는 메모리에 어떻게 저장되는걸까?
int *pointer = &age; 를 실행 했을때의 메모리 상태를 한번 보자.
봐바!!
우리의 메모리 공간에 새로운 변수가 생겼어.
0x05 ~ 0x08 위치에 새로운 값이 들어갔네!
포인터 변수는 바로 특정 변수의 주소값을 저장하고 있는 변수라는거지.
그럼 이 포인터를 어따가 쓰는걸까?
한번 응용해볼게.
int age = 65;
int* p = &age;
std::cout << p << std::endl;
std::cout << *p << std::endl;
어라? 마지막 std::cout 명령어에서 출력하는 변수가 이상하지 않아?
포인터 변수 이름 앞에 * 을 붙여놨잖아?!
일단 출력해보자.
????
std::cout << p << std::endl; 에서는 012FFB84 라는 값이 출력되고,
std::cout << *p << std::endl; 에서는 65라는 값이 출력됐네??
아하, 즉 포인터 변수인 p를 그대로 출력하면 포인터 변수가 가리키고 있는 주소가 출력되고,
포인터 변수인 p 앞에 별 (*) 을 붙인 상태로 출력하면 포인터 변수가 가리키고 있는 주소에 있는 변수의 값이 나오는구나!
그럼 실험을 조금 해보자!
int age = 65;
int* p = &age;
std::cout << "age : " << age << std::endl;
std::cout << "p : " << *p << std::endl;
age = 34;
std::cout << "age : " << age << std::endl;
std::cout << "p : " << *p << std::endl;
처음 age 변수에 65라는 값을 넣어주고,
age 와 *p 의 값을 각각 출력해준 다음,
age 변수에 34라는 값을 넣어주고,
다시 age 와 *p 의 값을 출력하는 코드야.
실행해보면...
우와!
age 의 값이 변함과 동시에 *p 의 값도 변했어!
왜냐고? p 는 포인터 변수고, 이 p는 age의 위치를 가리키고 있거든,
즉 age 의 값이 아닌 위치를 가리키고 있기 때문에, age가 변하면 *p 의 값도 변하는거야!
그럼 또 다른 실험을 해보자!
int age = 65;
int* p = &age;
std::cout << "age : " << age << std::endl;
std::cout << "p : " << *p << std::endl;
*p = 34;
std::cout << "age : " << age << std::endl;
std::cout << "p : " << *p << std::endl;
이렇게 하면 어떻게 될까??
이번에는 age 의 값을 바꾼게 아니라, *p 의 값을 바꿔봤어,
한번 보자.
오!! 이번에도 값이 변했어!
여기서 알 수 있는건 바로,
*p = 34; 는 즉, p가 가리키고 있는 메모리 주소에 있는 값을 바꾸는거지!
그러기 때문에 age 랑 *p 랑 같은 값이 나오는거고!
근데 이걸 어디에 써먹냐고?
엄청 좋은 예시로 함수가 있어.
주의) 이 예시는 조금 어려우니 이해가 안되면 그냥 건너뛰고 그 밑에 있는 예시를 읽어보세요.
예를 들어서 "23:37:54" 라는 문자열을 시간, 분, 초로 잘라서 변수 3개에 넣는 함수를 만들어보자.
void cutTime(std::string time, int* hour, int* minute, int* second) {
*hour = std::stoi(time.substr(0, 2));
*minute = std::stoi(time.substr(3, 2));
*second = std::stoi(time.substr(6, 2));
}
어라 오류뜬다고?
당연하지! std::stoi 함수는 iostream 에 없거든!
#include <string> 을 #include <iostream> 아래에 적어주자!
여기서 알아갈게 조금 있는데,
time.substr() 은 std::string 변수에 기본적으로 있는 기능이야.
.substr(위치, 크기);
형식으로 사용하고, 문자열의 위치 위치에 크기 만큼 문자열을 잘라내는 기능을 해.
그래서 substr(0, 2) 해준거지 (0위치에 2길이의 문자열을 잘라서 return)
어쨌든, 이걸 실행해보자.
int main(int argc, char* argv[]) {
int hour;
int minute;
int second;
cutTime("23:37:54", &hour, &minute, &second);
std::cout << hour << std::endl;
std::cout << minute << std::endl;
std::cout << second << std::endl;
return 0;
}
함수를 위에 선언해줬으니, 저렇게 main 문에 적어주면 실행되겠지?
각 변수들에 무슨 값이 들어갔는지도 알아야하니깐, 마지막에 저렇게 출력문도 적어보자.
이 상태로 실행하면?!
오오 23:37:54 라는 문자열이 23, 37, 54 라는 각각의 숫자로 나뉘어서 hour, minute, second 변수에 각각 들어갔어!
근데 뭔가 예시가 어려우니 좀 더 쉬운 예시를 들고와볼게.
이번에는 함수에 값이 들어가있는 int 변수를 넣으면 그 변수가 두배가 되도록 해보고 싶어.
해보자.
void doubleInt(int* num) {
*num = *num * 2;
}
이제 main 문에
int a = 34;
doubleInt(&a);
std::cout << a << std::endl;
넣고 실행해보면...
34의 두배인 68이 변수 a에 저장되어서 나왔어!
어떤식으로 작동된건지 뜯어보자!
int a = 34; <- 여기서 a 라는 변수를 만들고 34라는 값을 넣어줬어.
doubleInt(&a); <- 이제 doubleInt 라는 함수를 실행 해주는거야, doubleInt 함수는 int 형 포인터 변수를 필요로 하니깐 a의 주소값을 보내줬어.
void doubleInt(int* num) { <- doubleNum 함수의 포인터 변수인 num 에 a의 주소값이 도착했어!
*num = *num * 2; <- 이 주소값이 가리키고 있는 변수(a) 의 값을 2 곱해서 넣어줘.
}
std::cout << a << std::endl; <- 이제 출력이야!
어때..? 이해 좀 됐어..?
나도 포인터라는 개념이 이해도 잘 안되고 어따 써먹는지도 영 모르겠어서 익히기가 엄청 어려웠었는데,
이거라도 읽고 좀 이해했으면 좋겠다.
궁금한 점이나 어려운점, 수정 바라는 부분이나 오류 있는 부분은 댓글로 달아줘!
읽어줘서 고마워
일단궁금
메모리할당 써보쉴?
쿄코
동적할당?
Weakness
Import numpy as sex
고부추랄
자기전에 읽어야게땅 담에 collection 풀이점