먼저 다음은 몇 가지 코드입니다.
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는 반사 언어가 아닙니다. 개체는 자신이 무엇인지 자동으로 알지 못합니다.
그러나 많은 선택이 있습니다.
- 분명히, 매개 변수를 추가
- 매크로로 통화를 감싸고 매개 변수를 자동으로 추가
- 더 복잡한 개체를 사용하십시오. 동적 배열과 배열의 크기를 포함하는 구조를 정의하십시오. 그런 다음 구조의 주소를 전달하십시오.