Step by step

한 걸음 한 걸음 천천히

Programming Language/C Language

배열

개발자 까마귀 2024. 6. 8. 15:09
728x90

배열의 필요성

배열은 왜 필요한가?

int a0;
int a1;
int a2;
int a3;
int a4;

연속되는 데이터들을 만약 각각의 변수에 담게 된다면 데이터를 조작하기가 어려워진다.

배열

  • 배열(Array): 동일한 타입의 데이터를 여러 개 저장 가능한 자료구조
  • 원소(요소, element): 배열 안에 들어있는 각각의 데이터
  • 배열의 크기: 원소의 개수
  • 원소는 연속된 메모리에 저장되며, 정수형의 번호(index)를 사용하여 접근(access)
  • 인덱스(첨자, index, subscript): 배열 원소의 번호
    • 인덱스는 0부터 시작
  • 배열을 이용하면 여러 개의 값을 하나의 이름으로 다룰 수 있음
  • 배열 선언
    • int arr[10]

int - 원소의 자료형

arr - 배열의 이름

10 - 배열의 크기

배열 선언 예시

int score[10];         // 10개의 원소를 갖는 int형 배열 score
char src[10], dst[10]; // 2개의 문자형 배열 동시 선언(문자형 배열은 문자열에 쓰임)
int index, days[7]     // 일반 변수 index와 7개의 원소를 갖는 int 배열 days

배열의 원소 접근

score[5] = 80;         // score의 5번 원소는 80
score[1] = score[0];   // score 1번 원소는 score 0번 원소
score[i] = 100;        // score i번 원소는 100
score[i + 1] = 101;    // score i + 1번 원소는 101
score[index[i]] = 100; // score의 인덱스는 index의 i번 원소이며 score의 원소는 100

반복문

int score[5];
score[0] = 0;
score[1] = 0;
score[2] = 0;
score[3] = 0;
score[4] = 0;

#define SIZE 5
...
int score[SIZE];
...
for (int i = 0; i < SIZE; i++)
    score[i] = 0;

반복문을 통해 배열 사용 시 번거로움을 줄일 수 있음.

배열 입력

scanf("%d", &score[0]);
// 연산자 우선순위에 따라 &보다 [ ]가 더 높다.
// & = 주소 연산자, [ ] = 배열 인덱스

잘못된 인덱스

int score[5];

score[5] = 1; // 배열은 0부터 시작함.
// 0, 1, 2, 3, 4 → 인덱스 5를 참조하려하면 오류 발생

배열의 초기화

int score[5] = {1, 2, 3, 4, 5}; // 배열 "초기화" 시에만 중괄호({ }) 사용
int score[5] = {1, 2, 3}        // 부분 초기화: 일부 원소만 초기화 → 나머지는 모두 0 / NULL
int score[] = {1, 2, 3, 4, 5};
// 배열의 크기를 비워두면 초기화하는 원소의 개수만큼 컴파일러가 배열의 크기를 잡음

초기화되지 않은 배열

int score[5];
// score[0 ~ 4]는 모두 알 수 없는 미정된 값(undefined value)를 가짐

배열의 크기 계산

int score[ ] = {1, 2, 3, 4, 5, 6, 7};
...
size = sizeof score / sizeof score[0];
// 배열을 sizeof 할 시 배열의 크기 * 원소의 자료형의 크기
// 그렇기 때문에 원소의 자료형의 크기만큼 나눠줌

배열의 복사

int score1[5] = {1, 2, 3, 4, 5};
int score2[5];

score2 = score1; // 컴파일 에러, 배열의 이름은 상수 취급

int score1[SIZE] = {1, 2, 3, 4, 5};
int score2[SIZE];

...

for (int i = 0; i < SIZE; i++)
    score2[i] = score1[i];

배열의 비교

score1[SIZE] = {1, 2, 3, 4, 5};
score2[SIZE] = {1, 2, 3, 4, 5};

if (score1 == score2)
    printf("same");
else
    printf("diff");
// 배열의 이름끼리 비교할 수 없음, 틀린 표현

