programing

C/C++ 다차원 배열 초기화 시 크기 생략

cafebook 2023. 10. 15. 17:53
반응형

C/C++ 다차원 배열 초기화 시 크기 생략

제가 C/C++ 컴파일러에 대해 아는 것은 다차원 배열을 초기화하는 동안 내부 브레이스를 무시한다는 것입니다.

그럼, 당신은 할 수 없는거군요.

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

왜냐하면 컴파일러는 정확히 다음과 같이 볼 것이기 때문입니다.

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

이제 6 * 1, 3 * 2, 2 * 3, 1 * 6인지 아니면 다른 것인지 알 수 없습니다(이것은 부분 초기화 목록일 수 있지만 반드시 완전한 것은 아닙니다).

제 질문은, 왜 이것이 많은 컴파일러에서 작동하는가 하는 것입니다.

int myArray[][2] = { { 2 }, { 4, 5 }, { 4, 1 } };

컴파일러는 직관적으로 다음과 같이 봅니다.

int myArray[][2] = { { 2, 0 }, { 4, 5 }, { 4, 1 } };

교정기를 무시하지 않는다는 뜻입니다저는 지금까지 3개의 다른 컴파일러에 그것을 시도해보았고 모두 작동했습니다.

나는 "이것은 단지 컴파일러 의존적이다"라는 대답을 기대합니다.제가 표준에 접근할 수 없으니, 표준에서 답변 부탁드립니다.직감은 필요 없어요, 전 제 감정이 있어요.

다음은 K&R의 "The C Programming Language" 섹션 A8.7, 2판 219,220페이지입니다.

Aggregate는 구조 또는 배열입니다.Aggregate에 Aggregate 유형의 멤버가 포함되어 있으면 초기화 규칙이 재귀적으로 적용됩니다.브레이스는 초기화에서 다음과 같이 생략될 수 있습니다. 집합인 집합의 멤버에 대한 초기화자가 왼쪽 브레이스로 시작하는 경우 쉼표로 구분된 초기화자 목록에서 하위 집합의 멤버를 초기화합니다. 멤버보다 더 많은 초기화자가 있는 것은 잘못된 것입니다.그러나 하위 애그리게이트의 초기화자가 왼쪽 대괄호로 시작하지 않는 경우 목록의 요소만 하위 애그리게이트의 멤버를 고려하여 충분합니다. 나머지 멤버는 하위 애그리게이트가 속한 애그리게이트의 다음 멤버를 초기화할 수 있습니다.예를들면,

 int x[] = { 1, 3, 5 }; 

크기가 지정되지 않았기 때문에 x를 3개의 멤버로 구성된 1차원 배열로 선언하고 초기화합니다.

이니셜라이저가 3개 있습니다.

따라서 이 선을 감안하면

int myArray[][2] = { { 2 }, { 4, 5 }, { 4, 1 } };

컴파일러는 각 서브어레이가 왼쪽 대괄호로 시작하고 필요한 초기화기의 수 이상이 없다는 점에 주목하여 어레이를 재귀적으로 초기화하고 서브어레이의 수를 카운트하여 어레이의 첫 번째 차원을 결정합니다.

다음은 K&R의 "The C Programming Language" 섹션 A8.7, 제2판 220페이지에서 나온 것입니다.

float y[4][3] = {
    { 1, 3, 5 },    
    { 2, 4, 6 },
    { 3, 5, 7 }
};

화된 는 브래킷 입니다입니다.1,3그리고.5합니다.y[0],y[0][0],y[0][1],그리고.y[0][2]두도 마찬가지로 됩니다. 됩니다.y[1]그리고.y[2] 의 가 됩니다y[3]다로 됩니다.0 수 . 정확히 동일한 효과를 얻을 수 있었습니다.

float y[4][3] = {
   1, 3, 5, 2, 4, 6, 3, 5, 7 
};

두 경우 모두 배열의 네 번째 행은 충분한 초기화기가 지정되지 않았으므로 0으로 초기화됩니다.

float y[4][3] = { 
    { 1 }, { 2 }, { 3 }, { 4 } 
};

합니다의 첫 합니다.y그리고 나머지는 남깁니다.0.

