Namespaces
Variants

Array initialization

From cppreference.net

초기화 중인 객체가 배열 타입일 때, 초기자는 반드시 (선택적으로 중괄호로 둘러싸인) 문자열 리터럴 이거나 배열 멤버들을 위한 초기값들의 중괄호로 둘러싸인 목록이어야 합니다:

= string-literal (1)
= { expression , ... } (2) (C99 이전)
= { designator (선택적) expression , ... } (2) (C99 이후)
= { } (3) (C23 이후)
1) 문자 및 와이드 문자 배열을 위한 문자열 리터럴 초기화
2) 배열 요소에 대한 초기화자인 상수 (C99까지) 표현식들의 쉼표로 구분된 목록 , 선택적으로 [ constant-expression ] = 형태의 배열 지정자 사용 가능 (C99부터)
3) 빈 초기화자는 배열의 모든 요소를 빈 초기화합니다

알려진 크기의 배열과 알려지지 않은 크기의 배열은 초기화될 수 있습니다 , 하지만 VLA는 제외 (C99부터) (C23까지) . VLA는 빈 초기화만 가능합니다. (C23부터)

명시적으로 초기화되지 않은 모든 배열 요소는 empty-initialized 됩니다.

목차

문자열로부터의 초기화

문자열 리터럴 (선택적으로 중괄호로 둘러싸인)은 일치하는 타입의 배열에 대한 초기화자로 사용될 수 있습니다:

  • 일반 문자열 리터럴 및 UTF-8 문자열 리터럴 (C11부터) 은 모든 문자 타입의 배열을 초기화할 수 있습니다 ( char , signed char , unsigned char )
  • L-접두사 와이드 문자열 리터럴은 (cv-한정자 무시) wchar_t 와 호환되는 모든 타입의 배열을 초기화하는 데 사용될 수 있습니다
  • u-접두사 와이드 문자열 리터럴은 (cv 한정자를 무시하고) 호환 가능한 모든 타입의 배열을 초기화하는 데 사용될 수 있습니다 char16_t
  • U-접두사 와이드 문자열 리터럴은 (cv 한정자를 무시하고) 호환 가능한 모든 타입의 배열을 초기화하는 데 사용될 수 있습니다 char32_t
(C11부터)

문자열 리터럴의 연속된 바이트 또는 와이드 문자열 리터럴의 와이드 문자들(종료 널 바이트/문자를 포함)이 배열의 요소들을 초기화합니다:

char str[] = "abc"; // str은 char[4] 타입을 가지며 'a', 'b', 'c', '\0'을 저장함
wchar_t wstr[4] = L"猫"; // str은 wchar_t[4] 타입을 가지며 L'猫', '\0', '\0', '\0'을 저장함

배열의 크기가 알려진 경우, 문자열 리터럴의 크기보다 하나 작을 수 있으며, 이 경우 종료 널 문자는 무시됩니다:

char str[3] = "abc"; // str은 char[3] 타입을 가지며 'a', 'b', 'c'를 보유함

문자열 리터럴을 char * str = "abc" ; 로 직접 접근할 때와 달리, 이러한 배열의 내용은 수정 가능합니다.

중괄호로 둘러싸인 목록으로부터의 초기화

배열이 중괄호로 둘러싸인 초기화자 목록으로 초기화될 때, 목록의 첫 번째 초기화자는 인덱스 0의 배열 요소를 초기화합니다 (지정자가 명시되지 않은 경우) (C99부터) , 그리고 각 후속 초기화자 (지정자가 없는 경우) (C99부터) 는 이전 초기화자에 의해 초기화된 요소보다 하나 더 큰 인덱스의 배열 요소를 초기화합니다.

int x[] = {1,2,3}; // x는 int[3] 타입을 가지며 1,2,3을 보관함
int y[5] = {1,2,3}; // y는 int[5] 타입을 가지며 1,2,3,0,0을 보관함
int z[4] = {1}; // z는 int[4] 타입을 가지며 1,0,0,0을 보관함
int w[3] = {0}; // w는 int[3] 타입을 가지며 모두 0을 보관함

알려진 크기의 배열을 초기화할 때 요소 수보다 많은 초기화자를 제공하는 것은 오류입니다 (문자열 리터럴로 문자 배열을 초기화하는 경우는 제외).

지정자는 이후 초기화자가 지정자가 기술하는 배열 요소를 초기화하도록 합니다. 초기화는 지정자가 기술하는 요소 다음 요소부터 순서대로 계속 진행됩니다.

