programing

size of ( )를 사용하지 않고 이 코드를 사용하여 어레이 크기를 결정하는 방법

goodsources 2022. 7. 17. 18:20
반응형

size of ( )를 사용하지 않고 이 코드를 사용하여 어레이 크기를 결정하는 방법

C인터뷰 질문을 몇 가지 해 본 결과, 「연산자 사이즈를 사용하지 않고 C에서 어레이 사이즈를 찾는 방법」이라고 하는 질문을 다음과 같은 해답으로 발견했습니다.작동하는데 왜 그런지 모르겠어요.

#include <stdio.h>

int main() {
    int a[] = {100, 200, 300, 400, 500};
    int size = 0;

    size = *(&a + 1) - a;
    printf("%d\n", size);

    return 0;
}

역시 5가 반환됩니다.

edit: 사람들이 이 대답을 지적했지만 구문이 조금 다릅니다. 즉, 색인화 방식입니다.

size = (&arr)[1] - arr;

그래서 저는 두 질문 모두 타당하고 문제에 대한 접근법이 약간 다르다고 생각합니다.많은 도움과 철저한 설명에 감사드립니다!

포인터에 1을 추가하면 포인트 투 타입(즉, 배열)의 오브젝트 시퀀스에서 다음 오브젝트의 위치가 됩니다. ifpint그 다음에 '''로, '''p + 1 int만약p int(식( 「」)은&a 、 。p + 1는, 의 다음의 5 슬롯 배열을 시퀀스로 포인트 합니다.

2개의 포인터를 감산하면(두 포인터가 같은 어레이 오브젝트를 가리키거나 1개가 어레이의 마지막 요소를 가리키고 있는 경우), 이러한 2개의 포인터 사이에 있는 오브젝트(어레이 요소)의 수가 산출됩니다.

.&aa , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,int (*)[5]의 어레이로 구성된 )int라는 식입니다.&a + 1는, 의 5 .inta , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 이 .int (*)[5].표현*(&a + 1)를 부정하다&a + 1int의 요소에 a , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .int [5]에서는 '를 '감쇠'로int *.

표현은 '아예'입니다.a첫 " 유형 "decays"를 int *.

사진은 다음과 같은 이점이 있습니다.

int [5]  int (*)[5]     int      int *

+---+                   +---+
|   | <- &a             |   | <- a
| - |                   +---+
|   |                   |   | <- a + 1
| - |                   +---+
|   |                   |   |
| - |                   +---+
|   |                   |   |
| - |                   +---+
|   |                   |   |
+---+                   +---+
|   | <- &a + 1         |   | <- *(&a + 1)
| - |                   +---+
|   |                   |   |
| - |                   +---+
|   |                   |   |
| - |                   +---+
|   |                   |   |
| - |                   +---+
|   |                   |   |
+---+                   +---+

의 두 왼쪽은 5개의 엘리먼트 어레이로 구성되어 있습니다.int'으로 있어요.int이치노

주의해 주세요.*(&a + 1)정의되지 않은 동작이 발생합니다.

...
결과가 배열 객체의 마지막 요소를 1개 지나갔을 경우, 평가되는 단항 * 연산자의 피연산자로 사용할 수 없습니다.

C 2011년 온라인 드래프트, 6.5.6/9

이 행은 가장 중요합니다.

size = *(&a + 1) - a;

보시는 바와 같이 우선 주소부터 입력해 주세요.a거기에 하나를 더합니다.그런 다음 포인터를 폐기하고 원래 값을 뺀다.a그것으로부터.

C의 포인터 산술에 의해 어레이 내의 요소 수가 반환됩니다.5. 1을 추가하고&a5의 다음 배열에 대한 포인터입니다.int뒤를 쫓다a그 후, 이 코드는 결과 포인터를 참조해, 뺄셈을 실시합니다.a(포인터로 축소된 배열 유형)에서 배열 내의 요소 수를 나타냅니다.

포인터 산술의 동작에 관한 상세:

포인터가 있다고 칩시다.xyz을 가리키다int값을 입력합니다.(int *)160에서 임의의 숫자를 빼면xyz, C는 실제 감산된 양을 지정합니다.xyz그 숫자에 가리키는 타입의 크기를 곱한 값입니다.예를 들어, 뺄셈을 하면5부터xyz, 의 가치xyz결과적으로xyz - (sizeof(*xyz) * 5)포인터 산술이 적용되지 않은 경우.

