C언어 배열과 포인터, 이것만 알면 끝! 💡 개념부터 활용까지 쉽게 배우기
C언어를 배우다 보면 가장 어렵다고 느끼는 개념 중 하나가 바로 **'배열(Array)'**과 **'포인터(Pointer)'**입니다. 이 두 개념은 서로 긴밀하게 연결되어 있어 더욱 헷갈리게 느껴질 수 있죠. 하지만 C언어의 강력함은 바로 이 배열과 포인터에서 나온다고 해도 과언이 아닙니다.
오늘은 **2025년 최신 기준**으로 **배열과 포인터가 무엇인지, 왜 중요한지, 그리고 이 둘이 어떻게 긴밀하게 연결되어 사용되는지**를 그림과 쉬운 예시 코드를 통해 명확하게 설명해 드리겠습니다. 이 글을 통해 C언어의 핵심 개념을 확실하게 잡고 더 깊은 프로그래밍의 세계로 나아가세요!
---🌟 1. 배열 (Array): 값을 담는 연속된 상자들
배열은 **같은 종류의 데이터를 여러 개 한꺼번에 저장할 수 있는 공간**입니다. 쉽게 말해, 옆으로 쭉 이어진 **'칸막이 없는 서랍장'**이나 **'연속된 사물함'**이라고 생각할 수 있습니다.
배열의 특징
- **동일한 자료형:** 배열 안에는 오직 한 가지 종류의 데이터(예: 정수만, 문자만)만 저장할 수 있습니다.
- **연속된 메모리 공간:** 배열의 요소들은 메모리 상에 빈틈없이 연속적으로 저장됩니다. 이것이 포인터와 연결되는 중요한 지점입니다.
- **인덱스(Index) 사용:** 각 칸에는 0부터 시작하는 고유한 번호(인덱스)가 붙어 있어, 이 번호를 통해 원하는 칸의 데이터에 접근할 수 있습니다.
예시 코드: 배열 선언 및 사용
#include <stdio.h>
int main() {
// 5개의 정수를 저장할 수 있는 배열 선언
int scores[5];
// 배열에 값 저장
scores[0] = 90; // 첫 번째 칸 (인덱스 0)
scores[1] = 85; // 두 번째 칸 (인덱스 1)
scores[2] = 70;
scores[3] = 95;
scores[4] = 80; // 마지막 칸 (인덱스 4)
// 배열의 값 출력
printf("첫 번째 점수: %d\n", scores[0]);
printf("세 번째 점수: %d\n", scores[2]);
// 반복문을 이용한 전체 출력
printf("모든 점수: ");
for (int i = 0; i < 5; i++) {
printf("%d ", scores[i]);
}
printf("\n");
return 0;
}
위 코드에서 `scores[5]`는 `scores[0]`부터 `scores[4]`까지 총 5개의 정수 공간을 의미합니다.

▲ 그림 1: 배열이 메모리에 연속적으로 저장되는 모습 (예시)
✨ 2. 포인터 (Pointer): 메모리 주소를 가리키는 손가락
포인터는 **메모리 주소를 저장하는 특별한 변수**입니다. 컴퓨터 메모리는 모든 데이터가 저장되는 거대한 아파트 단지와 같고, 각 방에는 고유한 **'주소'**가 있죠. 포인터는 바로 이 방의 주소를 가리키는 **'손가락'** 또는 **'내비게이션'**이라고 생각하면 이해하기 쉽습니다.
포인터의 특징
- **주소를 저장:** 일반 변수가 값을 저장하는 것과 달리, 포인터 변수는 다른 변수의 메모리 주소를 저장합니다.
- **주소 연산자 (`&`):** 변수 앞에 `&`를 붙이면 해당 변수의 메모리 주소를 얻을 수 있습니다. (예: `&num`은 `num` 변수의 주소)
- **역참조 연산자 (`*`):** 포인터 변수 앞에 `*`를 붙이면 포인터가 가리키는 **주소에 저장된 실제 값**을 얻을 수 있습니다. (예: `*ptr`은 `ptr`이 가리키는 곳의 값)
- **자료형:** 포인터는 자신이 가리킬 값의 자료형을 명시해야 합니다. (예: `int *ptr;`은 정수형 변수의 주소를 저장하는 포인터)
예시 코드: 포인터 선언 및 사용
#include <stdio.h>
int main() {
int num = 10; // 정수형 변수 num 선언 및 초기화
int *ptr; // 정수형 변수의 주소를 저장할 포인터 ptr 선언
ptr = # // num 변수의 주소를 ptr에 저장
printf("num의 값: %d\n", num); // 10
printf("num의 주소: %p\n", &num); // 예: 0x7ffee5c01b1c (주소는 실행마다 다름)
printf("ptr의 값 (num의 주소): %p\n", ptr); // 예: 0x7ffee5c01b1c (num의 주소와 동일)
printf("ptr이 가리키는 값: %d\n", *ptr); // 10 (num의 값과 동일)
*ptr = 20; // ptr이 가리키는 곳 (즉, num)의 값을 20으로 변경
printf("num의 변경된 값: %d\n", num); // 20
return 0;
}
포인터 `ptr`을 통해 변수 `num`의 값을 읽고 변경할 수 있습니다. 이것이 포인터의 핵심적인 역할입니다.
🤝 3. 배열과 포인터, 뗄레야 뗄 수 없는 관계
C언어에서 배열과 포인터는 매우 밀접하게 관련되어 있습니다. 사실상 **배열의 이름 자체가 그 배열의 시작 주소를 가리키는 포인터처럼 사용될 수 있습니다.**
핵심 관계
- **배열 이름 = 첫 번째 요소의 주소:** 배열의 이름은 그 배열의 첫 번째 요소(인덱스 0)의 메모리 주소를 나타냅니다.
int arr[3] = {10, 20, 30}; printf("arr의 주소: %p\n", arr); // 배열 전체의 시작 주소 printf("arr[0]의 주소: %p\n", &arr[0]); // 첫 번째 요소의 주소 // 두 주소는 동일하게 출력됩니다.
- **포인터로 배열 요소 접근:** 포인터를 사용하여 배열의 요소에 접근할 수 있습니다.
int arr[3] = {10, 20, 30}; int *ptr = arr; // ptr이 arr의 시작 주소를 가리킴 (ptr = &arr[0]과 같음) printf("첫 번째 요소: %d\n", *ptr); // *ptr == arr[0] printf("두 번째 요소: %d\n", *(ptr + 1)); // *(ptr + 1) == arr[1] printf("세 번째 요소: %d\n", *(ptr + 2)); // *(ptr + 2) == arr[2]

