programing

배열의 크기를 찾는 방법(첫 번째 요소 배열을 가리키는 포인터에서)?

megabox 2023. 5. 4. 19:49
반응형

배열의 크기를 찾는 방법(첫 번째 요소 배열을 가리키는 포인터에서)?

먼저, 몇 가지 코드가 있습니다.

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

또 다른 요령은 이 언급한 것인데, 그것은 크기를 어딘가에 비축하는 것입니다.예를 들어, 배열을 동적으로 할당하는 경우 필요한 블록보다 한 int 더 큰 블록을 할당하고 첫 번째 int에 크기를 저장한 다음 반환합니다.ptr+1배열에 대한 포인터로 사용합니다.크기가 필요한 경우 포인터를 줄이고 숨김 값을 확인합니다.어레이뿐만 아니라 처음부터 전체 블록을 해제해야 합니다.

대답은 "아니오"입니다.

C 프로그래머가 하는 일은 배열의 크기를 어딘가에 저장하는 것입니다.될, 도 있고, 그은구일될수있고도가부있것프로래, 수도고속약일간가머그조의,▁it,머수래있고도▁structure속▁a▁cheat,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++ 표준 dlib가 훨씬 안전하고 사용하기 쉽습니다.

()의 크기를 사용하지 않고 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가 템플릿이나 참조를 지원하지 않는다는 점을 제외하면 C++ 스타일 제안과 유사합니다.

#define ARRAY_SZ 10

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

그러나 전달되는 배열의 크기를 정확하게 알 수 있도록 함수가 정의되어 있기 때문에 이 제안은 문제에 대해 다소 어리석은 것입니다(따라서 배열에서 의 크기를 사용할 필요가 거의 없습니다).하지만, 그것이 하는 일은 어떤 종류의 안전을 제공하는 것입니다.원하지 않는 크기의 배열을 전달하는 것을 금지합니다.

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

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

이 특정 예제의 경우, typeef를 사용하는 경우가 있습니다(아래 참조).물론 이렇게 하면 포인터가 가리키는 것이 무엇인지 알 수 있으므로 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는 반사적인 언어가 아닙니다.물체는 자동적으로 그들이 무엇인지 알지 못합니다.

하지만 선택의 폭이 넓습니다.

  1. 매개 변수를 추가
  2. 매크로로 통화를 래핑하고 자동으로 매개 변수 추가
  3. 더 복잡한 개체를 사용합니다.동적 배열과 배열 크기를 포함하는 구조를 정의합니다.그런 다음 구조물의 주소를 전달합니다.

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

int days[] = { /*length:*/5, /*values:*/ 1,2,3,4,5 };
int *ptr = days + 1;
printf("array length: %u\n", ptr[-1]);
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;
}

하지만 저장할 어레이의 올바른 길이를 설정하는 데 신경을 써야 합니다. 친구들이 설명한 것처럼 이 길이를 확인할 수 있는 방법이 없기 때문입니다.

이것이 제 개인적인 코드 방식입니다.저는 제가 필요로 하는 가치를 얻을 수 있으면서도 가능한 한 단순하게 유지하는 것을 좋아합니다.

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

아니요, 사용할 수 없습니다.sizeof(ptr)배열의 크기를 찾다ptr가 가리키고 있습니다.

길이를 추가 공간에 저장하려면 추가 메모리(어레이 크기보다 큼)를 할당하는 것이 유용합니다.

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입니다.포인터가 주소를 저장하여 다른 요소를 가리키기 때문입니다.

줄에는 다음이 있습니다.'\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;
}
 #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가 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;
    }
}

대부분의 구현에는 할당된 개체의 예약된 크기를 알려주는 기능이 있습니다.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-size-of-an-array-from-a-pointer-pointing-to-the-first-element-a

반응형