배열과 포인터는 구조상 닮은 점이 많다. 그래서 동일한 내용을 다르게 표현할 수 있다.
C에서는 사용자에게 표현의 범위를 넓게 줬다.
동일한 기능을 수행할때 다수의 문법 중에 하나를 고르라면 곤혹스러운 일이 될 수 있다.
하지만 C는 최대한 프로그래머의 자율성을 존중하며 그 책임또한 각자가 짊어져야 한다.
아래 예제는 배열과 포인터를 사용하여 동일한 기능을 가진 for문을 4개의 다른 표현방법으로 구현한다.
#include <stdio.h>
void main(){
int array[10] ={0,};
array[0] = 5;
array[3] = 7;
int length = sizeof(array)/sizeof(array[0]);
int *ptr1 = array; // or &array[0]
printf("\n Array style : ");
for (int i=0; i < length; i++){
printf("%d ",array[i]);
}
printf("\n Pointer style : ");
for (int i=0; i < length; i++){
printf("%d ",*(array+i));
}
printf("\n using Pointer 1 : ");
for (int i=0; i < length; i++){
printf("%d ",*(ptr1+i));
}
printf("\n using Pointer 2: ");
for (int i=0; i < length; i++){
printf("%d ",ptr1[i]);
}
}
첫번째 루프는 전통적 배열방식으로 인덱스를 사용했다
두번째 루프는 포인터연산 스타일을 배열변수에 적용시켰다.
세번째 루프는 기본 포인터 연산을 사용했다.
네번째 루프는 포인터에 배열과 같은 인덱스를 적용했다.
문법상 표기법이 다양하면 장점도 있고 단점도 있으니 사용자가 판단을 잘 해야한다.
참고로 배열의 구조를 알면 포인터와 사용법이 비슷한지 알 수 있을 것이다.
배열 시작주소의 표현방법도 다양하다. &는 주소 연산자 *는 포인터 연산자로 감안하면 이 숫자들이 무엇을 의미하는지 알 수 있을 것이다.
특히 혼동이 쉬운 부분은 배열의 시작 주소이다.
array[10] 의 시작주소는 명백히 &array[0] 이다. C언어에서는 편의를 제공한다. array 라는 이름만으로 배열의 시작주소임을 나타낸다. 편의적이지만 혼동의 소지가 많다. &array라고 사용하면 경고 메시지가 뜬다. array 가 주소값인데 또다시 주소값을 연산하면 중복이 된다. 그러니 배열의 주소 표기 방식은 주소 연산자를 붙이지 않는 array로 통일하는게 좋다.
배열은 어디까지나 배열이지 포인터는 아니다. 연산이 비슷한 것은 특징일 뿐 배열의 정해진 사용 범위를 넘을 수는 없다.
아래 예제는 배열 시작주소를 다양하게 표현한다.
#include <stdio.h>
void main(){
char ch_array1[3] = {0,};
char *ptr1 = &ch_array1[0];
char *ptr2 = ch_array1;
char *ptr3 = &(*ch_array1);
char *ptr4 = &*(ch_array1+0);
char *ptr5 = &*ch_array1;
// char *ptr6 = &ch_array1; warning
printf("array1 | %d : %p |\n",*ptr1,ptr1);
printf("array1 | %d : %p |\n",*ptr2,ptr2);
printf("array1 | %d : %p |\n",*ptr3,ptr3);
printf("array1 | %d : %p |\n",*ptr4,ptr4);
printf("array1 | %d : %p |\n",*ptr5,ptr5);
}