210914, C언어 입문 - day 9-1

Min Hyeok·2021년 9월 14일
0

C언어 개념 익히기

목록 보기
9/19

안녕. 13장 공부하는데 긴 긴 시간을 소비했다..

왜냐고..?

그 및친 포인터를 공부하고 왔기 때문이다. 1학년 때 c언어 기초 강의 들을때 포인터부터 어느정도 손 놨던 기억이 있기에, 같은 실수를 반복하지 않으려 나는 애썼따. ㄹㅇ 그때는 뇌절 씨게 때렸었는데.

뭐 여튼 그렇다. 오늘 복습은 좀 길 것 같은 느낌이 든다. 포인터는 확실히 이해하고 가고 싶거덩!

그리고 다음주면 찐전역임. 민간인 GO ㄷㄷㄷㄷㄷ

13장, 포인터

드디어 포인터. 총 6개의 소단원으로 나뉜다. 차근차근 스택쌓듯 이해해보자.

※ 우선 말하지만, 내용이 뒤지게 긴 관계로, 이틀에 나눠서 복습할 예정이다.

내가 C언어 source file을 만들 때, 변수들을 뭐 여러개 설정해왔다. 이런 변수들은, 컴파일 작업이 끝나고 low-level 언어인 기계어로 변경되면, 전부 다 메모리 주소로 바뀌어서 사용된다.

만약

int data;
data = 6;

이런 식으로 쓰면, data = 6이 메모리 주소로 바뀐다는 거겠지. 근데 만약 내가 data라는 변수가 위치한 메모리 주소를 알고 있다면, "data"라는 변수 이름이 중요할까? 아니다. 이딴거 몰라도 메모리 주소만 알고 있다면 찾아가서 값을 꺼내오면 된다. 이 메모리란 것은 운영 체제가 관리한다.

보통 우리의 경우엔 64bit의 윈도우를 쓰고있꼤찌? 여기선 하나만 알고 가자. 운영체제에 따라 데이터를 처리하는 기본 단위가 다르다. C언어에서는 INT형이 운영체제 비트수가 "일치"한다. 그럼 32BIT에서는 int형이 32BIT, 64BIT에서는 int형이 64BIT. 알간?

여기서 이 운영체제란 놈은 메모리 주소를 1바이트 단위로 관리한다. 여기서 이 메모리 주소를 우리가 지정하는 방식이 총 두가지가 있는데, 하나는 직접 주소 지정, 하나는 간접 주소 지정이다.

직접 주소 지정이 무어시냐. 말 그대로 "직접" 지정하는것. "100번지에 1231이라는 값을 2바이트 만큼의 크기로 저장한다" 이렇게 직접 지시해주는 것이지.

요런느낌. A가 직접 주소를 알려줌.

이 1231을 2진수로 바꿔주면 0000 0100 1100 1111.
이걸 두 바이트(한 바이트당 8bit)으로 째주면, 0000 0100 (4) / 1100 1111(207). 즉 100번지에 207, 101번지에 4가 저장된다. 왜 4가 100번지가 아니고 207이 100번지냐고? 리틀 엔디언이라는 바이트 정렬 때문에, 우리 생각이랑 반대로 정렬된다. 어렵죠? 그래도 알아는 두자.

..근데 굳이 이럴 필요 없이 처음부터 16진수로 저장해버리면 (앞의 1231은 0x04CF), 그냥 100번지에 0xCF, 101번지에 0x04가 저장된다. 바이트 계산이 쉬워지지.. 알아두자.

근데 뭐 어디서 본 것 같지 않니? "어떤 값"을 "어떤 주소"에 대입한다. 이거 변수랑 똑같아 보이는데..?

맞다. 변수라는 개념이랑 직접주소지정방식은 그냥 똑같따.
뭐 예로 들면,

short byeonsu; /** byeonsu가 어떠한 메모리 주소에 있다 치고**/
byeonsu = 0x04cf; /** 0x04cf값을 byeonsu가 위치한 메모리 주소에 갖다 넣어라!**/

이런 느낌.

근데, C언어에서 이 직접 주소 지정 방식을 쓰는게 어느정도 한계가 있는데, 지역 변수의 경우에 다른 함수에 있는 지역변수를 받아와서 쓸 수가 없다.
A() 함수에 x라는 변수를 설정하고, main함수에 x라는 변수를 설정 한다고 같은 변수로 쓸 수 있는게 아니다. 서로 아예 다른 변수라, main함수에서 x를 A()로 받아와서 써야지~~ 하고 쓸 수 있는게 아니란 거지. 이런 경우에 main함수에 위치한 x의 메모리 주소를 알고 있으면, A()함수에서도 같은 x를 쓸 수 있다. 이거란 말이죠.

이를 좀 편하게 해결하기 위한게~~ 간접 주소 지정 방식.

이건 말 그대로 "간접적"으로 주소를 알려준다는것이다. 위의 예를 간접주소지정으로 다시 쓰면, "100번지에 4바이트 크기의 '주소'가 저장되어 있다. 이 주소로 가서, 값 '1231'을 2바이트 크기로 대입하라"가 된다. 중간에 경유지가 하나 생겼다는게 차이점이랄까.

