본문 바로가기
C언어

C언어 기초 part 2-3. 포인터 (20.03.27. 내용 추가)

by algosketch 2020. 3. 3.
  • 포인터
  • NULL 포인터
  • 포인터 연산
  • 배열은 포인터다
  • 포인터로 배열 접근

 

1. 포인터

 포인터는 C와 C++ 언어가 갖는 특징이라고 할 수 있다. C에서는 포인터를 사용하기 때문에 컴퓨터에 대한 깊은 이해를 가능케 하고 더 빠른 프로그램을 작성할 수 있게 만든다. 대신 프로그래밍 자체에 더 오랜 시간이 걸릴 수 있고 에러가 발생할 가능성이 많다. (심지어 포인터를 사용하지 않는 언어에서도 포인터와 관련된 에러가 발생한다. null pointer exception 이 그 예이다.)

 포인터메모리상의 주소값이다. 변수를 선언하면 그 변수를 저장할 메모리를 할당한다. 그리고 C언어에서는 그 메모리 주소값을 포인터 변수에 저장할 수 있다. 포인터 변수도 변수이기 때문에 그에 대한 주소값 또한 새로운 포인터 변수에 저장할 수 있다. 이를 더블 포인터라고 부른다. 다중 포인터에 대한 이야기는 나중으로 미루고 오늘은 단일 포인터에 대해서만 이야기하겠다.

 포인터 변수의 크기는 운영체제에 따라 다르다. 32bit 운영체제를 사용하고 있다면 4byte(1byte == 8bit)이고 64bit 운영체제를 사용하고 있다면 8byte가 된다. -변수에 할당된 메모리의 크기를 알고 싶다면 sizeof("변수 이름")을 사용하여 확인할 수 있다.- 즉, 포인터 변수가 담고 있는 주소값의 내용이 int형이든 double형이든 char형이든 운영체제가 같다면 포인터 변수의 크기도 같다.

변수의 선언

 포인터 변수의 선언은 담고자하는 (주소값의 자료형) * (변수 이름) 과 같이 선언한다.

char * cptr;
int * iptr;

 

주소값 반환

 어떤 변수의 주소값을 얻으려면 변수이름 앞에 &(엠퍼센트)를 붙여준다. 글로 설명하기보단 코드를 보는 게 이해가 빠를 것이다.

int * ptr;
int val = 4;
ptr = &val;
printf("%p %p", ptr, &val);
/*
포인터 값을 출력할 때 사용하는 서식문자는 %p이다.
출력 예 : 0x7fffaf67a644 0x7fffaf67a644
*/

 

주소에 저장된 값 반환

 포인터 값에 저장된 값을 불러올 때는 *기호를 사용한다. &와 반대 개념이라고 생각하면 된다.

int * ptr;
int val = 4;
ptr = &val;
printf("%d %d", *ptr, *(&val));
// 출력 : 4 4

 

2. NULL 포인터

 포인터 변수에 아무것도 저장되지 않았을 경우에는 NULL 포인터가 저장된다. NULL의 사전적 의미는 '아무 가치 없는'(*네이버 사전)이라는 뜻이다. 즉, 아직 포인터 변수에 특정한 값을 넣지 않았을 때 NULL이 들어간다. 포인터는 굉장히 민감한 부분이고 실수하기 쉽기 때문에 당장 사용하는 것이 아니라면 명시적으로 NULL을 넣어주는 것이 좋다. 따라서 아래의 코드가 더 좋은 코드이다.

int * ptr = NULL;
int val = 4;
ptr = &val;

 추가로 NULL은 숫자 0과 같다. NULL을 입력하면 실제로는 0이 저장된다.

 

3. 포인터 연산

 포인터 변수를 대상으로도 ++나 -- 혹은 +3 과 같은 연산을 할 수 있다. 예를 들어 값이 1000번지인 포인터 변수 (int*)ptr이 있다고 가정하자. (ptr+1)의 값은 무엇이 될까? 정답은 1001번지... 가 아닌 1004번지이다. 포인터가 가리키는 값이 int형(4byte)이기 때문이다. 만약 char* 형 포인터에 +1을 한다면 1001번지가 된다. 같은 이유로 ptr+3 의 값은 1012번지가 된다.

 

4. 배열은 포인터다

 배열에 접근하기 위해서 arr[0], arr[1], arr[2] 와 같은 방법을 사용했다. 이러한 값들 또한 &arr[0]와 같이 주소값을 얻어낼 수 있다. 그 중에서도 배열의 이름인 arr는 &arr[0]와 동일한 값을 갖는다. (단, 포인터 연산에 대해서는 성질이 다를 수 있다.)

 

5. 포인터로 배열 접근

 arr와 &arr[0]의 값은 같다고 했다. 즉, *arr와 arr[0]의 값이 같다. 따라서 배열에 접근할 때 이런 방법도 가능하다. *(arr+0), *(arr+1), *(arr+2), ... 각각 arr[0], arr[1], arr[2]에 대응한다. *(arr)와 *(arr+0)은 같은 코드지만 *(arr+0)으로 쓰는 것이 의미있고 일반적이기 때문에 더 좋은 코드이다.

int arr[3] = {1, 2, 3};
for(int i = 0; i < 3; ++i) {
    printf("%d ", *(arr+i)); // arr[i]
}                            // *(arr+0)만 따로 떼어 *arr로 나타내기 힘들기 때문에 일반적이라는 표현을 사용했다.

 

'C언어' 카테고리의 다른 글

C언어 연재, 앞으로의 계획  (0) 2020.03.24
C언어 기초 part 2-4. 문자열  (2) 2020.03.20
C언어 기초 part 2-2. 다차원 배열  (1) 2020.01.31
C언어 기초 part 2-1. 배열  (0) 2020.01.21
C언어 기초 10. 함수 (part 1. 끝)  (2) 2019.12.14