如何找到一个数组的大小(从一个指针指向第一个元素数组)?

首先,这里有一些代码:

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

510114 次浏览

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

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

答案是,“不。”

C程序员所做的就是将数组的大小存储在某个地方。它可以是结构的一部分,或者程序员可以欺骗和malloc()比要求的更多的内存,以便在数组开始之前存储一个长度值。

对于动态数组(malloc或c++ ),你需要像其他人提到的那样存储数组的大小,或者构建一个数组管理器结构来处理添加、删除、计数等。不幸的是,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,更安全,更容易使用。

对于这个特定的例子,是的,如果你使用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++模板有一个干净的解决方案,不需要使用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

正如所有正确答案所述,您不能仅从数组的衰减指针值获得此信息。如果衰减指针是函数接收到的参数,则必须以其他方式提供原始数组的大小,以便函数知道该大小。

这里有一个不同于目前所提供的建议,它可以工作:传递一个指向数组的指针。这个建议类似于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 */

如果假定函数能够操作任意大小的数组,则必须将大小作为附加信息提供给函数。

 #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传递给< em > < / em >大小变量:

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

我对这个问题的解决方案是将数组的长度保存到一个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;
}

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

不,你不能使用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;
}

days的大小[]是20,它是元素的个数*它的数据类型的大小。 而指针的大小是4,不管它指向什么。 因为指针通过存储它的地址指向其他元素。< / p >

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

但你有很多选择:

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

在字符串中,末尾有一个'\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 );
}

你可以这样做:

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

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

然而,这将返回反转块的大小,它可以大于赋给malloc()/realloc()的值。


有一个流行的宏,你可以定义它来查找数组中的元素数量(Microsoft CRT甚至为它提供了名为_countof的OOB):

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