programing

'size of'(어레이를 가리키는 포인터)를 찾는 방법

randomtip 2022. 8. 17. 21:01
반응형

'size of'(어레이를 가리키는 포인터)를 찾는 방법

먼저, 몇 가지 코드를 다음에 나타냅니다.

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()

다른 방법은 잔이 말한 크기로 어딘가에 보관하는 것입니다.예를 들어 어레이를 동적으로 할당하는 경우 필요한 블록보다 1int 큰 블록을 할당하고 첫 번째 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;
}

이러한 매크로를 경계하는 이유로 구글을 검색할 수 있습니다.조심하세요.

가능하면 훨씬 안전하고 사용하기 쉬운 벡터 등의 C++ stdlib을 사용합니다.

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

여기에서는 지금까지의 제안과는 다른 제안을 제시합니다.대신 포인터를 어레이에 건네주세요.이 제안은 C가 템플릿 또는 참조를 지원하지 않는다는 점을 제외하고는 C++ 스타일의 제안과 유사합니다.

#define ARRAY_SZ 10

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

다만, 전달되는 어레이의 사이즈를 정확하게 알 수 있도록 함수가 정의되어 있기 때문에, 이 제안은 고객님의 문제에는 다소 우스운 것입니다(따라서 어레이에서는 size of을 사용할 필요가 없습니다).하지만, 그것이 하는 일은 일종의 안전성을 제공하는 것이다.불필요한 크기의 배열을 통과하지 못하게 됩니다.

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

이 함수가 임의의 크기의 어레이로 동작할 수 있도록 되어 있는 경우는, 그 함수의 사이즈를 추가 정보로 제공할 필요가 있습니다.

다음과 같은 작업을 수행할 수 있습니다.

int days[] = { /*length:*/5, /*values:*/ 1,2,3,4,5 };
int *ptr = days + 1;
printf("array length: %u\n", ptr[-1]);
return 0;

에는 '아까운'이 .'\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 );
}
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>

#define array(type) struct { size_t size; type elem[0]; }

void *array_new(int esize, int ecnt)
{
    size_t *a = (size_t *)malloc(esize*ecnt+sizeof(size_t));
    if (a) *a = ecnt;
    return a;
}
#define array_new(type, count) array_new(sizeof(type),count)
#define array_delete free
#define array_foreach(type, e, arr) \
    for (type *e = (arr)->elem; e < (arr)->size + (arr)->elem; ++e)

int main(int argc, char const *argv[])
{
    array(int) *iarr = array_new(int, 10);
    array(float) *farr = array_new(float, 10);
    array(double) *darr = array_new(double, 10);
    array(char) *carr = array_new(char, 11);
    for (int i = 0; i < iarr->size; ++i) {
        iarr->elem[i] = i;
        farr->elem[i] = i*1.0f;
        darr->elem[i] = i*1.0;
        carr->elem[i] = i+'0';
    }
    array_foreach(int, e, iarr) {
        printf("%d ", *e);
    }
    array_foreach(float, e, farr) {
        printf("%.0f ", *e);
    }
    array_foreach(double, e, darr) {
        printf("%.0lf ", *e);
    }
    carr->elem[carr->size-1] = '\0';
    printf("%s\n", carr->elem);

    return 0;
}

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

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

하지만 선택의 여지가 많습니다.

  1. 당연히 파라미터를 추가합니다.
  2. 콜을 매크로로 랩하여 자동으로 파라미터를 추가합니다.
  3. 좀 더 복잡한 개체를 사용합니다.동적 배열과 배열 크기를 포함하는 구조를 정의합니다.그런 다음 구조체의 주소를 전달합니다.

내 코드로 내가 개인적으로 이렇게 하는 거야.필요한 가치를 얻을 수 있을 때 가능한 한 심플하게 하고 싶습니다.

typedef struct intArr {
    int size;
    int* arr; 
} intArr_t;

int main() {
    intArr_t arr;
    arr.size = 6;
    arr.arr = (int*)malloc(sizeof(int) * arr.size);

    for (size_t i = 0; i < arr.size; i++) {
        arr.arr[i] = i * 10;
    }

    return 0;
}

이 문제의 해결 방법은 어레이의 길이를 어레이에 대한 메타 정보로 구조체 어레이에 저장하는 것입니다.

#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;
}

그러나 저장하려는 어레이의 올바른 길이를 설정하는 데 신경을 써야 합니다. 이는 이 길이를 확인하는 방법이 아니기 때문입니다. 이는 당사의 친구들이 자세히 설명했듯이 말입니다.

안 요, 안 돼요.sizeof(ptr)배열의 크기를 구하다ptr를 가리키고 있습니다.

여분의 메모리(어레이 크기보다 큰 메모리)를 할당하는 것은, 여분의 공간에 길이를 보존하는 경우에 도움이 됩니다.

 #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;
    }
}

이 예에서는 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
int main() 
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

일 []의 크기는 20으로, 요소 * 데이터 유형의 크기가 아닙니다.포인터의 크기는 포인터가 무엇을 가리키고 있는지에 관계없이 4입니다.포인터가 다른 요소의 주소를 저장하여 해당 요소를 가리키기 때문입니다.

대부분의 구현에는 할당된 개체의 예약된 크기를 알려주는 기능이 있습니다.malloc()또는calloc()예를 들어 GNU에는malloc_usable_size()

단, 이 경우 반전된 블록의 크기가 반환되며, 이는 다음 값보다 클 수 있습니다.malloc()/realloc().


어레이 내의 요소 수를 검색하기 위해 정의할 수 있는 일반적인 매크로가 있습니다(Microsoft CRT에서는 OOB에 이름을 붙일 수도 있습니다)._countof):

#define countof(x) (sizeof(x)/sizeof((x)[0]))

그런 다음 다음과 같이 쓸 수 있습니다.

int my_array[] = { ... some elements ... };
printf("%zu", countof(my_array)); // 'z' is correct type specifier for size_t

언급URL : https://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array

반응형