▲ 그림 2: 배열 이름이 첫 번째 요소의 주소를 가리키는 모습
왜 이렇게 연결될까요?
배열의 요소들이 메모리에 **연속적으로 저장**되기 때문입니다. 배열의 시작 주소만 알면, 각 요소의 자료형 크기만큼 주소를 더해가면서 다른 요소들에 쉽게 접근할 수 있습니다. 이것이 포인터 연산의 핵심 원리입니다.
이러한 특성 덕분에 C언어에서는 **배열을 다룰 때 포인터를 활용하면 더 효율적이고 유연한 코드 작성**이 가능해집니다.
---🚀 배열과 포인터, 언제 어떻게 활용할까?
배열과 포인터는 C언어에서 다양한 방식으로 활용됩니다.
- **함수에 배열 전달:** 함수에 배열을 인자로 전달할 때, 실제 배열 전체가 복사되는 것이 아니라 배열의 시작 주소(포인터)가 전달됩니다. 이는 메모리 효율성을 높입니다.
void printArray(int *arr, int size) { // 배열의 시작 주소와 크기를 받음 for (int i = 0; i < size; i++) { printf("%d ", *(arr + i)); // 포인터 연산으로 요소 접근 } printf("\n"); } int main() { int myNumbers[] = {10, 20, 30, 40, 50}; printArray(myNumbers, 5); // 배열 이름을 넘기면 시작 주소가 전달됨 return 0; }
- **동적 메모리 할당:** 프로그램 실행 중 필요한 만큼 메모리를 할당받아 사용할 때 포인터를 사용합니다. (malloc, calloc, realloc, free 함수)
- **문자열 처리:** C언어에서 문자열은 사실상 '문자 배열'이므로, 포인터를 이용한 문자열 처리가 빈번하게 사용됩니다.
- **연결 리스트, 트리 등 복잡한 자료구조 구현:** 메모리 상에 연속적이지 않은 데이터들을 서로 연결할 때 포인터가 필수적으로 사용됩니다.
마무리하며: 배열과 포인터, C언어의 핵심 역량! 🔑
C언어의 배열과 포인터는 처음에는 다소 어렵게 느껴질 수 있지만, 이 두 개념을 확실히 이해하면 C언어를 능숙하게 다룰 수 있는 강력한 기반을 마련하게 됩니다. **배열은 연속된 데이터 묶음이고, 포인터는 그 데이터 묶음의 '위치(주소)'를 가리키는 역할**을 한다고 기억하시면 됩니다.
특히 **배열 이름이 첫 번째 요소의 주소와 같다는 점**과 **포인터 연산을 통해 배열 요소를 효율적으로 접근할 수 있다는 점**을 명심하고, 다양한 예제 코드를 직접 작성하며 연습해 보는 것이 가장 중요합니다. 꾸준히 연습하다 보면 어느새 배열과 포인터가 친숙한 도구로 느껴질 것입니다. C언어 학습에 궁금한 점이 있다면 언제든지 댓글로 질문해주세요! 👇
'IT > c언어' 카테고리의 다른 글
C 언어 기초 강의 (13) | 2023.12.11 |
---|---|
C 언어의 if문: 설명과 사용예시 (5) | 2023.11.12 |
C 프로그램 작성과 컴파일 과정 (47) | 2023.11.03 |
C 언어의 개요와 특징 (50) | 2023.11.01 |