1. 배열
: 변수가 여러개 모인 것.
ex)
// 각각 한 개의 원소마다, int형이기 때문에 4byte씩 차지한다.
// 자료형에 따라, 주소값 또한 4씩 증가한다.
2. 포인터와 배열
① (parr + i) = & arr[i]
만약, p라는 포인터가 int a를 가르킨다면?
p+1 = (p의 주소값) + 1*4
p+3 = (p의 주소값) + 3*4
이 아이디어를 기반으로, 배열의 원소를 가르키는 포인터를 만들어 보려고 한다.
parr이 int형이므로, +i를 하면, 주소값에는 4*i씩 더해지는 것이다.
이 때 arr[i]도 int형 배열이므로, +i가 될 때마다, 4씩 증가하게 된다.
따라서 모든 결과가 일치하게 된다.
② arr = &arr[0]
이 예제에서 보면 알 수 있듯이, arr은 arr[0]의 주소값과 같다.
주의 ) 그러나 이 arr은 배열의 첫번째 원소를 가르키는 포인터가 아니다
③ 배열, 포인터 Sizeof 비교
sizeof(arr) : 배열의 실제크기가 나온다. 즉, arr배열에는 int원소 6개가 있으므로, 크기가 4*6 = 24가 된다.
sizeof(parr) : 배열 자체의 크기가 아닌, 그냥 포인터의 크기를 알려준다.
- 그런데 왜 arr이, &arr[0] 즉 parr과 같은 값이 나왔을까?
: C언어 상에서 배열의 이름이, sizeof연산자나 주소값 연산자(&)와 사용될 때(ex. &arr)의 경우를 빼면, 배열의 이름을 사용할 경우 암묵적으로 첫 번째 원소를 가리키는 포인터로 타입변환되기 때문이다.
따라서, arr의 경우, 첫 번째 원소를 가리키는 포인터로 타입 변환되기 때문에, &arr[0]과 일치하게 된다.
④ [ ] 연산자의 역할
[ ] 연산자가 C에서 쓰이면, 컴퓨터는 자동적으로 형태를 변환하여 처리한다.
즉, arr[3] = *(arr + 3)의 경우, arr이 첫번째 원소를 가리키는 포인터로 변환되어서, arr+3이 포인터 덧셈을 수행하게 되고, 이는 배열의 4번째 원소를 가리키게 된다.
이러한 원리에 따라서,
3[arr] = *(3+arr) = *(arr+3), 이 또한 실행이 가능하다.
⑤ 배열 이름의 활용, 배열과 포인터 차이점 인지
[ 배열 이름과 포인터 비교 ]
포인터 | 배열 이름 |
이름이 존재한다. | 이름이 존재한다. |
메모리의 주소를 나타낸다. | 메모리의 주소를 나타낸다. |
변수이다. | 상수이다. |
- 앞서 배운 내용들과 같이, 배열 이름을 포인터처럼, 포인터를 배열 이름처럼 활용하는 것이 가능하다.
- 그러나 ptr은 변수이기 때문에, 다른 값의 주소를 가르킬 수 있지만, arr은 상수이기 때문에 다른 주소를 가리킬 수 없다. 이 차이를 분명하게 인지하고 있어야 한다.
⑥ 포인터 활용하기
ex 1) 포인터 활용 예시
while(parr - arr <= 9){
// parr - arr은 주소값이 나옴. 그 뺀 주소값을, 십진수로 변환했을 경우, 36, 즉 arr[9]보다 크게 되면, 실행을 그만하게 된다.
sum+=(*parr);
parr++;
// 포인터변수에서 1을 증가시킨다면, parr에 저장된 주소값에 1이 더해지는 것이 아니라, 4가 더해지게 되면서 배열의 그 다음 원소를 가리키게 된다.
}
ex 2) 그렇다면, 왜 포인터변수 parr을 따로 선언하였을까?
의문점 ) arr이 arr[0]을 가리킨다는 사실을 알고 있으니까, 이를 증가시켜서 *(arr)로 접근해도 되지 않은가?
arr++;는 실행할 수 없다.
배열의 이름이 첫 번재 원소를 가리키는 포인터로, 타입 변경된다고 했지만, 이는 단순히 배열의 첫 번째 원소를 가리키는 주소값 자체가 될 뿐이다. 즉, arr은 상수이기 때문에, 주소값 자체가 변경될 수 없다는 것이다.
구체적인 사례는 ex 3)을 통해 확인해보자.
ex 3) 배열이름 vs 포인터의 '++연산자 '
다시말해서 아래와 같은 예시는 실행 가능하다는 것이다.
3. 1차원 문자배열
ex 1) 문자열 상수를 가리키는 포인터
- NULL공간은 문자열의 끝을 알려준다.
- 포인터는 문자열의 첫번째, 시작되는 주소를 가르키게 된다.
ex 2) char형 배열 vs char형 포인터
char형 배열 | char형 포인터 | |
가리키는 위치 변경 | 불가능 | 가능 |
문자열 내용을 변경 | 가능 | 불가능 |
char arr[10] = "Hello"; [" "은 문자열] // char형 배열 arr[10]은, char형 문자열 "Hello"를 담는다.
char * ptr = "world"; [" "은 문자열] // char형 포인터 변수 ptr은, char형 문자열 "world"의 시작주소를 담는다.
char * pptr = arr; [arr은 배열] // char형 포인터 변수 pptr은, char형 배열 arr[10]의 주소를 담는다.
ptr = "Hello"; // char형 포인터는 문자열의 수정이 불가능하다.
arr = ptr; // 오류 발생 o (배열의 첫 주소가 바뀔 수 없음)
ptr = arr; // 오류 발생 x (포인터는 가리키는 공간이 달라질 수 있으므로, 첫 주소가 바뀔 수 있음)
arr[0] = 'A'; // 오류 발생 x (문자열을 초기화 할 때, 배열은 배열 원소 변경을 할 수 있다) - char형 배열 문자열 변경 성공
ptr[0] = 'A'; //오류 발생 o (문자열을 초기화할 때, 포인터는 배열 원소를 바꿀 수 없다) - char형 포인터 문자열 변경 실패
pptr[0] = 'A' // 오류 발생 x (arr은 배열의 주소를 가져온 것과 마찬가지이므로, 원소의 값 변경 가능하다)
4. 포인터의 포인터
- 포인터변수도 그 자체로 주소값을 가지고 있다.
- 그 포인터변수의 주소를 가르키는, 포인터가 존재할 수 있다. (얼마든지 원한다면 설정 가능)
* 유의사항 - 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다. - 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다. - 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :) |