C언어 문서화

(C언어) 10. 포인터_1

Mosu(정종인) 2016. 3. 28. 19:28
반응형

[포인터]


0. 동기부여


흔히 C언어에서 가장 중요하고 가장 어려운 단원이 바로 이 "포인터"라는 단원이라고 한다. 그리고 오래 전에 만들어졌던 C언어가 아직까지 쓰이는 이유 중 하나(어쩌면 유일한 이유)가 바로 이 포인터이다. 

포인터를 배우기 전 : 정해진 메모리 공간 내에서 비교적 규모가 작은 코딩을 한다면,

포인터를 배운 후    : 메모리 공간을 다루는 능력이 생겨서 비교적 규모가 큰 코딩을 할 수 있다.



1. 포인터란?

<1: 포인터란? : 포인터는 주소 값을 담고 있는 변수(또는 상수)이다.

<2: 포인터 변수란? : 주소 값의 저장을 위해 선언되는 변수를 가리켜 포인터 변수라 한다.

<3: 주소체계 : 주소값 하나가 표현하는 메모리 공간은 : 1Byte.


이 위에 메모리블럭 1개당 1Byte의 값들이 있다.

<4: 1바이트 안에는 비트단위로 8조각이 나있다. 위의 주소값들은 이 8조각을 모두 포함해서 일컫는 말이라고 보면 된다.


2. 포인터 변수 선언하기

<1: 주소값 얻기

포인터 변수에는 주소값이 들어가기 때문에 주소값을 어떻게 얻는지 알고, 그다음에 포인터 변수 선언하는 법을 알아야한다.

주소값을 얻기 위해 사용하는 연산자는 바로 & 이다. 어디서 많이 본것같다. 그렇다. AND의 역할을 담당하는 이항 연산자이다.

&는 이렇게 쓰인다 : 

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
int main(){
    int i;
    i=10;
 
    printf("%d\n", i);
    printf("%x\n"&i);
 
    return 0;
}
cs

결과값은 얼마가 나올까?


이것으로 &i는 i의 주소값을 나타낸다는 것을 알게 됬다.


여기서 한가지 의문이 들었다. "배열은 값이 나란히 저장되어있는데 주소값도 정말 나란히 있는 걸까? 아니면 혹시 배열의 주소값은 하나일까?"

역시 직접 해보는게 답이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
 
int main(){
    int arr_1[3]={0,1,2};
    char arr_2[3]="abc";
 
    printf("%d\n", arr_1[0]);
    printf("%d\n", arr_1[1]);
    printf("%d\n", arr_1[2]);
 
    printf("%s\n\n", arr_2);
 
    printf("%x\n", &arr_1[0]);
    printf("%x\n", &arr_1[1]);
    printf("%x\n", &arr_1[2]);
 
    printf("\n%x", &arr_2);
 
    printf("\n\n%x\n", &arr_2[0]);
    printf("%x\n", &arr_2[1]);
    printf("%x\n", &arr_2[2]);
}
cs

이걸 돌려보았다. 어떤 결과가 나왔을까?



주소값의 크기는 그 안에 있는 데이터에 상관 없이 4바이트로 표현된다. 따라서 배열에 들어있는 각각의 값들은 나란히 저장되어있다.

하지만 문자열의 경우는 1바이트에 문자 하나씩 들어가기 때문에 문자열의 경우도 각각의 값들이 나란히 저장되어있다는 것을 알 수 있다.



<2: 위에 정의에 따르면 주소 값이 저장되어 있는 변수가 포인터 변수라고 했다. 그러면 그것을 어떻게 선언하는지 알아야 써먹을 수 있다.

포인터 변수는 이렇게 선언한다. :

[데이터형] * [변수명];

(선언하는 건)참 쉽다.


<  여기서 잠깐! *의 명칭은? : Asterisk 와 Asterisk-operator. 전자는 그냥 *(별표)이고, 후자는 포인터 연산자를 일컫는다.                            >

<  많은 사람들이 포인터연산자를 "에스크리터"라고 읽는다. 영어로는 asteri-tor이라고 읽는다.(필자도 왜 에스크리터라고 읽는지 모른다)      >


int A;

int *A;

첫번째는 그냥 변수 A를 선언한 것이고, 

두번째는 주소값을 담을 수 있는 포인터 변수 A를 선언한 것이다.


<3: 그럼 초기화는 어떻게 하지?

(1) 선언과 동시에 초기화

int vari=3;

int *A = &vari;

(2) 그냥 초기화

int vari=3;

int *A;

A=&vari;

(3) 정리

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
int main(){
    int A=3;
    int *ptr;
 
    ptr=&A; //포인터변수 ptr에 A의 주소값 대입. => 현재의 ptr은 A의 주소값이 들어가있다.
    *ptr=A; //포인터변수 ptr이 가리키는 수=A => 현재의 ptr이 가리키는 값에는 3이 들어가있다.
    *ptr=&A;//포인터변수 ptr이 가리키는 수에 A의 주소값을 대입한다. =>현재 ptr이 가리키는 값에는 A의 주소값이 들어있다.
    printf("\n%x\n\n"*ptr);
}
cs



(A의 주소값을 출력한 것이다. 모양을 보아하니 5xxxxbcc이런식으로 되어있는데 왜이런지 아직은 잘 모르겠다.)





3. 포인터를 이용한 간단한 예제

<1: 포인터를 이용해서 두 값을 바꾸기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
 
int main(){
    int num1=3, num2=55;
    int *ptr1, *ptr2, *temp;
 
    ptr1=&num1;
    ptr2=&num2;
 
    temp=ptr1;
    ptr1=ptr2;
    ptr2=temp;
 
    printf("%d %d\n"*ptr1, *ptr2);
}
cs



결과 : 55 3


4. 널포인터

<1: 다음 두개의 표현은 같은 표현이다.

int *ptr=0;

int *ptr=NULL;

<2: 널포인터란?

널포인터는 포인터 변수를 0으로 초기화 한 것이다.(여기서 0은 0번지, 즉 NULL을 뜻한다.)

이것은 "이 포인터는 어떠한 주소도 가리키고 있지 않습니다." 라는 의미를 지니고 있다.

선언은 다음과 같이 한다 : 

[데이터형] *[변수명]=0;

혹은 [데이터형] *[변수명]=NULL;


<3: 쓰임

만약 널포인터가 가리키는 곳에 50을 저장했다고 가정하자.

잠깐, 널포인터는 아무 곳도 가리키지 않는데?

=>에러메세지 출력.(애초에 아무것도 가리키고 있지 않는데 값을 저장한다는 것은 말도 안되는 것이다.)

반응형