C언어 강좌
포인터 변수
포인터
C언어에서 가장 어렵고도 중요한 개념입니다.
우리는 지금까지 '주소'의 존재를 간과하고 주로 데이터값을 중점적으로 프로그래밍 해왔습니다.
그러나 컴퓨터의 관점에서 변수를 참조할 때, 주소를 먼저 참조한 뒤 데이터값을 참조하죠.
우리는 택배 내용물만 관심이 있었지 택배를 보낼 주소에는 관심이 없었습니다.
포인터 변수는 그 '주소'를 저장해줍니다.
여기서 주소란 데이터의 저장 위치를 나타내며 &(엠퍼센트)로 표현합니다.
포인터를 사용해야 하는 이유
포인터는 데이터에 직접 접근하는 것이 아니라 간접적으로 접근합니다.
(포인터 이외에도 함수 호출, 재귀함수 등등에서도 간접적으로 접근)
데이터에 접근하기 전에 주소에 먼저 접근한 뒤 데이터를 꺼내옵니다.
따라서 직접적인 사고방식보다 간접적인 사고방식에 중점을 두는데
이때, 필요한 능력이 '논리력'입니다. 포인터를 자유자재로 활용하기 위해서는
'논리력'이 필요하며 포인터를 사용하면 할수록 논리적으로 사고할 수 있는 능력치가 점점 증가하게 되죠.
논리력뿐만 아니라 코드를 효율적으로 짜기 위해서도 포인터는 필요합니다.
나중엔 하드웨어를 공부하면서 포인터는 더욱 중요해진다고 하는데요,
서로 다른 코드가 같은 결과물을 내더라도 프로그래밍 속도의 차이가 날 수 있으니
포인터는 프로그래머에게 꼭 필요한 개념입니다.
포인터 변수의 선언
포인터 변수 앞에 '*'를 붙여주면 포인터 변수의 선언이 됩니다.
*는 변수에 저장된 메모리 공간에 접근할 때 사용하는 연산자입니다.
*연산자는 변수의 메모리 공간의 위치를 가리킵니다.
Ex)
int *p;
char* p;
char *p; → *의 위치는 자료형 바로 뒤에 와도 되고 변수 바로 앞에 붙어도 상관없습니다.
double *p;
→ 포인터 변수 앞에 '*'을 붙여줍니다.
포인터 변수의 초기화
포인터는 NULL 값으로 초기화해주어야 합니다.
형식 → 자료형 *포인터변수명 = NULL;
Ex) int *pointer = NULL;
NULL 값으로 초기화해주지 않으면 쓰레기값이 출력됩니다.
NULL값은 아스키코드에서 0값과 같으므로 0으로 초기화해주어도 됩니다.
Ex) int *pointer1 = NULL;
int *pointer2 = 0;
포인터 변수를 NULL값 또는 0으로 초기화해주면 아직 저장된 주소 값이 없다는 의미입니다.
포인터 주의사항
포인터 변수에는 주소만 저장됩니다.
주의해야 할 사항을 포인터의 자료형이 일치하는 변수의 주소만을 갖습니다.
Ex)
int a = 10;
char b = 'A';
int *p = NULL;
p = &a; (o)
p = &b; (x)
--> b의 주소를 왜 갖지 못할까요?
포인터 변수는 int형으로 선언했기 때문에 자료형이 다른 b의 주소를 갖지 못합니다.
int a, b, c; 를 포인터 변수로 모두 선언하기 위해서는
int *a, b, c;라고 표현하면 될까요?
위의 코드는 변수 a만을 포인터로 선언되고 b와 c는 일반 int 자료형으로 저장됩니다.
변수 a, b, c를 모두 포인터로 선언하기 위해서는
int *a, *b, *c;라고 표현해야겠죠.
포인터 자료형의 크기
포인터 자료형에 상관없이
32비트 운영체제에선 4byte의 메모리 크기를,
64비트 운영체제에선 8byte의 메모리 크기를 가집니다.
#include <stdio.h> int main(void){ printf("%d %d %d %d %d \n", sizeof(char), sizeof(int), sizeof(float), sizeof(double), sizeof(long double)); printf("%d %d %d %d %d \n", sizeof(char*), sizeof(int*), sizeof(float*), sizeof(double*), sizeof(long double*)); return 0; }
다음은 출력 결과입니다.
보신 바와 같이 포인터는 자료형과 관계없이 4byte or 8byte의 메모리 크기를 가집니다.
저의 컴퓨터는 64비트 운영체제인데 이클립스의 버전을 보니 32비트로 깔려있네요.(왜 그랬지)
(어쩐지 자꾸 4byte만 출력돼서 헷갈렸습니다;)
제 컴퓨터에 설치된 이클립스는 32비트 버전이므로 포인터 자료형은 4byte의 크기를 가지게 됩니다.
다음은 포인터를 이용한 예제입니다.
#include <stdio.h> int main(void){ int num = 10; //일반 변수 선언 및 초기화 int* ip = NULL; //포인터 변수 선언 및 초기화 ip = # //num의 주소 값을 포인터 변수 ip에 저장 printf("%d\n", num); //변수 num의 값 printf("%p\n", &num); //변수 num의 주소 값 printf("%p\n", ip); //포인터 변수 ip의 값(=&num) printf("%p\n", &ip); //포인터 변수 ip의 주소 값 printf("%d\n", *ip); //포인터 변수 ip가 가리키는 곳의 값(=num) printf("%p\n", *&ip); //포인터 변수 ip의 주소가 가리키고 있는 곳의 값(=&num) //*& → 서로 상쇄 return 0; }
다음은 출력 결과입니다.
일반 변수와 포인터 변수를 각각 선언한 뒤 초기화합니다.
일반 변수의 주소 값(&num)을 포인터 변수(ip)에 저장합니다.
일반 변수와 포인터 변수를 출력해줍니다.
위의 출력결과에서 *&는 상쇄되어 기호가 없는것과 같습니다.
ip의 주소(&ip)에 있는 데이터값을 출력하는 것이므로
ip=&num의 값이 출력됩니다.
참고
서식문자 %p는 주소를 표현할 때 쓰입니다.
Call by Value와 Call by Reference
Call by Value는 값에 의한 전달을 의미하며,
Call by Reference는 주소에 의한 전달을 의미합니다.
Call by Value
데이터값을 전달하는 기본적인 호출방법입니다.
#include//함수 func 선언 int func(int i); int main(void){ int n=10; int result=0; //함수 func 호출 //값(n)을 전달 (Call by Value) result = func(n); printf("%d \n", result); printf("%d \n", n); return 0; } //함수 func 정의 int func(int i){ i=i+1; return i; }
다음은 출력 결과입니다.
Call by Reference
주소를 참조해서 함수를 호출합니다.
데이터값을 전달하는 것이 아닌, 값이 들어있는 '주소'를 전달합니다.
연산 결과에 따라 변수에 저장된 값이 변경될 수 있습니다.
#includeint func(int *i); int main(void){ int n=10; int result=0; //함수 func 호출 //주소(&n)를 전달(Call by Reference) result = func(&n); printf("%d \n", result); printf("%d \n", n); //기존변수에 저장된 값이 변경이 됩니다. return 0; } int func(int *i){ *i=*i + 1; return *i; }
다음은 출력 결과입니다.
'Code.D IT 강좌 > C언어' 카테고리의 다른 글
[C언어 강좌] 배열(1차원 배열, 2차원 배열, 3차원 배열) (0) | 2017.06.12 |
---|---|
[C언어 강좌] 함수(function) (0) | 2017.06.09 |
fflush 함수, fflush(stdin)/fflush(stdout) 개념 제대로! (0) | 2017.06.07 |
[C언어 강좌] 제어문 - 반복문(while문, for문, do~while문) (0) | 2017.06.01 |
[C언어 강좌] 제어문 - 조건문(if문, switch문) (0) | 2017.05.30 |