int n[5] = {[4]=5,[0]=1,2,3,4}; // holds 1,2,3,4,5
int a[MAX] = { // starts initializing a[0] = 1, a[1] = 3, ...
    1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
// for MAX=6,  array holds 1,8,6,4,2,0
// for MAX=13, array holds 1,3,5,7,9,0,0,0,8,6,4,2,0 ("sparse array")
(C99부터)

알 수 없는 크기의 배열을 초기화할 때, 초기화자가 지정된 가장 큰 첨자가 선언되는 배열의 크기를 결정합니다.

중첩 배열

배열의 요소가 배열, 구조체 또는 공용체인 경우, 중괄호로 묶인 초기화 목록에서 해당 멤버에 대한 유효한 초기화자는 다음과 같이 중괄호를 생략할 수 있다는 점을 제외하고 해당 멤버에 유효한 모든 초기화자입니다:

중첩된 초기화 리스트가 여는 중괄호로 시작하는 경우, 닫는 중괄호까지의 전체 중첩 초기화 리스트가 해당 배열 요소를 초기화합니다:

int y[4][3] = { // 각각 3개의 int를 가진 4개의 배열로 구성된 배열 (4x3 행렬)
    { 1 },      // 0번 행이 {1, 0, 0}으로 초기화됨
    { 0, 1 },   // 1번 행이 {0, 1, 0}으로 초기화됨
    { [2]=1 },  // 2번 행이 {0, 0, 1}으로 초기화됨
};              // 3번 행이 {0, 0, 0}으로 초기화됨

중첩된 초기화자가 여는 중괄호로 시작하지 않는 경우, 하위 배열, 구조체 또는 공용체의 요소나 멤버를 설명하기 위해 목록에서 충분한 초기화자만 가져옵니다. 남은 초기화자는 다음 배열 요소를 초기화하는 데 사용됩니다:

int y[4][3] = {    // 4개의 3개 int 배열로 구성된 배열 (4x3 행렬)
1, 3, 5, 2, 4, 6, 3, 5, 7 // 행 0이 {1, 3, 5}로 초기화됨
};                        // 행 1이 {2, 4, 6}로 초기화됨
                          // 행 2가 {3, 5, 7}로 초기화됨
                          // 행 3이 {0, 0, 0}로 초기화됨
struct { int a[3], b; } w[] = { { 1 }, 2 }; // 구조체 배열
   // { 1 }은 배열의 요소 #0에 대한 완전한 중괄호 초기화자로 간주됨
   // 해당 요소는 { {1, 0, 0}, 0}으로 초기화됨
   // 2는 배열의 요소 #1에 대한 첫 번째 초기화자로 간주됨
   // 해당 요소는 { {2, 0, 0}, 0}으로 초기화됨

배열 지정자는 중첩될 수 있습니다; 중첩된 배열을 위한 대괄호 안의 상수 표현식은 외부 배열을 위한 대괄호 안의 상수 표현식 뒤에 옵니다:

int y[4][3] = {[0][0]=1, [1][1]=1, [2][0]=1};  // row 0 initialized to {1, 0, 0}
                                               // row 1 initialized to {0, 1, 0}
                                               // row 2 initialized to {1, 0, 0}
                                               // row 3 initialized to {0, 0, 0}
(C99부터)

참고 사항

배열 초기자에서 부분식의 평가 순서 는 C에서 indeterminately sequenced입니다 (그러나 C++11 이후 C++에서는 그렇지 않음):

int n = 1;
int a[2] = {n++, n++}; // 지정되지 않았지만 명확히 정의된 동작,
                       // n이 두 번 증가됨 (임의의 순서로)
                       // a가 {1, 2} 또는 {2, 1}로 초기화되는 것 모두 유효함
puts((char[4]){'0'+n} + n++); // 정의되지 않은 동작:
                              // n의 증가와 읽기 연산이 순서가 지정되지 않음

C에서는 초기화자의 중괄호 목록이 비어 있을 수 없습니다. C++은 빈 목록을 허용합니다:

(until C23)

빈 초기화자를 사용하여 배열을 초기화할 수 있습니다:

(since C23)
int a[3] = {0}; // 블록 범위 배열을 0으로 초기화하는 유효한 C 및 C++ 방식
int a[3] = {}; // 블록 범위 배열을 0으로 초기화하는 유효한 C++ 방식; C23부터 C에서 유효

다른 모든 초기화 와 마찬가지로, 정적 또는 스레드 지역 저장 기간 을 가진 배열을 초기화할 때는 초기화 리스트의 모든 표현식이 상수 표현식 이어야 합니다:

static char* p[2] = {malloc(1), malloc(2)}; // 오류

예제

int main(void)
{
    // 다음 네 개의 배열 선언은 모두 동일합니다
    short q1[4][3][2] = {
        { 1 },
        { 2, 3 },
        { 4, 5, 6 }
    };
    short q2[4][3][2] = {1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 5, 6};
    short q3[4][3][2] = {
        {
            { 1 },
        },
        {
            { 2, 3 },
        },
        {
            { 4, 5 },
            { 6 },
        }
    };
    short q4[4][3][2] = {1, [1]=2, 3, [2]=4, 5, 6};
    // 열거형 상수와 문자 이름을 지정자를 사용한 배열로 연결할 수 있습니다:
    enum { RED, GREEN, BLUE };
    const char *nm[] = {
        [RED] = "red",
        [GREEN] = "green",
        [BLUE] = "blue",
    };
}

참고문헌

  • C17 표준 (ISO/IEC 9899:2018):
  • 6.7.9/12-39 초기화 (p: 101-105)
  • C11 표준 (ISO/IEC 9899:2011):
  • 6.7.9/12-38 초기화 (p: 140-144)
  • C99 표준 (ISO/IEC 9899:1999):
  • 6.7.8/12-38 초기화 (p: 126-130)
  • C89/C90 표준 (ISO/IEC 9899:1990):
  • 6.5.7 초기화