그래서 컴파일러는 내부 교정기를 무시하지 않습니다.그러나 공백이 없는 순서로 모든 초기화자를 지정하는 경우 내부 가새는 선택 사항입니다.전체 초기화자 집합을 지정하지 않으려면 내부 브레이스를 사용하여 초기화를 더 잘 제어할 수 있습니다.

다음은 K&R의 "The C Programming Language" A8.7, 2판 220페이지

float y[4][3] = {
    { 1, 3, 5 },    
    { 2, 4, 6 },
    { 3, 5, 7 }
};

와 동치입니다.

float y[4][3] = {
   1, 3, 5, 2, 4, 6, 3, 5, 7 
};

두 경우 모두 배열의 네 번째 행은 충분한 초기화기가 지정되지 않았으므로 0으로 초기화됩니다.

float y[4][3] = { 
    { 1 }, { 2 }, { 3 }, { 4 } 
};

y의 첫 번째 열을 초기화하고 나머지 0을 남깁니다.

그래서 컴파일러는 내부 교정기를 무시하지 않습니다.그러나 공백이 없는 순서로 모든 초기화자를 지정하는 경우에는 내부 가새가 필요하지 않습니다.전체 초기화자 집합을 지정하지 않으려면 내부 브레이스를 사용하면 초기화를 더 잘 제어할 수 있습니다.

어레이의 초기화를 이해하는 데 도움이 되는 C 표준의 몇 가지 인용문은 다음과 같습니다.

20 집합이나 조합이 집합이나 조합인 요소나 조합을 포함하는 경우에는 하위 집합이나 포함된 조합에 재귀적으로 적용합니다.부분 집합체 또는 포함된 결합의 초기화자가 왼쪽 가새로 시작하는 경우 해당 가새와 일치하는 오른쪽 가새로 둘러싸인 초기화자는 부분 집합체 또는 포함된 결합의 요소 또는 구성원을 초기화합니다.그렇지 않으면 하위 집합의 요소 또는 멤버 또는 포함된 결합의 첫 번째 멤버를 고려할 수 있는 충분한 초기화자만 목록에서 선택됩니다. 나머지 초기화자는 현재 하위 집합 또는 포함된 결합이 속한 결합의 다음 요소 또는 결합의 멤버를 초기화하기 위해 남겨집니다.

21 대괄호로 둘러싸인 목록에 있는 초기화자의 수가 집합체의 원소나 구성원의 수보다 적거나, 집합체의 크기가 알려진 배열의 초기화에 사용되는 문자열 리터럴에 있는 문자의 수가 집합체의 원소의 수보다 적을 경우, 집합체의 나머지는 정적 저장 기간을 갖는 객체와 암묵적으로 동일하게 초기화되어야 합니다.

22 크기를 알 수 없는 배열을 초기화하는 경우, 그 크기는 명시적인 초기화기를 가진 가장 큰 색인화된 요소에 의해 결정됩니다.배열 유형은 이니셜라이저 목록의 끝에서 완료됩니다.

그리고 여기 표준의 예시가 있습니다.

int y[4][3] = {
    { 1, 3, 5 },
    { 2, 4, 6 },
    { 3, 5, 7 },
};

는 완전한 괄호 형태의 초기화를 가진 정의입니다. 1, 3, 5는 y의 첫 번째 행(어레이 객체[0]), 즉 y[0], y[0], y[1], y[0][2]를 초기화합니다.마찬가지로 다음 두 줄도 y[1]과 y[2]를 초기화합니다.초기화기가 일찍 끝나므로 sy[3]는 0으로 초기화됩니다.정확히 동일한 효과를 얻을 수 있었습니다.

int y[4][3] = {
    1, 3, 5, 2, 4, 6, 3, 5, 7
};

y[0]의 이니셜라이저는 왼쪽 대괄호로 시작하지 않으므로 목록에서 세 개의 항목이 사용됩니다.마찬가지로 다음 세 가지는 y[1] 및 y[2]에 대해 연속적으로 취합니다.

ANSCI C-89(3.5.7)는 다음과 같이 말합니다.

float y[4][3] = {
    { 1, 3, 5 },
    { 2, 4, 6 },
    { 3, 5, 7 },
};

