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

C 언어 포인터와 1차원 배열 완벽 가이드 – 개념부터 예제까지

포인터란 무엇인가?

포인터(pointer)는 다른 변수의 메모리 주소를 저장하는 특수한 변수입니다. C 언어에서 포인터를 제대로 이해하면 메모리를 직접 제어하는 강력하고 유연한 프로그래밍이 가능해집니다.

포인터의 주요 특징

  • 메모리 공간을 절약할 수 있습니다.
  • 메모리 위치에 직접 접근하기 때문에 실행 속도가 빠릅니다.
  • 동적 메모리 할당과 해제를 통해 메모리를 효율적으로 관리할 수 있습니다.
  • 연결 리스트, 트리 등 다양한 자료구조를 구현할 때 필수적으로 활용됩니다.

포인터의 선언, 초기화, 접근

먼저 다음 문장을 살펴보겠습니다.

int qty = 179;

변수는 메모리상에서 이름, 주소, 값의 형태로 표현됩니다.

포인터 선언

아래 문장에서 'p'는 다른 정수형(int) 변수의 주소를 저장하는 포인터 변수임을 의미합니다.

int *p;

포인터 초기화

포인터 변수는 주소 연산자(&)를 사용하여 초기화합니다.

int qty = 175;
int *p;
p = &qty;

이제 포인터 p에는 변수 qty의 메모리 주소가 저장됩니다.

포인터를 통한 변수 값 접근

포인터가 가리키는 변수의 값을 읽으려면 간접 참조 연산자(*)를 사용합니다. 여기서 '*'는 "해당 주소에 저장된 값"을 의미한다고 생각하면 됩니다.

따라서 아래 두 문장은 서로 동일한 결과를 가져옵니다.

p = &qty;
n = *p;   /* n = qty와 같음 */

포인터와 1차원 배열의 관계

  • 컴파일러는 배열의 모든 요소에 대해 연속적인 메모리 공간을 할당합니다.
  • 기준 주소(base address)란 배열의 첫 번째 요소, 즉 인덱스 0의 주소를 의미합니다.
    예: int a[5] = {10, 20, 30, 40, 50};

배열 요소의 메모리 배치

다섯 개의 요소는 메모리에 순차적으로 저장됩니다.

'p'가 정수형 포인터로 선언되어 있다면, 배열 'a'는 다음과 같이 포인터에 대입할 수 있습니다.

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

배열 이름 자체가 첫 번째 요소의 주소를 의미하기 때문에 두 표현은 같은 결과를 냅니다.

포인터 연산과 스케일 팩터

  • p++를 사용하면 한 요소에서 다음 요소로 이동하며 배열의 모든 값을 접근할 수 있습니다.
  • 포인터가 증가할 때 그 값은 포인터가 가리키는 자료형의 크기만큼 증가합니다. 이 크기를 스케일 팩터(scale factor)라고 부릅니다. 예를 들어 int형은 일반적으로 4바이트이므로 포인터가 1 증가할 때마다 주소는 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
  • 배열 인덱싱 대신 포인터를 사용하여 배열 요소에 접근할 수 있습니다.
  • *(p+3)a[3]의 값을 나타냅니다.

즉, 인덱스 표기법과 포인터 표기법 사이에는 다음과 같은 일반적인 관계가 성립합니다.

a[i] = *(p+i)

예제 프로그램

다음은 포인터와 1차원 배열을 함께 활용한 C 프로그램입니다. 사용자로부터 5개의 정수를 입력받아, 포인터 연산으로 배열 요소를 출력합니다.

#include <stdio.h>

int main(void) {
    int a[5];
    int *p, i;

    printf("5개의 정수를 입력하세요 : ");
    for (i = 0; i < 5; i++)
        scanf("%d", &a[i]);

    p = &a[0];

    printf("배열의 요소들 : ");
    for (i = 0; i < 5; i++)
        printf("%d ", *(p + i));

    return 0;
}

실행 결과

위 프로그램을 실행하면 다음과 같은 결과가 출력됩니다.

5개의 정수를 입력하세요 : 10 20 30 40 50
배열의 요소들 : 10 20 30 40 50

이처럼 포인터를 활용하면 배열의 요소를 인덱스 없이도 자유롭게 탐색할 수 있으며, 이는 C 언어에서 메모리를 효율적으로 다루는 핵심 개념이 됩니다.