如何找到'sizeof'(指向数组的指针)?

时间:2009-01-29 16:33:34

标签: c arrays pointers 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个字节)?

15 个答案:

答案 0 :(得分:240)

不,你不能。编译器不知道指针指向的是什么。有一些技巧,比如以已知的带外值结束数组,然后计算大小直到该值,但这不是使用sizeof。

另一个技巧是Zan提到的那个,就是在某个地方存放大小。例如,如果您正在动态分配数组,请分配一个大于您需要的块的块,在第一个int中存储大小,并返回ptr + 1作为指向数组的指针。当您需要大小时,递减指针并查看隐藏值。只需记住从头开始释放整个块,而不仅仅是数组。

答案 1 :(得分:76)

答案是“不。”

C程序员做的是在某处存储数组的大小。它可以是结构的一部分,或者程序员可以欺骗一点和malloc()更多的内存而不是请求,以便在数组开始之前存储长度值。

答案 2 :(得分:44)

对于动态数组( malloc 或C ++ new ),您需要存储其他人提到的数组大小,或者构建一个处理add的数组管理器结构,不幸的是,C不会像C ++那样做得那么好,因为你基本上必须为你存储的每种不同的数组类型构建它,如果你需要管理多种类型的数组,这很麻烦。 / p>

对于静态数组,例如示例中的静态数组,有一个常用的宏用于获取大小,但是不推荐,因为它不检查参数是否真的是静态的阵列。宏用于实际代码,例如,在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如vector,它更安全,更容易使用。

答案 3 :(得分:17)

使用C ++模板有一个干净的解决方案,而不使用 sizeof()。以下 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

答案 4 :(得分:5)

对于这个具体的例子,是的,如果你使用typedef(见下文)。当然,如果你这样做,你也可以使用SIZEOF_DAYS,因为你知道指针指向的是什么。

如果你有一个(void *)指针,就像malloc()等返回的那样,那么,不,没有办法确定指针所指向的数据结构,因此无法确定它大小

#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

答案 5 :(得分:4)

没有神奇的解决方案。 C不是反思语言。物体不会自动知道它们是什么。

但是你有很多选择:

  1. 显然,添加一个参数
  2. 在宏中包裹呼叫并自动添加参数
  3. 使用更复杂的对象。定义包含动态数组以及数组大小的结构。然后,传递结构的地址。

答案 6 :(得分:3)

正如所有正确答案所述,您无法仅从阵列的衰减指针值获取此信息。如果衰减指针是函数接收的参数,则必须以某种其他方式提供原始数组的大小,以使函数知道该大小。

这是一个与目前为止提供的建议不同的建议,它将起作用:将指针传递给数组。此建议类似于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 */

如果该函数应该可以在任何大小的数组上运行,那么你必须提供该函数的大小作为附加信息。

答案 7 :(得分:2)

我对此问题的解决方案是将数组的长度保存为struct Array,作为有​​关数组的元信息。

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

但是你必须要关心设置你想要存储的数组的正确长度,因为无法检查这个长度,就像我们的朋友大量解释一样。

答案 8 :(得分:2)

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,无论它指向什么。 因为指针通过存储它的地址指向其他元素。

答案 9 :(得分:2)

您可以执行以下操作:

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

答案 10 :(得分:1)

不,您无法使用sizeof(ptr)查找数组ptr指向的大小。

如果你想将长度存储在额外的空间中,那么分配额外的内存(超过数组的大小)会有所帮助。

答案 11 :(得分: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;
    }
}

答案 12 :(得分: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;
}

答案 13 :(得分:0)

大多数实现都会有一个函数来告诉你使用 malloc()calloc() 分配的对象的保留大小,例如 GNU 有 malloc_usable_size()

但是,这将返回反向块的大小,该大小可能大于赋予 malloc()/realloc() 的值。


答案 14 :(得分:-1)

在字符串中,最后有一个'\0'字符,因此可以获得大小 一个像strlen这样的函数的字符串例如,整数数组的问题是你不能使用任何值作为结束值,所以一种可能的解决方案是解决数组并将其用作结束值NULL指针

/* http://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array */
#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;
/*
 *    -- --
 *   -**-**-
 *   -$$$$$-
 *    -999-
 *     -^-
 *      -
 */
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 );
}
/* край */