본문 바로가기
C 언어/실무

C언어 배열과 포인터 차이 (헷갈리는 이유부터 핵심 차이까지)

by Autosar 2026. 4. 12.
반응형

C언어에서 포인터를 어느 정도 이해하고 나면 많은 사람이 다음 단계에서 헷갈린다.
바로 배열과 포인터가 왜 비슷하게 동작하는가?, 그리고 둘은 같은 것인가? 라는 질문이다.

예를 들어 아래 코드를 보면 배열과 포인터가 같은 역할을 하는 것처럼 느껴진다.

uint8 Data[3] = {10U, 20U, 30U};
uint8 *ptr = Data;

(void)printf("%u", Data[0]);
(void)printf("%u", *ptr);

 

둘 다 첫 번째 값인 10을 출력한다.

그래서 많은 사람이 이렇게 생각한다.

* 배열 = 포인터 아닌가?
* 배열 이름은 왜 주소처럼 쓰이지?
* 둘이 뭐가 다른가?

결론부터 말하면, 배열과 포인터는 비슷하게 사용할 수는 있어도 완전히 다른 개념이다.

이번 글에서는 임베디드 실무 스타일 코드 기준으로 배열과 포인터 차이를 쉽게 설명한다.

 

배열이란 무엇인가?

 

배열은 같은 자료형 데이터를 여러 개 연속으로 저장하는 메모리 공간이다.

예:

uint8 TxData[4] = {0x11U, 0x22U, 0x33U, 0x44U};

 

의미:

TxData[0] = 0x11
TxData[1] = 0x22
TxData[2] = 0x33
TxData[3] = 0x44


즉, 배열은 여러 데이터를 한 번에 관리하기 위한 저장소다.

실무에서는 다음과 같이 많이 사용된다.

- CAN Tx/Rx 데이터
- 센서 샘플 데이터
- EEPROM 버퍼
- 진단 데이터 버퍼

 

포인터란 무엇인가?

 

이미 앞전에 포인터가 무엇인지 설명했지만 그래도 비교를 위해 간단하게 한 번 더 설명한다.

앞전 글을 보지 못했다면 아래 링크로 들어가서 천천히 읽어보면 된다.

https://jjongday.tistory.com/96

 

포인터는 메모리 주소를 저장하는 변수다.

예:

uint8 Value = 10U;
uint8 *ptr = &Value;

 

의미:

Value는 실제 값 10 저장
ptr은 Value의 주소 저장

 

즉, 배열은 데이터 저장 공간이고, 포인터는 위치(주소)를 저장하는 변수이다.

둘은 역할 자체가 다르다.

 

왜 배열과 포인터가 같아 보일까?

 

배열 이름은 특정 상황에서 첫 번째 요소의 주소처럼 사용되기 때문이다.

예:

uint8 RxData[3] = {1U, 2U, 3U};
uint8 *ptr = RxData;

 

여기서 RxData는 아래와 비슷하게 동작한다.

ptr = &RxData[0];

 

즉, 배열 이름이 첫 번째 요소 주소처럼 전달된다.

그래서 다음 코드가 가능하다.

uint8 A = *ptr;       
uint8 B = *(ptr + 1);
uint8 C = *(ptr + 2);

 

결과:

A = 1
B = 2
C = 3

 

이 때문에 배열과 포인터가 같은 것처럼 느껴진다.

 

핵심 차이 1: 배열은 공간, 포인터는 변수

 

## 배열

uint8 Buffer[8];

 

이 코드는 8바이트 저장 공간을 만든다.
즉, 배열은 실제 데이터를 담는 메모리 공간이다.

 

## 포인터

uint8 *ptr;


이 코드는 주소를 저장할 변수를 만든다.
즉, 포인터는 데이터 자체가 아니라 위치 정보를 저장한다.

 

핵심 차이 2: 배열 이름은 변경 불가, 포인터는 변경 가능

 

## 배열

 

배열은 다른 주소를 가리킬 수 없다

uint8 Buffer[4];

Buffer = Buffer + 1U;   /* 오류 */

 

배열 이름은 변수처럼 값을 바꾸는 대상이 아니다. (위 코드는 잘못된 코드)

## 포인터

 

포인터는 변경 가능하다

uint8 Data1 = 10U;
uint8 Data2 = 20U;

uint8 *ptr = &Data1;
ptr = &Data2;

 

이 코드의 의미는 처음에는 Data1 주소 저장하고, 이후 Data2 주소로 변경하는 코드이다.

이것이 배열과 포인터의 큰 차이다.

 

핵심 차이 3: sizeof 결과가 다르다
uint8 Buffer[8];
uint8 *ptr = Buffer;

 

의미:

sizeof(Buffer) = 8
sizeof(ptr) = 포인터 크기 (예: 4 또는 8)


즉, 배열은 전체 저장 공간 크기이고, 포인터는 주소 변수 크기이다.

메모리 구조가 완전히 다르다.

 

핵심 차이 4: 함수 인자에서는 배열이 포인터처럼 동작한다

 

실무에서 가장 자주 보는 패턴이다.

void ProcessData(uint8 *DataPtr)
{
    uint8 Value;

    Value = DataPtr[0];
}

 

사용:

uint8 RxBuffer[8];

ProcessData(RxBuffer);

 

설명:

RxBuffer는 배열
함수에 전달될 때 첫 번째 요소 주소 전달
함수 내부에서는 포인터로 사용

 

즉, 배열과 포인터가 만나는 지점이다.

 

정리

 

배열은 여러 데이터를 저장하는 공간이다.
포인터는 주소를 저장하는 변수다.
배열 이름은 특정 상황에서 첫 요소 주소처럼 동작한다.
그래서 비슷해 보이지만 실제로는 다르다.
실무에서는 배열과 포인터를 함께 사용한다.

반응형