首先,这里有一些代码:

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个字节)?


当前回答

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

其他回答

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

对于动态数组(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++的标准库,如vector,更安全,更容易使用。

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

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

对于这个特定的例子,是的,如果你使用typedefs(见下面)。当然,如果您这样做,您也可以使用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

没有神奇的解决办法。C不是一种反射语言。对象不会自动知道它们是什么。

但你有很多选择:

显然,要添加一个参数 将调用包装在宏中并自动添加参数 使用更复杂的对象。定义一个包含动态数组和数组大小的结构。然后,传递结构的地址。