~하듯이a의 배열입니다.5 inttypes, 결과값은 5가 됩니다.단, 포인터에서는 동작하지 않고 어레이에서만 동작합니다.이것을 포인터로 시도하면 결과는 항상 다음과 같습니다.1.

다음은 주소와 정의되지 않은 방법을 보여 주는 간단한 예입니다.왼쪽에는, 다음의 주소가 표시됩니다.

a + 0 | [a[0]] | &a points to this
a + 1 | [a[1]]
a + 2 | [a[2]]
a + 3 | [a[3]]
a + 4 | [a[4]] | end of array
a + 5 | [a[5]] | &a+1 points to this; accessing past array when dereferenced

즉, 코드가 뺄셈을 하고 있습니다.a부터&a[5](또는a+5), 증정5.

이는 정의되지 않은 동작이므로 어떤 상황에서도 사용하지 마십시오.이 동작은 모든 플랫폼에서 일관성이 있을 것으로 예상하지 마십시오.또, 실가동 프로그램에서는 사용하지 말아 주세요.

음, 이건 C 초기엔 안 먹혔을 것 같아요.그래도 똑똑해.

한 번에 하나씩 단계를 수행합니다.

  • &aint[5] 유형의 객체에 대한 포인터를 가져옵니다.
  • +1이러한 오브젝트가 배열되어 있다고 가정하여 다음 오브젝트를 취득한다.
  • *해당 주소를 int에 대한 유형 포인터로 효과적으로 변환합니다.
  • -a는 2개의 int 포인터를 감산하여 이들 사이의 int 인스턴스 수를 반환합니다.

나는 그것이 완전히 합법적인지 확신할 수 없다(이것은 언어변호사 법률이다.실제로 효과가 없을 것이다).예를 들어, 포인터가 같은 배열의 요소를 가리킬 때만 포인터를 뺄 수 있습니다. *(&a+1)부모 배열이지만 다른 배열에 액세스하여 합성되었기 때문에 실제로는 같은 배열에 대한 포인터는 아닙니다.a또한 배열의 마지막 요소를 지나 포인터를 합성할 수 있으며 임의의 오브젝트를 1개의 요소의 배열로 취급할 수 있지만, 참조 조작은*이 경우 동작이 없어도 이 합성 포인터에서는 허용되지 않습니다.

아마도 C(K&R 구문, 누구 없나요?) 초기에는 어레이가 포인터로 훨씬 빨리 붕괴되었기 때문에*(&a+1)는 타입 int**의 다음 포인터 주소만 반환할 수 있습니다.최신 C++의 보다 엄격한 정의에서는 어레이 타입에 대한 포인터가 존재하고 어레이 크기를 알 수 있습니다.아마도 C 규격도 이에 준거하고 있을 것입니다.모든 C 함수 코드는 포인터를 인수로만 받아들이기 때문에 기술적인 가시적인 차이는 미미합니다.하지만 나는 여기서 추측하고 있을 뿐이다.

이러한 상세한 적법성 질문은 컴파일된 코드가 아닌 C 인터프리터 또는 보풀 타입의 툴에 적용됩니다.인터프리터는 어레이에 대한 포인터 배열로 2D 어레이를 구현할 수 있습니다.실장해야 할 런타임 기능이 하나 적기 때문입니다.이 경우 +1을 참조하면 치명적이며, 작동하더라도 잘못된 답을 얻을 수 있습니다.

또 다른 약점은 C 컴파일러가 외부 어레이를 정렬할 수 있다는 것입니다.이것이 5글자의 배열이라고 상상해 보세요.char arr[5]프로그램 실행 시)&a+1어레이의 배열 동작을 호출하고 있습니다.컴파일러는 5글자의 배열로 결정할 수 있습니다.char arr[][5]는, 실제로는 8 문자 배열로서 생성됩니다( ).char arr[][8]외측 어레이가 올바르게 정렬되도록 합니다.현재 설명되고 있는 코드는 어레이 크기를 5가 아닌 8로 보고합니다.특정 컴파일러가 반드시 이 작업을 수행할 것이라고 말하는 것은 아니지만 그럴 수도 있습니다.

언급URL : https://stackoverflow.com/questions/56154380/how-does-this-piece-of-code-determine-array-size-without-using-sizeof

반응형