먼저 다음은 몇 가지 코드입니다.
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 바이트 인 크기를 제공하는 대신) 가리키는 배열의 크기를 찾는 방법이 있습니까?
먼저 다음은 몇 가지 코드입니다.
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.
ARRAY_SIZE
매크로는 인수가 배열 인 경우 항상 작동합니다 (예 : 배열 유형의 표현). 소위 "동적 배열"의 경우 실제 "배열"(배열 유형의 표현)을 얻지 못합니다. (물론, 배열 유형에는 컴파일 타임에 크기가 포함되기 때문에 할 수 없습니다.) 첫 번째 요소에 대한 포인터 만 가져옵니다. 여러분의 반대 의견은 "매개 변수가 실제로 정적 배열인지 확인하지 않습니다"는 실제로는 유효하지 않습니다. 하나는 배열이고 다른 하나는 그렇지 않기 때문입니다.
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
T (&)[SIZE]
. 이것이 무엇을 의미하는지 설명 할 수 있습니까? 또한이 컨텍스트에서 constexpr을 언급 할 수 있습니다.
SIZE
인수로 전달하지 않습니다. 이는 템플릿 매개 변수입니다. 함수 정의에 의해 이미 알려질 것입니다.)
이 특정 예제의 경우 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는 반사 언어가 아닙니다. 개체는 자신이 무엇인지 자동으로 알지 못합니다.
그러나 많은 선택이 있습니다.
이 문제에 대한 나의 해결책은 배열의 길이를 배열에 대한 메타 정보로 구조체 배열에 저장하는 것입니다.
#include <stdio.h>
#include <stdlib.h>
struct Array
{
int length;
double *array;
};
typedef struct Array Array;
Array* NewArray(int length)
{
/* Allocate the memory for the struct Array */
Array *newArray = (Array*) malloc(sizeof(Array));
/* Insert only non-negative length's*/
newArray->length = (length > 0) ? length : 0;
newArray->array = (double*) malloc(length*sizeof(double));
return newArray;
}
void SetArray(Array *structure,int length,double* array)
{
structure->length = length;
structure->array = array;
}
void PrintArray(Array *structure)
{
if(structure->length > 0)
{
int i;
printf("length: %d\n", structure->length);
for (i = 0; i < structure->length; i++)
printf("%g\n", structure->array[i]);
}
else
printf("Empty Array. Length 0\n");
}
int main()
{
int i;
Array *negativeTest, *days = NewArray(5);
double moreDays[] = {1,2,3,4,5,6,7,8,9,10};
for (i = 0; i < days->length; i++)
days->array[i] = i+1;
PrintArray(days);
SetArray(days,10,moreDays);
PrintArray(days);
negativeTest = NewArray(-5);
PrintArray(negativeTest);
return 0;
}
그러나 친구가 대규모로 설명 했듯이이 길이를 확인할 수있는 방법이 없기 때문에 저장하려는 배열의 올바른 길이를 설정해야합니다.
다음과 같이 할 수 있습니다 :
int days[] = { /*length:*/5, /*values:*/ 1,2,3,4,5 };
int *ptr = days + 1;
printf("array length: %u\n", ptr[-1]);
return 0;
int main()
{
int days[] = {1,2,3,4,5};
int *ptr = days;
printf("%u\n", sizeof(days));
printf("%u\n", sizeof(ptr));
return 0;
}
days []의 크기는 20이며 이는 데이터 유형의 크기가 아닙니다. 포인터의 크기는 무엇을 가리 키든 4입니다. 포인터는 주소를 저장하여 다른 요소를 가리 킵니다.
#define array_size 10
struct {
int16 size;
int16 array[array_size];
int16 property1[(array_size/16)+1]
int16 property2[(array_size/16)+1]
} array1 = {array_size, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
#undef array_size
array_size가 크기 변수로 전달됩니다 .
#define array_size 30
struct {
int16 size;
int16 array[array_size];
int16 property1[(array_size/16)+1]
int16 property2[(array_size/16)+1]
} array2 = {array_size};
#undef array_size
사용법은 :
void main() {
int16 size = array1.size;
for (int i=0; i!=size; i++) {
array1.array[i] *= 2;
}
}
문자열에는 '\0'
끝에 문자가 있으므로 다음과 같은 함수를 사용하여 문자열의 길이를 얻을 수 있습니다 strlen
. 예를 들어 정수 배열의 문제점은 값을 끝 값으로 사용할 수 없으므로 배열을 처리하고 NULL
포인터를 끝 값으로 사용하는 것 입니다.
#include <stdio.h>
/* the following function will produce the warning:
* ‘sizeof’ on array function parameter ‘a’ will
* return size of ‘int *’ [-Wsizeof-array-argument]
*/
void foo( int a[] )
{
printf( "%lu\n", sizeof a );
}
/* so we have to implement something else one possible
* idea is to use the NULL pointer as a control value
* the same way '\0' is used in strings but this way
* the pointer passed to a function should address pointers
* so the actual implementation of an array type will
* be a pointer to pointer
*/
typedef char * type_t; /* line 18 */
typedef type_t ** array_t;
int main( void )
{
array_t initialize( int, ... );
/* initialize an array with four values "foo", "bar", "baz", "foobar"
* if one wants to use integers rather than strings than in the typedef
* declaration at line 18 the char * type should be changed with int
* and in the format used for printing the array values
* at line 45 and 51 "%s" should be changed with "%i"
*/
array_t array = initialize( 4, "foo", "bar", "baz", "foobar" );
int size( array_t );
/* print array size */
printf( "size %i:\n", size( array ));
void aprint( char *, array_t );
/* print array values */
aprint( "%s\n", array ); /* line 45 */
type_t getval( array_t, int );
/* print an indexed value */
int i = 2;
type_t val = getval( array, i );
printf( "%i: %s\n", i, val ); /* line 51 */
void delete( array_t );
/* free some space */
delete( array );
return 0;
}
/* the output of the program should be:
* size 4:
* foo
* bar
* baz
* foobar
* 2: baz
*/
#include <stdarg.h>
#include <stdlib.h>
array_t initialize( int n, ... )
{
/* here we store the array values */
type_t *v = (type_t *) malloc( sizeof( type_t ) * n );
va_list ap;
va_start( ap, n );
int j;
for ( j = 0; j < n; j++ )
v[j] = va_arg( ap, type_t );
va_end( ap );
/* the actual array will hold the addresses of those
* values plus a NULL pointer
*/
array_t a = (array_t) malloc( sizeof( type_t *) * ( n + 1 ));
a[n] = NULL;
for ( j = 0; j < n; j++ )
a[j] = v + j;
return a;
}
int size( array_t a )
{
int n = 0;
while ( *a++ != NULL )
n++;
return n;
}
void aprint( char *fmt, array_t a )
{
while ( *a != NULL )
printf( fmt, **a++ );
}
type_t getval( array_t a, int i )
{
return *a[i];
}
void delete( array_t a )
{
free( *a );
free( a );
}
NULL
하는 것은 별개의 size
직접 저장하는 것으로 상상할 수있는 가장 효율적인 대안 일 것입니다 . 특히 실제로 경우에 사용하는 간접이 한층 모든 시간을.