포인터란 무엇인가?
포인터는 번지에 대한 기호화된 표현을 의미합니다.
즉, 포인터는 번지입니다.
이해가 잘 안될 수 있으므로,
int mozi; 라는 변수를 정의합니다. 시스템은 정의를 만나는 순간 mozi 변수에 대해 4 byte 의 메모리를 할당해줍니다.
시스템이 할당해준 4 byte 는 다른 프로세스들이 할당받지 못하며, 각 byte 는 모두 이름을 가지는데 이를 번지라고 합니다.
그림으로 표현하면 다음과 같습니다.
결국 포인터라는 것은 메모리의 위치를 표현한 기호를 의미합니다.
포인터 변수
포인터는 메모리의 특정 위치를 가리킨다고 했습니다.
그렇다면 포인터 변수는 무엇을 의미할까요?
포인터 변수는 포인터를 저장할 수 있는 변수를 말합니다.
이 말은, 메모리의 특정 위치를 저장한다는 말과도 동일합니다.
즉, 포인터 변수에는 상수 값이나 문자, 문자열이 들어가는 것이 아니라 번지가 들어가는 것 입니다.
포인터 변수는 번지 이외에는 어떤 것도 들어갈 수 없다는 것을 꼭 기억해주세요.
포인터 변수 정의
포인터 변수를 정의하는 방법입니다.
int *mozi;
mozi 라는 변수에 * 를 붙였습니다.
포인터 변수를 정의하는 방법은 위처럼 매우 간단합니다.
이것을 해석하면 "mozi 는 정수가 저장된 곳의 위치를 카리킬 수 있다" 라는 말입니다.
그러므로 다음과 같은 식은 성립할 수 없게됩니다.
mozi = 5; mozi = 'a';
포인터 변수를 정의했으므로 시스템은 mozi 에 대해서 아래와 같이 할당을 해줍니다.
그렇다면 아래의 소스에서 각각의 값들은 어떻게 출력이 될까?
main() { int *mozi; printf("%p\n", mozi); printf("%p\n", &mozi); }
첫 번째 printf 의 경우, mozi 에 저장된 값을 출력하라는 의미입니다.
mozi 에 저장된 값은 현재 초기화가 되어있지 않은 상태이므로 쓰레기 값이 들어가 있으며, 매번 실행할 때마다 값이 바뀝니다.
값이 바뀐다고 해서 그 값이 의미가 있는게 아닙니다.
두 번째 printf 의 경우, mozi 에 할당된 첫 번째 메모리의 주소를 출력하라는 의미입니다.
& * 연산자
포인터 변수를 정의했으므로 포인터 변수에 값을 할당해봅니다.
위에서 말한것처럼 포인터 변수에는 번지 이외에는 어떤 값도 들어갈 수 없습니다.
그렇다면 포인터 변수에 번지를 저장하기 위해서는 어떻게 해야할까?
포인터 변수에 번지를 저장하기 위해서 마련된 것이 & 연산자 입니다.
int mozi; &mozi;
mozi 는 4 바이트의 정수를 저장할 수 있는 변수입니다.
& 연산자에 의해서 &mozi 는 mozi 가 저장된 곳의 위치를 뜻하게 됩니다.
main() { int mozi = 5; printf("mozi %d\n", mozi); printf("&mozi %010x\n", &mozi); } mozi 5 &mozi 0x8047d24
위의 소스는 mozi 정수형 변수에는 5라는 값과 5 가 저장된 곳의 메모리 번지는 0x8047d24 라는 것을 알 수 있습니다.
* 연산자는 & 의 반대의 뜻이 됩니다.
즉, 포인터 변수에 저장된 선두 번지를 참조하여 해당하는 장소에 저장된 값을 읽어옵니다.
포인터 변수에 번지 할당
main() { int mozi = 5; int *tistory; // 좌측 그림 tistory = &mozi; // 우측 그림 구조로 변경되는 순간 printf("*tistory %d\n", *tistory); }
mozi 4 byte 정수형 변수 메모리 어딘가에 할당하고 그곳에 5 라는 값을 저장합니다.
5 라는 값이 저장된 곳의 위치를 tistory 에 저장합니다.
마지막으로 * 연산자를 이용하여 tistory 가 가리키고 있는 곳의 값을 출력합니다.
Segmentation Fault
포인트를 사용하다보면 Segmentation Fault 라는 오류를 발생하는 경우를 많이 경험해볼듯 합니다.
이 에러는 해당 번지를 시스템에서 이미 사용하고 있는 경우, 수행이 되려고 하는 프로그램을 중단하며 중단할 때 발생되는 에러입니다.
main() { int *mozi; *mozi = 5; }
위 소스의 의미는 mozi 가 가르키는 곳에 5라는 값을 할당하겠다 라는 의미입니다.
중요한 점이 있습니다. mozi 가 가르키는 곳이 명확하게 정의되어 있어야 한다는 겁니다.
이 소스는 운이 좋다면 Segmentation Fault, 운이 나쁘다면 해당 에러가 발생하지 않을 수 있습니다.
왜 에러가 발생하는데 운이 좋다고 하는걸까?
mozi 는 번지를 저장할 수 있는 변수입니다.
현재 이 번지는 사용자가 초기화 해 준 것이 아니라 변수를 생성할 때 자동으로 들어간 알 수 없는 즉, 쓰레기 값이 들어있는 것 입니다.
만약 쓰레기 값의 번지가 다른 프로그램에 의해 이미 사용되고 있는 상태면 어떻게 될까요?
같은 장소의 메모리를 사용하려고 하다보니 충돌나는 프로그램은 엉망이 되고, 시스템 장애로 발생되게 됩니다.
당연히 시스템은 이 행위를 막으려고 할 것이고 이 때 발생되는 에러메세지가 Segmentation Fault 입니다.
이 에러가 발생하는 경우, "이 프로그램이 다른 프로그램의 메모리 영역을 침범하는구나" 라고 생각하시면 됩니다.
그러므로 이 치명적인 에러를 조기에 발견했다는 점에서 운이 좋다고 하는거였습니다.
위의 소스를 고치려면 어떻게 할까?
mozi 의 변수를 초기화 해준 뒤, 사용합니다.
main() { int tistory; int *mozi; mozi = &tistory; *mozi = 5; }
항상 기억합시다.
포인터 변수는 번지를 초기화(할당) 해주어야 합니다.
'Computer Language > C' 카테고리의 다른 글
[C] 2차원 배열과 포인터 학습하기 (0) | 2018.11.18 |
---|---|
[C] 1차원 배열과 포인터 학습하기 (0) | 2018.11.18 |
[C] 스택 개념, 함수, 코드 정리 (0) | 2018.11.08 |
[C] 큐 개념, 종류 및 작동 방식, 코드 정리 (0) | 2018.11.08 |
[C] 삽입정렬 개념, 알고리즘, 코드 정리 (0) | 2018.11.06 |