for (int i = 0; i < SIZE; i++)
    if (score1[i] != score2[i]) {
        printf("diff");
        return 0;
    } // 배열의 원소를 하나하나 비교하여야 함

배열과 함수

int f(int a[], int n);

...

f(arr, n);
// 함수 호출 시 배열의 첫 원소의 주소가 복사되어 전달 됨(배열의 원본이 간다는 것과 비슷한 의미), 포인터에서 다룸

int f(int a[], int n) { // 배열의 원본
    ...
}

함수의 매개변수로서 const 배열

void f(const int a[]); // 배열의 원소를 바꾸지 않음

배열과 정렬

배열과 정렬은 매우 밀접한 관계를 갖고 있다. 유관한 동일 자료형의 집합이라는 점에서 매우 유사한데, 간단한 정렬 알고리즘인 선택 정렬에 관해 다룬다.

// 선택 정렬(Selection Sort)
#include <stdio.h>
#define SIZE 5

void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; }

int main() {
    int arr[SIZE] = {5, 3, 2, 4, 1};
     
    for (int i = 0; i < SIZE - 1; i++) {
        int least = i;
        for (int j = i + 1; j < SIZE; i++)
            if (arr[least] > arr[j])
                least = j;
        swap(arr[least, arr[i]);
    }
    
    for (int  i = 0; i < SIZE; i++)
        printf("%d ", arr[i]);

    return 0;
}

정렬이 안 된 구간을 순회에서 최소값 / 최대값을 선택하여 구간의 첫 번째와 교환한다.

다차원 배열

2차원 이상의 배열을 다차원이라고 부른다. 이는 설명을 듣는 것보다 그림으로 보는 것이 훨씬 편리하다.

코드로 다차원 배열을 선언하는 방식 또한 매우 단순하다.

int _1d [5];
int _2d [5][5];
int _3d [5][5][5];

다차원 배열은 다루기가 까다로워 실제로 자주 쓰이진 않지만, 그나마 자주 쓰이는 것 중 하나인 2차원 배열에 관해 설명하자면, 첫 번째 [5]가 행을 뜻하며, 그 다음 [5]가 열을 뜻한다.

int arr[3][5] = {
    {0, 1, 2, 3, 4},
    {5, 6, 7, 8, 9},
    {10, 11, 12, 13, 14}
}; // OK - 3 * 5 크기의 배열

int arr[][5] = {
    {0, 1, 2, 3, 4},
    {5, 6, 7, 8, 9},
    {10, 11, 12, 13, 14}
}; // OK - 3 * 5 크기의 배열, 첫 번째 차원의 크기만 생략 가능

int arr[][10] = {
    {0, 1, 2, 3, 4},
    {5, 6, 7, 8, 9},
    {10, 11, 12, 13, 14}
}; // OK - 3 * 10 크기의 배열, 생략된 원소는 부분 초기화로 모두 0이 됨

첫 번째 차원의 크기만 생략이 가능한 까닭은 두 번째 차원부터는 배열의 형태를 컴파일러에게 넘겨주어 배열의 올바른 위치에 엑세스할 수 있도록 해주어야 하기 때문이다. 배열 전체의 크기는 컴파일러가 몰라도 되지만 각 차원의 배열 크기를 알아야 올바른 위치를 찾을 수 있다.

초기화

int arr[2][2] = {
    {1, 2},
    {3, 4}
};

int arr[][2] = {1, 2, 3, 4};

두 방법 모두 가능하다.

인덱스 접근

for (int i = 0; i < SIZE; i++)
    for (int j = 0; j < SIZE; j++)
        arr[i][j] = 1; // i = 행, j = 열

형식 인자

함수에서의 형식인자는 첫 번째 차원의 크기만 생략 가능하다.

int f(int arr[][SIZE][SIZE]); // 첫 번째 크기만 생략 가능
728x90

'Programming Language > C Language' 카테고리의 다른 글

포인터  (1) 2024.06.08
변수의 범위와 생존 시간  (1) 2024.06.07
변수와 함수(심화)  (1) 2024.06.07
함수  (0) 2024.06.06
반복문  (1) 2024.06.06