본문 바로가기
[ C언어 ]/- C언어 문법공부

C언어 16장_1(포인터, 메모리)

by MRG 2020. 5. 11.
728x90
반응형
728x90

▣ 안녕하세요 ^^ 
저번장에 함수 해보셨나요??
어렵죠? 많이 ㅠ.ㅠ
하지만 포기하지 마세요!!!
하실 수 있습니다.
제가 처 음장에서 이야기한 것처럼 코딩을 꼼꼼하게 읽는 훈련을 하시면서 
반복적으로 사고하고 코딩하시면 할 수 있습니다.
어려우신 게 있으시면 댓글 남겨주세요.



▣ 자 오늘은 C언어를 공부할 때 가장 어려워하는 포인터를 진행해보겠습니다.
포인터를 진행하면서 메모리에 대한 이야기도 하겠습니다.
이 부분은 할 이야기가 많아 챕터를 나누겠습니다.



▣ 제가 이걸 준비하면서 여러 책과 좋은 강사님들에 자료를 많이 읽어보고 
저도 다시 공부해보았습니다. 
가능하면 쉽게 설명하도록 하겠지만 
여러분들이 꼭 하셔야 할 건 꼼꼼하게 코딩을 읽는 훈련을 하셔야 한다는 겁니다.
그냥 보고 무작정 어렵다고 포기하시면 안 됩니다.
결국 코딩에 코드는 사람이 컴퓨터한테 우리에 언어로 
명령을 주기 위해서 만든 것 이기 때문에 
제가 첫 시간부터 이야기한 그 읽는 훈련을 하시면서 숙제도 열심히 하시면
충분히 할 수 있습니다. 
그러니 만약에 제가 이야기한 것이 기억이 안 난다면 
다시 앞 장을 복습하시면서 진행해주세요.
그럼 포인터를 시작하겠습니다.



▣ 포인터라는 건 무엇일까요?
위키백과사전에는 이렇게 나와있습니다.
포인터(pointer)는 프로그래밍 언어에서 다른 변수, 혹은 그 변수의 메모리 공간 주소를 가리키는 변수를 말한다. 포인터가 가리키는 값을 가져오는 것을 역참조라고 한다.
포인터는 어셈블리, C, C++, 파스칼 등 하위 레벨까지 제어할 수 있는 언어에서 주로 많이 쓰이며, 모듈라-2, 에이다와 같은 언어에서는 극히 제한적으로 사용되고, 자바, 에펠 등에서는 완전히 숨겨져 사용할 수 없다.
첫 번째 부류의 언어에서는 포인터를 메모리의 임의의 주소를 가리키도록 할 수 있으며 포인터의 연산도 가능하다.
일반적으로 포인터는 메모리 주소로 바꿀 수 있다. 포인터는 다른 변수나 함수를 가리키도록 사용된다.
라고 나와있는데요
여기서 중요한 포인트는 
포인터도 결국 주소에 변수라고 생각하시면 될 거 같습니다.

 

 

 

▣ 자 먼저 이렇게 코딩을 해보겠습니다.
그리고 하나하나 해석을 해 보록 하겠습니다.
처음에 변수를 만드는 건 우리가 잘 알고 있습니다.
그럼 두 번째 있는 건 무엇일까요?
네 바로 포인터를 선언하고 그 안에 number변수에 주소를 정의한 과정입니다.
일반 변수를 선언하고 정의하는 것과 동일하죠?



포인터 변수 앞에 있는 자료형을 해석하면 포인터 변수 안에 있는 number에 저장된 주소를 가진 메모리를 int형 변수로 취급하겠다고 생각하시면 되는데
이건 말이 너무 어려우니 쉽게 이야기하면 
int자료형으로 포인터 변수를 만드는데 
거기에 안에 있는 메모리에 형식을 int으로 저장하겠다고 생각해주세요.



그럼 *pList안에는 &number에 주소가 들어있겠죠?
제가 변수를 했을 때에도 scanf를 했을때에도 
&엔퍼센드 기호와 주소에 대한 설명은 계속 해왔습니다.
모르시는 분은 꼭 앞장을 복습하고 와주세요.



▣ 위에 말한 내용들을 확인하기 위해서 
저 위에 코드처럼 &number를 주소를 확인하고
pList포인터 변수에 주소를 확인해보면 
같은 주소 값이 나오게 됩니다.