는 완전한 괄호 형태의 초기화를 가진 정의입니다. 1, 3 및 5는 배열 개체의 첫 번째 행을 초기화합니다.y[0]()y[0][0],y[0][1]그리고.y[0][2]). 마찬가지로 다음 두 줄이 초기화됩니다.y[1]그리고.y[2]. 이니셜라이저가 일찍 끝나니까요.y[3]0으로 초기화됩니다.정확히 동일한 효과를 얻을 수 있었습니다.

float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };

의 이니셜라이저.y[0]왼쪽 대괄호로 시작하지 않으므로 목록에서 세 개의 항목이 사용됩니다.마찬가지로, 다음 세 가지는 다음과 같이 연속적으로 다음과 같습니다.y[1]그리고.y[2].또한.

float z[4][3] = {
    { 1 }, { 2 }, { 3 }, { 4 }
};

첫번째 열을 초기화합니다.z지정한 대로 나머지를 0으로 초기화합니다.

제 생각에, 이 장은 관련이 있습니다.

8.5.1 골재

(...)

다차원 배열을 초기화할 때, 초기화기-클라우스는 배열의 마지막(가장 오른쪽) 인덱스가 가장 빠르게 변화하는 요소를 초기화합니다(8.3.4). [예:

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

이니셜라이즈x[0][0]3까지,x[0][1]1까지,x[1][0]4까지, 그리고x[1][1]2로. 반면에.

float y[4][3] = {
    { 1 }, { 2 }, { 3 }, { 4 }
};

y의 첫 번째 열(2차원 배열로 regarded)을 초기화하고 나머지 열은 0으로 유지합니다.—끝 예제 ]

양식에 대한 선언문에

T x = { a };

괄호는 다음과 같이 initializer-list에서 생략할 수 있습니다.105 initializer-list가 왼쪽 괄호로 시작하는 경우 쉼표로 구분된 initializer-list는 하위 집합의 멤버를 초기화합니다. 멤버보다 initializer-class가 더 많다는 것은 잘못된 것입니다.그러나 하위 애그리게이트에 대한 초기화자-목록이 왼쪽 대괄호로 시작하지 않는 경우 목록에서 하위 애그리게이트의 멤버를 초기화할 수 있는 초기화자-절만 사용됩니다. 나머지 초기화자-절은 현재 하위 애그리게이트가 멤버인 애그리게이트의 다음 멤버를 초기화할 수 있도록 남아 있습니다.[ 예:

float y[4][3] = {
    { 1, 3, 5 },
    { 2, 4, 6 },
    { 3, 5, 7 },
};

는을 초기화합니다. 1, 3, 5 는합니다.y[0],y[0][0],y[0][1],그리고.y[0][2]두도 마찬가지로 됩니다. 됩니다.y[1]그리고.y[2] .y[3]즉, s 는 float (), , 0.0 으로됩니다.위에서는 initializer-list initializer-list는 initializer-list다와 를 갖습니다.

float y[4][3] = {
    1, 3, 5, 2, 4, 6, 3, 5, 7
};

초기화기 y는 왼쪽 대괄호로 시작하지만 y[0]의 경우에는 그렇지 않으므로 목록의 세 요소가 사용됩니다. 세 다에 으로 취합니다.y[1]그리고.y[2] —끝 예제 ]

언어 사양에는 배열 초기화 시 "지정되지 않은 필드는 0이 됩니다"라고 명시되어 있습니다.

섹션 8.5: n3337 버전의 C++11 표준 7항:

목록에 있는 초기화자-조항이 집합체에 있는 구성원보다 적을 경우, 명시적으로 초기화되지 않은 각 구성원은 빈 초기화자 목록에서 초기화되어야 합니다(8.5.4). [예:

struct S { int a; const char* b; int c; };
S ss = { 1, "asdf" };

ss.a를 1로, s.b를 "asdf"로, ss.c를 (), 형식의 값으로 초기화합니다. 즉, 0. — 끝 예제 ]

언급URL : https://stackoverflow.com/questions/22346426/omitting-sizes-while-initializing-c-c-multidimensional-arrays

반응형