[c] ‘sizeof'(배열을 가리키는 포인터)를 찾는 방법은 무엇입니까?

먼저 다음은 몇 가지 코드입니다.

int main()
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

ptr(32 비트 시스템에서 4 바이트 인 크기를 제공하는 대신) 가리키는 배열의 크기를 찾는 방법이 있습니까?



답변

아냐, 못해 컴파일러는 포인터가 무엇을 가리키는 지 모릅니다. 알려진 대역 외 값으로 배열을 끝내고 해당 값까지 크기를 세는 것과 같은 트릭이 있지만 사용하지는 않습니다 sizeof().

또 다른 트릭은 Zan이 언급 한 것으로 , 크기를 어딘가에 숨길 수 있습니다. 예를 들어 배열을 동적으로 할당하는 경우 필요한 것보다 1 int 큰 블록을 할당하고 첫 번째 int의 크기를 숨기고 ptr+1배열의 포인터로 반환 하십시오. 크기가 필요할 때 포인터를 줄이고 숨김 값을 살펴보십시오. 배열 만이 아니라 처음부터 전체 블록을 해제해야합니다.


답변

내 대답은 아니오 야.”

C 프로그래머가하는 일은 배열의 크기를 어딘가에 저장하는 것입니다. 구조의 일부이거나 프로그래머가 malloc()배열 시작 전에 길이 값을 저장하기 위해 요청한 것보다 비트 및 더 많은 메모리를 속일 수 있습니다 .


답변

동적 배열 ( malloc 또는 C ++ new) )의 경우 다른 사람들이 언급 한 것처럼 배열의 크기를 저장하거나 추가, 제거, 계산 등을 처리하는 배열 관리자 구조를 구축해야합니다. 불행히도 C는 거의 수행하지 않습니다. C ++은 기본적으로 저장하는 각 배열 유형마다 빌드해야하기 때문에 관리해야 할 여러 유형의 배열이있는 경우 번거 롭습니다.

예제와 같은 정적 배열의 경우 크기를 얻는 데 사용되는 일반적인 매크로가 있지만 매개 변수가 실제로 정적 배열인지 확인하지 않으므로 권장 하지 않습니다. 매크로는 실제 코드에서 사용됩니다. 예를 들어 Linux 커널 헤더에서는 아래와 약간 다를 수 있습니다.

#if !defined(ARRAY_SIZE)
    #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
#endif

int main()
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", ARRAY_SIZE(days));
    printf("%u\n", sizeof(ptr));
    return 0;
}

이와 같은 매크로에주의 해야하는 이유로 Google을 사용할 수 있습니다. 조심해.

가능하면 훨씬 안전하고 사용하기 쉬운 벡터와 같은 C ++ stdlib.


답변

sizeof () 를 사용하지 않고 C ++ 템플릿을 사용하는 깨끗한 솔루션이 있습니다 . 다음 getSize () 함수는 정적 배열의 크기를 반환합니다.

#include <cstddef>

template<typename T, size_t SIZE>
size_t getSize(T (&)[SIZE]) {
    return SIZE;
}

다음은 foo_t 구조 의 예입니다 .

#include <cstddef>

template<typename T, size_t SIZE>
size_t getSize(T (&)[SIZE]) {
    return SIZE;
}

struct foo_t {
    int ball;
};

int main()
{
    foo_t foos3[] = {{1},{2},{3}};
    foo_t foos5[] = {{1},{2},{3},{4},{5}};
    printf("%u\n", getSize(foos3));
    printf("%u\n", getSize(foos5));

    return 0;
}

산출:

3
5


답변

이 특정 예제의 경우 typedef를 사용하는 경우 (아래 참조) 있습니다. 물론 이렇게하면 포인터가 무엇을 가리키는 지 알기 때문에 SIZEOF_DAYS를 사용하는 것이 좋습니다.

malloc () 등에 의해 리턴 된 것처럼 (void *) 포인터가 있다면, 아니오, 포인터가 가리키는 데이터 구조를 판별 할 방법이 없으므로 그 크기를 결정할 방법이 없습니다.

#include <stdio.h>

#define NUM_DAYS 5
typedef int days_t[ NUM_DAYS ];
#define SIZEOF_DAYS ( sizeof( days_t ) )

int main() {
    days_t  days;
    days_t *ptr = &days;

    printf( "SIZEOF_DAYS:  %u\n", SIZEOF_DAYS  );
    printf( "sizeof(days): %u\n", sizeof(days) );
    printf( "sizeof(*ptr): %u\n", sizeof(*ptr) );
    printf( "sizeof(ptr):  %u\n", sizeof(ptr)  );

    return 0;
} 

산출:

SIZEOF_DAYS:  20
sizeof(days): 20
sizeof(*ptr): 20
sizeof(ptr):  4


답변

모든 정답이 언급했듯이 배열의 붕괴 된 포인터 값에서만이 정보를 얻을 수 없습니다. 소멸 된 포인터가 함수가 수신 한 인수 인 경우 함수가 해당 크기를 알 수 있도록 다른 방법으로 원래 배열의 크기를 제공해야합니다.

지금까지 제공된 것과 다른 제안이 작동합니다. 대신 포인터를 배열에 전달하십시오. 이 제안은 C가 템플리트 또는 참조를 지원하지 않는다는 점을 제외하고 C ++ 스타일 제안과 유사합니다.

#define ARRAY_SZ 10

void foo (int (*arr)[ARRAY_SZ]) {
    printf("%u\n", (unsigned)sizeof(*arr)/sizeof(**arr));
}

그러나이 제안은 전달 된 배열의 크기를 정확히 알 수 있도록 정의되었으므로 문제에 대해 어리석은 일입니다 (따라서 배열에서 sizeof를 전혀 사용할 필요가 없습니다). 그러나 그것이하는 일은 일종의 안전을 제공하는 것입니다. 원치 않는 크기의 배열을 전달할 수 없습니다.

int x[20];
int y[10];
foo(&x); /* error */
foo(&y); /* ok */

함수가 임의의 크기의 배열에서 작동 할 수 있어야하는 경우 추가 정보로 함수에 크기를 제공해야합니다.


답변

마법의 해결책은 없습니다. C는 반사 언어가 아닙니다. 개체는 자신이 무엇인지 자동으로 알지 못합니다.

그러나 많은 선택이 있습니다.

  1. 분명히, 매개 변수를 추가
  2. 매크로로 통화를 감싸고 매개 변수를 자동으로 추가
  3. 더 복잡한 개체를 사용하십시오. 동적 배열과 배열의 크기를 포함하는 구조를 정의하십시오. 그런 다음 구조의 주소를 전달하십시오.