요런 느낌. (오른쪽에 "자"라고 한 애가 B다. 실수로 안적음 ㅋㅋ) A가 B를 통해 간접적으로 알려줬다. 중간에 B라는 매개체가 있다는게 차이점이죠? ㅋㅋ 32비트 운영체제를 기준으로 하면, 주소를 32비트(4바이트)로 저장하기 때문에 주소를 4바이트 크기로 고정해야한다. 알아둬라.

그러니까, 이 간접을 쉽게 말하면 A번지에 "사용할 메모리의 주소"를 저장한 값을 넣고, 이 A에 저장되어있는 주소로 이동하면 실제 사용할 데이터인 B가 있단거지. 이 간접주소지정을 쓰면, 만약 B가 108번지에 있다가 130번지로 이동하면, A에 저장된 메모리의 주소를 그냥 108에서 130으로 바꾸면 된다. simple하지.

지금까지가 포인터를 설명하기 위한 사전지식이다. 개기네 진짜.

자 드디어 대망의 포인터.

우선, 포인터는 앞서 언급한 간접 주소 지정 방식으로만 동작하는 "특별한 변수"를 선언하기 위해 추가로 제공하는 문법이다.

이걸 어떻게 나타내냐!

short *ptr

이렇게 나타낸다. "short"는 자료형, "*"는 포인터 변수임을 나타내는 기호 (개중요하다!), ptr은 변수 이름. 즉, 2바이트로 저장된 ptr 포인터 변수.

.. 라고 생각하면 틀린다.

여기서 작성된 short는 "ptr 변수에 저장된 주소에 저장될 값의 자료형"이다. 뭔 개소리냐고?

우선, 포인터 변수 자체는 무조건 크기가 4바이트로 고정된다. 이 포인터에 저장된 주소로 이동하면, 어떤 특정 값이 있겠지? 그 값의 자료형이 short란 거다. 알아두자. 개중요한 포인터니까.

프로그램은 실행할 때마다, 우리가 쓸 메모리 공간의 주소가 달라진다. 갑자기 뭔 개소리냐고? 그냥 적은대로 알아들어라 좀. 여튼 그렇다. 포인터가 가리키는 대상 주소를 어디에 직접 써서 프로그램을 돌리면, 안된다는 거다. 고라니라는 친구가 하루마다 다른 곳으로 옮겨가며 전국 순회를 도는데, 어느날 고라니가 부산에 있다고 들어서 그 다음날에 부산 찾아가는, 그런 짓은 하지 말자 이거지. 그래서, 그냥 주소를 직접 가서 찾는 것 보단 그 애가 어딨나~~ GPS를 붙여서 주소를 떼 온 다음에 가는게 낫다 이거지. 그걸 써보자.

short gorani; /** short형 변수인 gorani **/
short *jangso; /** jangso 라는 이름을 가진 포인터 변수 선언**/
jangso = &gorani; /** gorani라는 변수의 주소를 jangso 포인터 변수에 대입한다 **/
*jangso = 101; /** jangso가 가리키는 주소에 가서 값 101을 대입한다 **/

이렇게 적으면, 어떻게 될까? 우선, gorani라는 변수의 위치를 가져올 수 있게 된다. 정확한 위치의 주소 (몇번지인지..)는 몰라. 근데 여기있는건 맞아! 이런 느낌이지. 이 gorani 변수의 주소를 jangso에 저장한다. 그러면 이 jangso 포인터는 gorani를 가리키고 있다 이거지. 그리고 jangso가 가리키는 주소로 가서, 그 값으로 101을 대입한다. 앞서 간접 주소 지정 방식에서 설명한 중간 매개체가 "jangso"가 되는거고, 그 "jangso"에 저장된 주소를 따라가면 "gorani"변수가 있다는거다. 그리고 jangso가 가리키는 곳에 가서 101이라는 값을 대입하는거고. 뭔소린진 알겠는데 적어놓으니까 모르겠네 ㅁㅊ ㅋㅋ 여튼 그렇다. 누가 이 글 보겠냐 나말고. 내가 알면 되지 ㅋㅋ

그리고 ptr = x를 설정하는거랑 *ptr = x를 설정하는건 전혀 다른 의미다.

ptr = x; 는 "포인터에 저장된 주소를 변경"
*ptr=x; 는 "포인터에 저장된 주소에 위치한 데이터 값을 저장" 한다는 뜻임.
개떡같이 말해도 찰떡같이 이해하도록 하자.

그리고 이 포인터를 이용해서 다른 함수에서 선언한 변수를 써먹을 수 있다. 예를 보자.

#include <stdio.h>

void hamsu(short *pointer) {
    short soft = 0;
    soft = *pointer;
    *pointer = 1;
}

int main() {
    short gab = 3;
    hamsu(&gab);
}

이렇게 하면 된다. 알아서 해석하자.

오늘은 여기까지. 힘들다.. 백준으로 성취감 좀 얻어야겠다. 나머지 공부시간은.

여기까지!

0개의 댓글