C 배열 완전 정복: 선언, 초기화, 접근, 다차원, 함수 전달, 포인터 관계
배열은 동일 타입 요소의 연속된 메모리 집합입니다. C에서 배열의 선언, 초기화, 메모리 레이아웃, 함수 전달, 포인터와의 관계까지 실무 관점에서 정리합니다.
배열 선언
타입 이름[크기]; // 크기: 상수 표현식 (C99 이전)
타입 이름[상수표현식]; // C99: VLA(가변 길이 배열) 지원 - 런타임 크기 가능
예시
int scores[100]; // 고정 크기 100
double prices[50];
char name[32];
int n = 10;
int vla[n]; // C99 VLA (스택 할당, 큰 크기 주의)
배열 초기화
// 1. 선언 시 초기화 (중괄호)
int arr[5] = {10, 20, 30, 40, 50};
// 2. 크기 생략 → 초기값 개수만큼 자동 할당
int arr[] = {1, 2, 3, 4, 5}; // 크기 5
// 3. 부분 초기화 → 나머지는 0 초기화
int arr[10] = {1, 2, 3}; // arr[3]~arr[9] = 0
// 4. 지정 초기화자 (C99) - 순서 무관, 중복 시 나중 값
int arr[10] = {[0]=1, [5]=10, [9]=100};
int arr[] = {[2]=5, [0]=1}; // 크기 3: {1, 0, 5}
// 5. 문자열로 char 배열 초기화
char str[] = "Hello"; // {'H','e','l','l','o','\0'} 크기 6
char str[10] = "Hi"; // {'H','i','\0',0,0...} 크기 10
배열 요소 접근
int arr[5] = {10, 20, 30, 40, 50};
printf("%d\n", arr[0]); // 10 (첫 요소)
printf("%d\n", arr[4]); // 50 (마지막 요소)
arr[2] = 300; // 수정
// arr[5] = 100; // 위험: 버퍼 오버플로
배열과 포인터의 관계 (핵심)
| 표현 | 타입 | 값 | 주소 연산 & |
arr | int * (첫 요소 주소로 자동 변환) | &arr[0] | &arr은 int (*)[5] (배열 전체 주소) |
&arr[0] | int * | 첫 요소 주소 | - |
arr + i | int * | &arr[i] | - |
*(arr + i) | int | arr[i] | - |
차이점: 배열 vs 포인터
int arr[10];
int *ptr = arr;
sizeof(arr) // 40 (배열 전체 크기: 10 * 4)
sizeof(ptr) // 8 (포인터 크기, 64비트)
&arr // int (*)[10] - 배열 타입 포인터
&ptr // int ** - 포인터의 포인터
// arr = ptr; // 에러: 배열은 lvalue가 아님 (수정 불가)
// ptr = arr; // OK: 포인터에 배열 주소 대입
다차원 배열
2차원 배열
int matrix[3][4]; // 3행 4열, 총 12개 int
// 초기화
int mat[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
// 부분 초기화
int mat[3][3] = {{1}, {2, 3}}; // {{1,0,0}, {2,3,0}, {0,0,0}}
// 접근
mat[row][col] // 행 우선 저장 (Row-major)
*(mat[row] + col)
*(*(mat + row) + col)
메모리 레이아웃
연속된 1차원 배열로 저장: mat[0][0], mat[0][1], ..., mat[0][3], mat[1][0], ...
가변 길이 2차원 배열 (C99 VLA)
void process(int rows, int cols) {
int matrix[rows][cols]; // 스택 할당, 큰 크기 시 스택 오버플로 주의
// ...
}
배열과 함수
배열을 매개변수로 전달
배열을 통째로 반환 불가 (포인터 반환은 가능: 정적/동적 할당/구조체 래핑)
배열 대입 불가: arr1 = arr2 에러
복사하려면 memcpy, 루프, struct 래핑 활용
구조체로 배열 감싸기 (값 전달/반환 가능)
typedef struct { int data[10]; size_t len; } IntArray;
IntArray create_array() {
IntArray a = {.len = 10};
for (size_t i = 0; i < a.len; i++) a.data[i] = i * i;
return a; // 값 복사 반환 가능
}
배열 포인터 vs 포인터 배열
int (*arr_ptr)[10]; // 10개 int 배열에 대한 포인터 (배열 포인터)
int *ptr_arr[10]; // int 포인터 10개 배열 (포인터 배열)
// 배열 포인터 활용: 2차원 배열 행 단위 접근
int mat[3][4];
int (*row_ptr)[4] = mat; // mat 첫 행 주소
row_ptr++; // 다음 행으로 이동 (16바이트 이동)
문자열과 배열
char str[] = "hello"; → 수정 가능 배열 (스택)
char *str = "hello"; → 읽기 전용 리터럴 가리킴 (수정 시 UB)
문자열 함수: strlen, strcpy, strcat, strcmp, strchr, strstr (<string.h>)
모범 사례
크기 상수화: #define MAX 100 또는 enum { MAX = 100 };
배열 크기 매크로: #define ARRAY_LEN(arr) (sizeof(arr)/sizeof((arr)[0])) (포인터엔 동작 안 함)
경계 검사 루틴화: assert(i < n), 안전한 래퍼 함수
큰 배열은 동적 할당(malloc) 또는 정적 저장 기간 사용 (스택 한계 회피)
VLA 사용 자제: 스택 오버플로 위험, C11에서 선택 사항으로 변경
C 언어
-
C# 배열 마스터하기: 선언, 초기화, 조작과 LINQ 연산
-
C# 가변 배열(Jagged Array): 선언, 초기화, 접근 완전 가이드
-
C++ 배열을 함수에 전달하는 방법: 실전 가이드
-
C 언어에서 1차원 및 2차원 배열을 함수에 전달하는 방법 – 실전 가이드
-
C 언어에서 배열과 포인터의 관계 이해하기
-
Java 배열 복사 기법: 대입, 루프, System.arraycopy, Arrays.copyOfRange 총정리
-
C++ 배열 완전 정복: 선언, 초기화, 포인터 기법
-
C++ 동적 배열 할당 완벽 가이드: new, delete, 실전 코드 예제
-
Java 배열 튜토리얼: 선언, 생성, 초기화와 예제 코드
-
MATLAB: 다차원 배열과 특수 배열 마스터하기
-
Java 배열 마스터하기: 효율적인 데이터 처리를 위한 종합 가이드
Java는 배열이라는 데이터 구조를 제공하며, 이는 같은 타입의 요소들을 고정된 크기의 순차적 컬렉션으로 저장합니다. 배열은 데이터 컬렉션을 저장하는 데 사용되지만, 같은 타입의 변수 컬렉션으로 생각하는 것이 더 유용합니다.
number0, number1, ..., number99 같은 개별 변수들을 선언하는 대신, numbers 같은 하나의 배열 변수를 선언하고 numbers[0], numbers[1], ..., numbers[99]로 개별 변수들을 표현합니다.
이 튜토리얼에서는 배열 변수 선언, 배열 생성, 인덱스 변수를 사
-
C# 배열 마스터하기: 효율적 데이터 저장과 접근
배열(Array)은 같은 타입의 요소를 고정된 크기로 순차적으로 저장하는 컬렉션입니다. 배열은 데이터를 저장하는 용도뿐 아니라, 동일한 타입의 변수들이 연속된 메모리 위치에 저장된 집합으로 생각하는 것이 더 유용합니다.
개별 변수(number0, number1, ..., number99)를 선언하는 대신, 하나의 배열 변수(numbers)를 선언하고 numbers[0], numbers[1], ..., numbers[99]로 개별 요소에 접근합니다. 특정 요소는 인덱스(Index)로 접근합니다.
모든 배열은 연속된 메모리 위치로