* 기호는 포인터 선언뿐만 아니라
*pList를 이렇게 선언하면 
pList안에 들어 있는 주소로 찾아가 그 값을 가져온다고 생각하시면 될꺼같습니다.
그래서 *pList를 출력하면 number에 값이 나오게 됩니다.
디버깅해서 메모리로 직접 확인을 해보겠습니다.

 

 

▣ 자 먼저 &number에 주소와 pList를 검색해보면 이렇게 같은 메모리 주소를 가리키고 있는 걸 볼 수 있습니다.

 

 

▣ 또한 &pList 포인터 변수에 주소를 확인해보면 
그 안에 &number에 주소 값이 들어있는것도 확인할 수 있습니다.
왼쪽에서 반대로 하나하나 주소값이 적혀 있죠?
이건 나중에 다루도록 하고 이렇게 값이 들어있는 걸 확인했습니다.



▣ 여러분들도 직접 변수와 포인터 변수를 만들고
그 포인터 변수 안에 만든 변수에 주소를 넣고 
이렇게 직접 확인해보세요.
이건 직접 확인하지 않고 이해하지 않으면 다음에 배열로 포인터 변수를 다룰 때
전혀 이해하지 못합니다.
꼭 직접 해보세요.
이해가 안 되신다면 앞장에 변수 부분과 scanf 입출력 부분을 다시 공부하고 오세요.

 

 

 

▣ 자 이렇게 우리가 배열을 공부했을 때 배열에 이름이 주소라는 걸 알고 있습니다.
기준 주소 상대 주소 등을 연산해보고 직접 주소를 확인해보았습니다.
이 부분을 모르신다면 배열 부분을 다시 꼼꼼하게 공부해주세요.

 

▣ 아까와 조금 다르게 이번에는 배열을 포인터 주소로 지정해보겠습니다.
배열을 먼저 만들어주시고, 그다음에 포인터 변수 안에 aList를 넣어주세요.
그런데 배열 앞에 &기호가 왜 안 붙었을까요?
이유를 아시겠죠?? ㅎㅎ
배열 이름 자체가 주소를 의미하기 때문에 &필요하지 않습니다.
직접 확인해보세요.

 

 

▣ 다음에 반복문을 이용해서 
aList와 pList에 주소를 모두 다 확인해보겠습니다.

 

 

▣ 그럼 이렇게 배열과 포인터 변수에 주소가 같다라는 걸 확인했습니다.

 

 

 

 

▣ 그림으로 표현하는 이렇습니다.
주소를 100번지라고 예시를 든 겁니다.
아까 메모리를 확인한 것과 동일하게  pList포인터 변수에 주소를 넣게 되면
이렇게 그 안에 aList에 주소 값이 들어가게 됩니다.
그럼 *pList로 값을 확인해보면
그 주소에 값인 0번 인덱스에 값을 가져오게 됩니다.
쉽게 이야기하면
우리는 주소를 보고 집을 찾아가죠?
그것과 동일하게
* 기호는 포인터 변수가 가지고 있는 주소를 보고 물건을 찾으러 간다라고 생각하시면 될꺼같습니다.

 

 

▣ 그럼 값을 바꿀 수도 있겠죠?
* 기호를 사용해서 직접 값을 가져오기도 하지만
직접 메모리에 주소를 찾아가 값을 바꿀수도 있습니다.
직접 지정, 간접 지정이라는 말이 있는데 
이건 헷갈릴 수 있으니 그냥 안 쓰겠습니다.



▣ 그런데 제가 *(pList + 1) 이렇게 했죠?
왜 이렇게 했을까요?
먼저 *pList+1을 해보시면 어떻게 되는지 확인해주세요.



▣ 네 그럼 그 결괏값이 101이 나오게 됩니다.
연산자 우선순위를 생각하시면
*pList가 먼저 연산이 되겠죠?
100이라는 값을 찾아와서
+1을 하게 되면 101이 됩니다.



▣ 그렇다고 한다면 *(pList + 1)을 하게 되면
pList+1은 주소 값에 +1 이 되면 우리가 배열에서 배운 것처럼 
그 자료형 값만큼 +1이 됩니다.
int 4byte를 더해주면 다음 aList [1]에 주소를 가리키게 됩니다.



