Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C 언어 포인터와 배열의 관계 쉽게 이해하기

포인터와 배열

C 언어에서 컴파일러는 배열의 모든 요소에게 연속된 메모리 공간을 할당합니다. 이때 베이스 주소(base address)란 배열의 첫 번째 요소가 저장된 메모리 위치를 의미합니다.

예를 들어 다음과 같은 배열을 선언해 보겠습니다.

int a[5] = {10, 20, 30, 40, 50};

그러면 다섯 개의 요소는 아래 그림처럼 연속된 메모리에 순서대로 저장됩니다.

C 언어 포인터와 배열의 관계 쉽게 이해하기

포인터로 배열 가리키기

만약 p가 정수형(int) 포인터로 선언되어 있다면, 배열 a는 다음 두 가지 방법 중 하나로 가리킬 수 있습니다.

p = a;
또는
p = &a[0];

두 표현식이 같은 의미인 이유는, 배열 이름 자체가 배열 첫 번째 요소의 주소를 나타내기 때문입니다.

포인터 연산과 스케일 팩터(Scale Factor)

p++를 사용하면 한 요소에서 다음 요소로 이동하면서 배열의 각 값에 접근할 수 있습니다. 포인터가 증가할 때 그 값은 단순히 1씩 늘어나는 것이 아니라, 포인터가 가리키는 데이터 타입의 크기만큼 증가합니다. 이 길이를 바로 “스케일 팩터(scale factor)”라고 부릅니다.

예를 들어 int형은 일반적으로 4바이트이므로, 포인터 p와 배열 a의 관계는 다음과 같습니다.

P   = &a[0] = 1000
P+1 = &a[1] = 1004
P+2 = &a[2] = 1008
P+3 = &a[3] = 1012
P+4 = &a[4] = 1016

즉, 특정 요소의 주소는 인덱스와 해당 데이터 타입의 스케일 팩터를 이용해 계산할 수 있습니다.

주소 계산 예제

a[3]의 주소 = 베이스 주소 + (3 × int의 스케일 팩터)

= 1000 + (3 × 4)

= 1000 + 12

= 1012

같은 원리로 역참조(dereference)를 활용하면 다음과 같은 관계가 성립합니다.

*(p+3)은 a[3]의 값을 나타냄
a[i] = *(p+i)

예제 프로그램

포인터를 사용해 배열의 요소를 입력받고 출력하는 전체 코드입니다.

#include<stdio.h>

main() {
    int a[5];
    int *p, i;
    clrscr();
    printf("Enter 5 elements");
    for (i = 0; i < 5; i++)
        scanf("%d", &a[i]);
    p = &a[0];
    printf("Elements of the array are");
    for (i = 0; i < 5; i++)
        printf("%d ", *(p+i));
    getch();
}

참고: 위 코드의 clrscr()getch()는 Turbo C 계열 컴파일러에서 제공하는 함수입니다. 최신 컴파일러(GCC 등)에서는 이 두 함수 호출을 제거하고 #include<conio.h> 없이 실행하면 됩니다.

실행 결과

Enter 5 elements : 10 20 30 40 50
Elements of the array are : 10 20 30 40 50

이처럼 C 언어에서 포인터와 배열은 밀접한 관계를 가지며, a[i]*(p+i)는 본질적으로 동일한 방식으로 동작합니다. 이 개념을 이해하면 배열을 포인터로 자유롭게 다룰 수 있습니다.