메모리의 주소를 가지고 있는 변수입니다. 컴퓨터의 메모리에는 바이트 단위로 주소가 매겨져있는데 이 주소를 이용하여 접근이 가능합니다.
포인터를 알아보기 전에 변수의 주소에 대해서 알아보겠습니다.
변수는 컴퓨터 메모리에 저장된다.
지금까지 우리는 변수를 만들어서 사용해 왔습니다. 이런 변수는 모두 메모리에 만들어집니다. 이러한 메모리에는 각 바이트마다 고유한 주소가 존재합니다. 우리는 이 주고를 이용하여 메모리 바이트에 접근이 가능합니다. 만약 시스템이 20바이트의 메모리를 가지고 있다면, 첫 번째 바이트의 주소는 0부터 시작해서 19까지의 주소가 존재합니다.
프로그램에서 변수를 만들면 컴파일러에 의해여 메모리 공간을 차지합니다. 전에 배웠듯이 변수에 따라서 메모리공간이 다른건 아실껍니다.
주소 연산자 &
C언어에서는 변수의 주소를 계산하는 연산자 &가 존재합니다. 주소 연산자 &는 변수의 이름을 받아서 변수의 주소를 반환합니다.
예를 들어서
1 | int i; 라고 정의하였으면, 변수 i의 주소는 &i를 하면 알 수있다. | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h> int main() { int i = 10; char c = 69; double f = 12.3; printf("i의 주소: %u\n", &i); printf("c의 주소: %u\n", &c); printf("f의 주소: %u\n\n", &f); printf("i의 주소: %x\n", &i); printf("c의 주소: %x\n", &c); printf("f의 주소: %x\n", &f); } | cs |
포인터의 선언
point + er 가리키는 것입니다.. 포인터는 변수의 주소를 가지고 있는 변수입니다. 같은 변수이지만 저장하고 있는 것은 데이터가 아닌 메모리의 주소입니다. 이것뺴고는 변수와 거의 동일하기 때문에 초기화를 해줘야합니다.
포인터를 선언하려면 포인터가 가리키게되는 대상을 쓰고 *을 붙인 다음, 포인터의 이름을 씁니다. 수식과는 아무 상관이 없습니다.
1 2 3 4 5 | int *p; int == 정수를 * == 가리키는 p == 포인터 p | cs |
포인터의 초기화
1 2 3 | int i = 10; // 정수 변수i가 선언되고 10으로 초기화된다/. int *p; // 정수 포인터가 선언된다. p = &i; //포인터p에 i의 주소가 저장된다. | cs |
이런식으로 해주면 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <stdio.h> int main() { int i = 10; double f = 12.3; int *pi = NULL; double *pf = NULL; pi = &i; pf = &f; printf("%u %u\n", pi, &i); printf("%u %u\n", pf, &f); return 0; } | cs |
컴퓨터 마다 주소는 달라지지만 포인터를 이용하여 정상적으로 주소를 출력한 것을 볼수 있습니다.
간접 참조 연산자 *
앞서 &는 주소를 반환한다고 말했습니다. 간접 참조 연산자*는 p가 가리키는 주소에 저장된 내용을 읽어옵니다.
1 2 3 4 | int i = 10; // 정수 변수i가 선언되고 10으로 초기화된다/. int *p; // 정수 포인터가 선언된다. p = &i; //포인터p에 i의 주소가 저장된다. printf("%d \n", *p); //10이 출력된다. | cs |
*p는 p가 가리키는 위치에 있는 데이터를 가져오라는 의미입니다. p는 p가 가리키는 위치에 무엇이 있는지 모르기때문에, p가 int형 포인터라면 4바이트를 읽어들입니다. 포인터의 타입이 없다면, 포인터를 이용하여 데이터를 읽어 들일 때 몇개의 바이틀르 읽어야 할지 알 수 없게 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /*변수와 포인터를 연결한 후에 변수의 주소와 포인터의 값을 출력.*/ #include <stdio.h> int main() { int i = 3000; int*p = NULL; p = &i; printf("p=%u\n", p); printf("&i=%u\n\n", &i); printf("i=%d\n", i); printf("*p=%d\n\n", *p); return 0; } | cs |
사용자마다 메모리 주소는 다릅니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /*변수와 포인터를 연결한 후에 변수의 주소와 포인터의 값을 출력.*/ #include <stdio.h> int main() { int i = 3000; int*p = NULL; p = &i; printf("p=%u\n", p); printf("&i=%u\n\n", &i); printf("i=%d\n", i); printf("*p=%d\n\n", *p); return 0; } | cs |
포인터 사용지 주의할 점
-초기화 하지 않기
쓰레기 값을 가지기때문에 꼭 초기화를 해줘야 합니다.
-NULL포인터의 사용
포인터가 아무것도 가리키고 있지 않을 때는 NULL로 설정해주세요. NULL은 0을 뜻합니다.
-포인터 타입과 변수의 타입은 일치해야한다.
포인터도 여러가지 타입이 존재하는데 포인터의 타입에 따라 메모리를 얼만큼 읽어들이는지 달라지기때문에 꼭 일치해야합니다.
- 절대 주소 사용
윈도우에서는 절대 주소를 사용하지 말아주세요.,
포인터의 연산
덧셈과 뺼셈 연산
포인터에서 p++하게되면 포인터의 정수형 만큼 ++가 됩니다. int 형이면 1이 늘어나는것이 아닌 4만큼 늘어나고,
double형이면 8만큼 늘어나게 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <stdio.h> int main() { char *pc; int *pi; double *pd; pc = (char *)10000; pi = (int *)10000; pd = (double *)10000; printf("증가 전 pc = %d , pi = %d , pd = %d\n", pc, pi, pd); // 현재 값 pc++; pi++; pd++; printf("증가 후 pc = %d , pi = %d , pd = %d\n", pc, pi, pd); // 1씩 더한 값 printf(" pc+2 = %d , pi+2 = %d , pd+2 = %d\n", pc + 2, pi + 2, pd + 2); // 2씩 더한 값 return 0; } | cs |
'C 프로그래밍 > 9. 포인터 ' 카테고리의 다른 글
9.2 포인터와 함수, 포인터 사용의 장점 (0) | 2019.06.18 |
---|