다시 말해 *(pList + 1)를 연산하게 되면 *(pList [0] + 1)이 되고
pList [1]에 값을 바꾸게 되면 aList [1]에 값을 찾아가 바꾸는 것이 되겠죠?
그래서 저렇게 연산을 해야 합니다.
이해가 되셨나요?



▣ 이건 제가 연산에 우선순위를 이야 할 때 너무 중요하다고 이야기했습니다.
이 부분이 이해가 가지 않으시면 연산자 부분을 다시 공부해주세요.
결국 컴퓨터는 연산을 하는 것이기 때문에 연산 우선순위를 알아야
해석이 가능합니다.
그래야 우리가 버그나 오류를 고칠 수 있겠죠?

 

 

▣ 아까처럼 메모리를 확인해보면 이렇게 포인터 주소에 주소 안에 aList에 주소가 넣어져 있고

 

 

▣ pList를 확인해보면 이렇게 같은 주소를 가리키고 있는걸 확인할 수 있습니다.

 

▣ 그림으로 보면 이렇게 가르키고 있고 
*기호는 그 주소를 찾아간다.
이렇게 생각하시면 될꺼같네요.



▣ 꼭 이 부분들은 다 직접 해보셔야 합니다.
그래야 이해가 가지 눈으로만 읽고 넘어가시면 나중에 포인터 변수를 활용할 때
코딩을 하지도 못하겠지만 읽지도 못합니다.
꼭 직접 위에 있는 예시들을 해보시고 
다르게 만들어서도 확인해주세요.



▣ 자 우리가 계속 메모리 메모리 이야기를 하고 있습니다.
하지만 모든 메모리가 같은 용도로 사용하지는 않겠죠?
그렇기 때문에 메모리 또한 영역이 나누어져 있습니다.
모두 다 메모리를 공유하면 정말 엉망이 되겠죠?
우리에 방처럼요 ㅎㅎ



▣ 메모리에 용도에 따라 나누는데 
스택(stack), 힙(heap), 데이터 영역(data section), 텍스트 영역(text section) 이렇게 크게 있습니다.
오늘은 간단하게 이야기할 건데요



▣ 스택(stack)은 자동 변수, 지역변수를 사용할 때 사용합니다.
그리고 임시 메모리적 성격을 가지는데 그건 { } 범위 안에서는 메모리를 생각하시면 될꺼같습니다.
크기가 작고 자동으로 이루어진 장점이 있습니다.



▣ 힙(heap)은 자유 메모리 영역입니다. 저 위에 있는 것 나머지라고 생각하시면 될꺼같습니다.
대향의 메모리가 필요할 때 메모리 크기를 미리 알 수 없을 때 사용합니다.



▣ 텍스트 영역(text section)은 소스 코그에서 기계어가 저장된 메모리 영역을 이야기합니다.
그리고 읽기 전용 메모리입니다. 



▣ 데이터 영역은 전역 변수, 정적 변수들을 사용하는 메모리 영역입니다. 
별도로 초기화하지 않아도 0으로 초기화되고 자동으로 관리를 해줍니다.



▣ 오늘은 메모리 영역을 이 정도까지 있다고 생각해주시고
계속 앞으로 우리가 코딩을 진행하면서 이야기하도록 하겠습니다.





▣ 자 오늘은 포인터와 메모리에 대해 배웠습니다.
아직 메모리를 관리하고 할당하는 부분도 안 했기 때문에
다음장에 이어서 포인터와 메모리를 공부하도록 하겠습니다.



제가 쉽게 한다고 했지만 그래도 어려운 부분이라 
꼭 중간중간 앞장에서 이해하지 못한 부분이 있으면 넘어가지 마시고 
다시 한번 복습하시면서 공부해주세요.
그리고 이 블로그로 공부하는 게 끝나면 안 됩니다.
꼭 다른 좋은 강사님들과 선생님들에 자료와 영상을 보고 같이 공부해주세요.
여러분들은 할 수 있습니다.
질문 있으시면 댓글 남겨주세요.
그럼 다음장에서 뵙겠습니다.



▣ 포기하지 마세요!!! 저도 했습니다!!! 파이팅!!!

728x90
반응형

댓글