본문 바로가기
[R&D] 프로그래밍/C, C++

[C/C++] 배열이란? - 배열의 개념 및 기본 사용법

by Geuni 2022. 7. 28. 07:12
728x90
반응형

배열이란?

배열은 사전적 의미로 "일정한 차례나 간격에 따라 벌여 놓음"입니다.

프로그래밍에서의 배열도 자료형의 크기(간격)로 값을 연속적으로 나열한 것을 뜻합니다.

기본 사용 방법

선언 및 초기화

변수명에 대괄호 '[]'를 더하여 선언할 수 있으며, 대괄호 안에는 배열의 크기를 지정합니다.

char cVal[2];

하지만 배열의 크기를 지정하지 않고 선언도 가능한데 이때는 선언과 동시에 초기화를 하지 않으면 에러가 발생합니다.

선언과 동시에 초기화하는 방법은 중괄호 '{}' 사이에 배열의 크기만큼 값을 넣어주면 됩니다.

(초기화 방법은 크기를 지정해도 동일하게 적용됩니다.)

int iValT[] = {1, 2, 3, 4, 5};
int iVal[2] = {5, 6};

사용

배열은 선언 및 초기화를 완료했다면 인덱싱을 통해 사용이 가능합니다.

// Read
printf("iVal [0] : %d", iVal[0]);

// Write
iVal[0] = 15;

위와 같은 인덱싱이 아닌 배열의 주소 값을 사용해서도 접근이 가능합니다.


변수명 (주소)을 통한 사용 방법

배열의 특징은 '변수명'에 첫 번째 배열의 주소를 담고 있다는 것입니다.

배열은 메모리에 연속적으로 위치하고 있기 때문에 첫 번째 배열의 주소를 알고 있다면 '포인터 변수'처럼 주소값으로 접근(역참조)이 가능합니다.

 

아래의 예제 코드를 확인하기 전 포인터에 대한 기본 개념을 확인해 보면 쉽게 이해가 가능합니다.

[C/C++] 포인터(pointer)란? - 포인터의 기본 개념 (tistory.com)

 

[C/C++] 포인터(pointer)란? - 포인터의 기본 개념

포인터(Pointer) 란? 포인터 변수라고도 불리며 메모리의 주소 값을 저장하는 변수를 말합니다. 우리가 코딩을 할 때 사용하는 변수들은 값을 가지고 있는데, 이 변수들은 모두 특정 메모리에 위치

geuninote.tistory.com

예제) 주소값 확인 

#include <stdio.h>

int main(void)
{
    int iVal[2] = {5, 6};
    char cVal[2] = {1, 2};

    printf("iVal : %p / &iVal[0] : %p\n", iVal, &iVal[0]);
    
    printf("iVal [0] : %d / address : %p\n", iVal[0], &iVal[0]);
    printf("iVal [1] : %d / address : %p\n", iVal[1], &iVal[1]);

    printf("cVal [0] : %d / address : %p\n", cVal[0], &cVal[0]);
    printf("cVal [1] : %d / address : %p\n", cVal[1], &cVal[1]);
    
    return 0;
}
iVal : 0061FF18 / &iVal[0] : 0061FF18
iVal [0] : 5 / address : 0061FF18
iVal [1] : 6 / address : 0061FF1C
cVal [0] : 1 / address : 0061FF16
cVal [1] : 2 / address : 0061FF17

위 코드의 결과를 토대로 그림을 그려보면 아래와 같습니다.


이처럼 배열은 인덱스 없이 변수명만 호출하면 해당 배열의 주소(0번째의 주소)를 담고 있기 때문에 변수명과 역참조 연산자를 통해 배열 값에 접근이 가능합니다.

예제) 인덱싱과 역참조를 통한 접근

#include <stdio.h>
  
int main(void)
{
    int i;
    int iVal[6] = {100, 200, 300, 400, 500, 600};
    char cVal[6] = {1 ,2 ,3 ,4 ,5 ,6};

    for(i = 0; i < 6; i++)
    {
        printf("[ cVal[%d] : %d / *(cVal+i) : %d ] ", i, cVal[i], *(cVal+i));
        printf("[ iVal[%d] : %d / *(iVal+i) : %d ]\n", i, iVal[i], *(iVal+i));
    }
    return 0;
}
[ cVal[0] : 1 / *(cVal+i) : 1 ] [ iVal[0] : 100 / *(iVal+i) : 100 ]
[ cVal[1] : 2 / *(cVal+i) : 2 ] [ iVal[1] : 200 / *(iVal+i) : 200 ]
[ cVal[2] : 3 / *(cVal+i) : 3 ] [ iVal[2] : 300 / *(iVal+i) : 300 ]
[ cVal[3] : 4 / *(cVal+i) : 4 ] [ iVal[3] : 400 / *(iVal+i) : 400 ]
[ cVal[4] : 5 / *(cVal+i) : 5 ] [ iVal[4] : 500 / *(iVal+i) : 500 ]
[ cVal[5] : 6 / *(cVal+i) : 6 ] [ iVal[5] : 600 / *(iVal+i) : 600 ]

배열 사용시 주의사항)

 위 내용에서 확인한 것처럼 배열은 기본적으로 첫 번째의 주소값을 통해 값에 접근하기 때문에 '인덱싱', '역참조' 방식 모두 배열의 크기보다 큰 수를 넣게 되면 할당되지 않은 메모리에 접근할 수 있습니다. 이는 프로그램 동작에 큰 문제를 야기할 수 있습니다.
내가 다른 곳에서 사용하는 변수의 값을 강제로 바꿀 수도 있고(overwrite) 존재하지 않거나 보호받고 있는(read only 등) 메모리를 읽거나 쓰려다가 프로그램이 죽거나 비정상 동작할 수 있습니다.

 

728x90
반응형

댓글