1.포인터 연산과 배열과의 관계
int *p;가 선언되어 있고 p에 주소 0x1000전지가 저장되어 있다고 가정하면 p+1은 어떤 값을 가질까? 0x1001이 될 것이라고
생각할 수도 있는데 여기서 +1은 int형 하나의 크기를 의미한다. 즉, int형은 4바이트이므로 주소 값에 +4가 되어 0x1004가 된다.
결국 포인터 변수에 N을 더하거나 뺄 경우는 '포인터가 가리키는 데이터형 x N'만큼 주소를 더하거나 뺀 값이 된다.
이 시점에서 배열과 포인터의 관계에 대한 감이 조금 잡힐 것이다. 아래의 코드를 보자.
포인터 변수 p는 배열 arr의 첫 번째 원소의 주소 값을 가졌으므로 *p는 첫 번째 원소의 값을 가리키게 된다. 그러므로 p++가
되면 앞서 말했듯이 int형 포인터 변수의 증감이므로 4바이트 이동해서 정확히 배열 arr의 다음 원소를 가리킨다. 즉, arr[1]을
가리키게 된다. 도식화 하면 아래와 같다.
배열의 이름은 배열의 시작 주소가 된다. 즉, int arr[5];에서 인덱스 없이 arr는 배열의 시작 주소이다. 이 말은 arr는 arr[0]의
주소와 같다는 것이다. 따라서 arr==&arr[0]=true가 된다. 여기서 배열의 이름인 arr은 주소이므로 포인터처럼 이용할 수 있다. arr+1이 되면 앞서 설명했듯이 arr[1]을 가리키게 되므로 *(arr+1)은 arr[1]의 값을 나타낸다.
이것을 이용하여 배열을 포인터로 가리키면 포인터를 배열처럼 사용할 수 있다.
arr는 주소이므로 포인터 변수에 대입이 가능하다.
여기서 p+1을 하면 arr[0](=arr)을 가리키던 것이 arr[1]을 가리키게 된다. 그리고 이것을 &p[1]로 표현할 수 있다.
이렇게 포인터 변수를 배열 이름인 것처럼 사용할 수 있다.
하지만 배열과 포인터의 중요한 차이점이 있다.
배열은 일단 메모리에 할당되면 시작 주소를 변경할 수 없다.
반면 포인터 변수는 변수이므로 보관된 주소를 변경할 수 있다.
2.포인터와 문자열
'A', 3.14와 같은 리터럴 상수는 메모리에 저장하지 않고 필요할 때마다 CPU 레지스터에 만들어지고 사용 후에 없어지는
임시 값(temporary value)이다. 하지만 CPU 레지스터는 보통 크기가 정해져 있는데 문자열 리터럴은 길이가 정해지지
않아 특별히 메모리에 보관해두고 사용한다. 하지만 리터럴 상수이므로 값을 읽어볼 수만 있고 변경할 수 없는 메모리
영역에 존재하며 "abc";는 실제로 문자열 리터럴 주소를 의미한다.
문자열을 비교할 때 strcmp()를 쓰는 이유를 이제 알 수 있다.
p == "abc"는 문자열의 주소를 비교하는 것이다. 당연히 주소는 다르다. 따라서 strcmp()를 이용해서 문자열의 내용을
비교하는 것이다.
3.const 포인터
int *p;가 선언되어 있고 p에 주소 0x1000전지가 저장되어 있다고 가정하면 p+1은 어떤 값을 가질까? 0x1001이 될 것이라고
생각할 수도 있는데 여기서 +1은 int형 하나의 크기를 의미한다. 즉, int형은 4바이트이므로 주소 값에 +4가 되어 0x1004가 된다.
결국 포인터 변수에 N을 더하거나 뺄 경우는 '포인터가 가리키는 데이터형 x N'만큼 주소를 더하거나 뺀 값이 된다.
이 시점에서 배열과 포인터의 관계에 대한 감이 조금 잡힐 것이다. 아래의 코드를 보자.
int arr[5]; int *p = &arr[0]; int i; for(i=0;i<5;i++,p++) printf("%d\n",*p); |
되면 앞서 말했듯이 int형 포인터 변수의 증감이므로 4바이트 이동해서 정확히 배열 arr의 다음 원소를 가리킨다. 즉, arr[1]을
가리키게 된다. 도식화 하면 아래와 같다.
↑ ↗ ↗ ↗ ↗
|
배열의 이름은 배열의 시작 주소가 된다. 즉, int arr[5];에서 인덱스 없이 arr는 배열의 시작 주소이다. 이 말은 arr는 arr[0]의
주소와 같다는 것이다. 따라서 arr==&arr[0]=true가 된다. 여기서 배열의 이름인 arr은 주소이므로 포인터처럼 이용할 수 있다. arr+1이 되면 앞서 설명했듯이 arr[1]을 가리키게 되므로 *(arr+1)은 arr[1]의 값을 나타낸다.
&arr[i] == arr+i; arr[i] == *(arr+i); |
이것을 이용하여 배열을 포인터로 가리키면 포인터를 배열처럼 사용할 수 있다.
int arr[5]; int *p = arr; |
여기서 p+1을 하면 arr[0](=arr)을 가리키던 것이 arr[1]을 가리키게 된다. 그리고 이것을 &p[1]로 표현할 수 있다.
*(p+i) == p[i]; p+i == &p[i]; |
하지만 배열과 포인터의 중요한 차이점이 있다.
배열은 일단 메모리에 할당되면 시작 주소를 변경할 수 없다.
int a[5]; int b[5]; a=b; //배열 a의 시작 주소를 배열 b의 시작 주소로 변경하려고 하면 컴파일 에러 발생 a++; //배열 a의 시작 주소를 증가시키므로 (4바이트만큼 이동) 컴파일 에러 |
반면 포인터 변수는 변수이므로 보관된 주소를 변경할 수 있다.
int a[5]; int b[5]; int* p=a; //포인터 p를 배열 a의 시작 주소로 초기화 p=b; //포인터 변수 p에 배열 b의 주소를 저장, p는 b를 가리킴 p++; //포인터 p를 1만큼 증가시켜 b[1]을 가리킴 |
2.포인터와 문자열
'A', 3.14와 같은 리터럴 상수는 메모리에 저장하지 않고 필요할 때마다 CPU 레지스터에 만들어지고 사용 후에 없어지는
임시 값(temporary value)이다. 하지만 CPU 레지스터는 보통 크기가 정해져 있는데 문자열 리터럴은 길이가 정해지지
않아 특별히 메모리에 보관해두고 사용한다. 하지만 리터럴 상수이므로 값을 읽어볼 수만 있고 변경할 수 없는 메모리
영역에 존재하며 "abc";는 실제로 문자열 리터럴 주소를 의미한다.
char *p = "abc"; //p에 문자열 리터럴 주소를 보관 p[0] = 'A'; //문자열 리터럴은 변경 불가 strcpy(p,"hello"); //문자열 리터럴은 변경불가 p="hello"; //포인터 변수 p에 다른 문자열 주소 대입은 가능 |
문자열을 비교할 때 strcmp()를 쓰는 이유를 이제 알 수 있다.
p == "abc"는 문자열의 주소를 비교하는 것이다. 당연히 주소는 다르다. 따라서 strcmp()를 이용해서 문자열의 내용을
비교하는 것이다.
3.const 포인터
const char* p; //포인터가 가리키는 값 변경 불가 char* const p; //포인터 변수 자신의 값(주소) 변경 불가 const char* const p; //가리키는 값, 주소 둘 다 변경 불가 |
'프로그래밍 > C' 카테고리의 다른 글
typedef (0) | 2011.01.22 |
---|---|
공용체와 열거체 (0) | 2011.01.19 |
구조체 (0) | 2010.10.23 |
포인터 (Pointer) (0) | 2010.10.09 |
선택정렬 (Selection Sort) (0) | 2010.10.09 |
배열 (array) (0) | 2010.10.09 |
비트 연산자 (0) | 2010.10.03 |