인프런 커뮤니티 질문&답변
(9:30)검토 부탁드립니다. 보기 편하게 만들었어요.
해결된 질문
작성
·
235
2
*150% 확대해서 보면 보기 편합니다.
1. 문제 발생
// 1번 주소 값
void doSomething(int studnet_score[20])
{
cout << (int)&studnet_score << endl; //@1
}
// 2번 주소 값
int main()
{
int student_score[20] = { 1, 2, 3, 4, 5 };
cout << (int)&studnet_score << endl; // @2
doSomething(studnet_score);
}
@1과 @2의 주소 값이 다르다!!
2. 문제 원인!
void doSomething(int studnet_score[20])
{
cout << (int)&studnet_score << endl; --------------------
cout << studnet_score[0] << endl; | -> 포인터 변수들
cout << studnet_score[1] << endl; -----------------------
}
// void doSomething 파라미터 안에 있는 배열은 사실 배열이 아니다!
// 포인터 변수이다!
// 즉, { }안에 있는 studnet_score[0]들도 포인터 매개변수들이다!
3. 주소 값이 다른 이유!
// #1
int main()
{
int student_score[20] = { 1, 2, 3, 4, 5 }; // @1 : 난 선언과 동시에 주소값 있지롱~!
cout << (int)&studnet_score << endl;
doSomething(studnet_score); // @2 : 나도 주소 값 가지고 싶어!!
}
// #2
int main()
{
int student_score[20] = { 1, 2, 3, 4, 5 }; // @1 : 내꺼 줄게 같이 쓰자!
cout << (int)&studnet_score << endl;
doSomething(studnet_score); // @2 : 고마워!!
}
// #3
void doSomething(int studnet_score[20]) // @3 : 주소 받을 자리, 새로 만들어야겠네!
// (@1번의 주소를 받기 위한 새로운 주소를 만듬)
{
cout << (int)&studnet_score << endl; // @3 : 내가 그 새로운 주소의 주인공이야!
}
int main()
{
int student_score[20] = { 1, 2, 3, 4, 5 };
cout << (int)&studnet_score << endl;
doSomething(studnet_score); // @2 : void야! @1번한테 받은 주소값 보내줄게! ↑
}
// #4
void doSomething(int studnet_score[20])
{
cout << (int)&studnet_score << endl; // @3 : 나는 @1번의 주소를 가져오기 위한 주소값이야!
cout << (int)&studnet_score[0] << endl; // @4 : 야!! @3번! 너 나랑 주소값이 다르잖아!
}
// #5
void doSomething(int studnet_score[20])
{
cout << (int)&studnet_score << endl;
cout << (int)&studnet_score[0] << endl; // @4 : @1의 첫 번쨰 주소값하고 같구나!
}
int main()
{
int student_score[20] = { 1, 2, 3, 4, 5 };
cout << (int)&studnet_score << endl; // @1 : 반갑다, @4번! 나랑 같은 주소값이야!
cout << (int)&studnet_score[0] << endl; // @5 : 어서와, @4번. 나도 너랑 같아.
doSomething(studnet_score);
}
4. 정리
main의 배열 student_score[0](첫 번째) 주소 값 복사 ->
void의 파라미터는 주소값을 받기 위한 주소 만듬 ->
void의 포인터 배열은 [0](첫 번째)부터 main의 student_score과 같은 주소지를 갖음
의문점) <2 .문제 원인>에서 void 안에 있는 변수는 모두 포인터 변수라고 하셨는데, 그러면 아치피 main에서 주소값 받기 위해서 만든 새로운 주소값으로 쭉쭉 나가면 될건데...
어째서 [0](첫 번째)부터는 main 배열[0](첫 번째)와 다시 주소가 같게 한 걸까요...? 궁금합니다..
답변 4
5
질문자님께서 doSomething 함수 안에서의 (int)&studnet_score[0] 와 main 함수 안에서의 (int)&studnet_score[0] 값이 왜 같은지에 대해 의문점을 가지고 계시다고 이해했는데 맞을까요?
- 우선 정정해드리고 싶은게 <2. 문제 원인> 부분에서 "즉, { }안에 있는 studnet_score[0]들도 포인터 매개변수들이다!" 는 사실이 아닙니다. student_score[0] 는 포인터가 아닌 첫번째 원소값을 나타내는 정수입니다. student_score만 포인터입니다.
- 또한 포인터는 메모리 주소값을 담을 수 있는 타입의 변수를 의미합니다. 포인터와 주소를 살짝 구분해서 생각해주시는 것을 추천드립니다.
🌼 아래부턴 질문자님 코드의 실행 과정에 대한 설명입니다.
main 내에서의 doSomething(student_score);
- 배열 같이 생겼지만 사실은 포인터인 doSomething 의 매개변수인 student_score 에다가 main 함수에 있는 student_score 값(즉, student_score 배열의 첫번째 원소 주소값)을 대입합니다. (main 함수의 student_score 와 doSomething 의 student_score 는 이름은 동일하지만 사실 메모리가 다른 전혀 다른 변수입니다.덧붙여서 doSomething 의 student_score 는 doSomething의 { } 중괄호 안에서만 수명을 가지는 변수이고, main 함수의 student_score 와 범위가 다르기 때문에 이렇게 동일한 이름의 매개 변수를 가질 수 있는 것입니다.)
- doSomething의 stduent_score 매개변수는 포인터이기 때문에 주소를 저장할 수 있습니다. 따라서 main의 sutdent_score 배열의 주소를 받을 수 있었습니다.
- student_score = student_score 이렇게 넘긴 파라미터가 doSomething의 매개변수인 포인터에 복사되는 과정이 일어납니다. 전자는 doSomething의 매개변수 포인터고, 후자는 main 함수 안에있는 그 배열입니다.
- 배열 매개변수가 사실 배열이 아닌 포인터인 이유는 https://www.inflearn.com/questions/100022 다른 질문에서 제가 자세히 답변을 드린적이 있습니다. 참고 부탁드립니다.
doSomething 내에서의 (int)&studnet_score 와 main 함수 내에서의 (int)&studnet_score 값이 다른 이유
&를 변수 앞에 붙이면 그 변수가 위치한 주소값을 리턴할 수 있게 됩니다. 예를들어 &a 이면 a 변수 값이 위치한 메모리의 주소입니다. (혹시 모르신다면 포인터부분에서 자세히 배우실거에요!) 앞에서 말씀 드렸듯이 main 함수의 student_score 와 doSomething 의 student_score 는 이름은 동일하지만 사실 메모리가 다른 별개의 변수이기 때문에 두 변수의 주소가 다른 것입니다. 두 변수는 서로 다른 별개의 변수이기 때문에 주소가 다를테니 &student_score != &student_score 이겠지만 doSomething 의 student_score 가 main 함수의 student_score 값을 앞에서 복사 받았으니 student_score == student_score 두 값 자체는 같습니다. 덧붙여서 student_score 이 자체로 주소값을 담는 포인터기 때문에 &student_score 은 포인터 변수의 주소!가 되겠네요.
doSomething 내에서의 (int)&studnet_score[0] 와 main 함수 내에서의 (int)&studnet_score[0] 값이 같은 이유
student_score 값은 배열의 첫번째 원소 주소이므로 곧 &student_score[0] 와도 같게 됩니다. student_score 값에는 &student_score[0] 가 들어있는 셈이에요. &student_score[0] 은 &(student_score[0]) 라고 생각하시면 되는데요, doSomething의 student_score 변수에는 main 함수의 student_score 배열의 주소값을 받아 저장한 상태이므로 doSomething은 이 주소를 통해 main 함수 내에서의 그 student_score 배열의 원소들에 접근할 수 있게 됩니다. 이름이 같아서 헷갈리는데 만약 doSomething 의 매개변수 이름이 student_score 가 아닌 Array 였다고 가정해보면, Array[2]와 student_score[2]는 완전히 동일한 메모리를 가리키는 것이 되요. 사본이 아니구요! doSomething 의 매개변수에서 main의 student_score 배열의 주소를 넘겨받아서 그 동일한 배열의 원소들에 Array[2], Array[3] 이런식으로 접근할 수 있게 되었다고 생각하시면 됩니다! 그래서 doSomething에서의 student_score[0]와 main에서의 student_score[0]은 완전히 동일한 메모리이기 때문에 &(student_score[0]) 이 둘의 주소가 같은 것이에요!
덧붙여서 같은 배열 내의 원소들은 메모리가 다 연속적으로 따닥따닥 붙어서 자리잡습니다. 그래서 배열의 첫번째 원소가 어디있는지만 알아도 그 배열의 모든 원소들에 접근할 수 있게 됩니다. 예를 들어 int 배열이라면 메모리 한칸당 1byte가 저장되니까, 배열의 이름으로 첫번째 원소 Array[0]로 찾아가서 4 x 2 = 8 칸만 더 가면 Array[2]에 바로 접근할 수 있어요. 그래서 doSomething에서의 student_score[0]가 포인터가 아닌, 진짜 그 main에서 넘겨받은 그 student_score 배열의 첫번재 원소값을 가져올 수 있는 이유입니다. student_score 배열의 주소를 넘겨 받았기 때문에 가능했던 것이에요!
제가 질문자님 의문점을 정확히 이해한게 맞는지 잘 모르겠어서 ㅜㅜ 답변을 좀 여러가지 장황하게 설명하는 식으로 드려보았습니다. 잘 해결되지 않으셨다면 또 답글 주세요!
3
Array[0], Array[1] ..이런 것들은 배열에 속한 '원소'들이라고 불러주시면 됩니다. 정확히 말하자면 Array 로 student_score 배열의 첫번째 두번째 원소를 가지고 온 것이에요
student_score 배열의 주소(정확히는 첫번째 원소의 주소)를 포인터인 Array 에게 넘겼으니 Array 는 이제 student_score 배열의 첫번째 원소의 주소를 아니까 그 주소를 통해 바로 그 student_score 배열에 찾아갈 수 있겠죠
따라서 사실 main 의 그 student_score 배열 메모리의 진짜 이름은 student_score긴 하지만 Array도 student_score의 주소를 알게 되었기 때문에 Array[2] 이런식으로 Array로도 직접 그 배열 메모리에 찾아가서 두번째 원소를 가져올 수 있게 된 것이에요. 배열 원소들은 메모리 내부에서 다 기차처럼 한줄로 연결되어 붙어서 자리잡고 있기 때문에 첫번째 원소 주소만 알아도 다른 원소들에도 다 찾아갈 수 있거든요 2칸 (int 배열이라면 정확히는 4 x 2 = 8칸) 만 더 가면 student_score[2] 에 찾아갈 수 있는거죠! Array 가 student_score 배열의 집 주소를 받아서 Array[2]로 student_score[2] 에 찾아갈 수 있게 된거라고 이해해주시면 될 것 같아요. Array[2]와 student_score[2]는 동일한 메모리를 메모리입니다.
이런식으로 포인터를 사용하여 주소를 통해 그 주소에 있는 메모리를 직접 찾아가는 식의 작업을 앞으로 많이 하게 되실거에요
원래 포인터가 C언어에서 가장 어렵다고 합니다. 근데 포인터를 제대로 이해해놔야 그 뒤에가 수월하실거에요! 포인터 사용 빈도가 정말 정말 많거든요. 아무튼 포인터 관련해서 궁금하신 점 있으면 언제든지 질문 주세요. 뒷 강의부터 포인터 배우실텐데 그때 교수님께서 설명 자세히 해주실거에요~!
0
0
포인터를 아직 모르고 있기에 해당 챕터 영상이 이해가 잘 가지 못했어요.
지금은 이해했습니다! joy님의 답변은 길이길이 박제될 답변이십니다!
*doSomething의 student_score을 Array로 표현한다고 가정 하,
Array는 포인터이고, 포인터는 메모리의 주소값을 받을 수 있는 변수. 따라서 변수 선언과 동시에 주소가 새로 생김.
Array는 main의 student_score[] 첫 번째 주소 값을 받은 상태 ( 내부적으로 Array = student_score[] )
그래서 doSomething의 Array[0,1,2, ..]부터는 main의 student_score[0,1,2, ..] 동일한 배열 주소 출력됨
ex).
main의 student_score[] → Array → Array[0,1,2, ...]
(배열 메모리) → 배열의 메모리를 담고 있는 포인터 → 동일한 원소들의 주소를 연결시켜줌
**그렇다고 Array[0,1,2, ..]가 그때그때 원소마다 student_score[0,1,2, ..]의 메모리를 복사해 오는 것이 아니라, 배열은 연속적으로 붙어 나열되 있기에 다음 주소를 그대로 따라가서 출력 해줌.
<추가 정보>
배열의 첫 번째 원소의 주소만 알 수 있다면, 해당 배열의 모든 원소들의 주소를 알 수 있음.
왜냐하면, 배열의 원소들은 연속적으로 붙어 자리잡고 있기 때문!
P.S. Array가 포인터이고, student_score의 첫 번째 원소 메모리를 담고 있는 건 알겠어요. 그리고 [0,1,2, ...]는 그 배열의 주소를 화면에 보여주는 것이고요. ,즉, Array[0]은 student_score[0]의 분신!
다만, Array[0,1,2 ...] 원소들은 뭐라고 불러야 할까요..? Array[0], Array[1] .. 이런 것들이요. 배열이라고 불러야 하나요?





