首先,这是一些代码:
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个字节)?
首先,这是一些代码:
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个字节)?
Answers:
不,你不能。编译器不知道指针指向什么。有一些技巧,例如以一个已知的带外值结束数组,然后计算大小直到该值,但这并未使用sizeof()
。
Zan提到的另一个技巧是将大小存储在某个地方。例如,如果要动态分配数组,则将一个块分配一个比您所需的块大一个int的块,将大小存储在第一个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;
}
您可以出于某些原因对此类宏保持警惕,因此可以使用Google。小心。
如果可能的话,使用C ++ stdlib(例如vector)会更安全,更易于使用。
ARRAY_SIZE
宏总是工作如果它的参数是一个数组(数组类型的即表达)。对于您所谓的“动态数组”,您永远不会获得实际的“数组”(数组类型的表达)。(当然,您不能这样做,因为数组类型在编译时会包括它们的大小。)您只需获得一个指向第一个元素的指针即可。您的反对意见“不检查参数是否真的是静态数组”不是真的有效,因为它们是不同的,因为一个是数组而另一个不是。
使用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
T (&)[SIZE]
。您能解释一下这是什么意思吗?您也可以在这种情况下提及constexpr。
SIZE
作为arg 传递,这是一个模板参数,具有已经通过函数定义是已知的)。
对于此特定示例,是的,如果您使用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
正如所有正确答案所述,您不能仅从数组的衰减指针值中获取此信息。如果衰减的指针是函数接收到的参数,则必须以其他方式提供原始数组的大小,以使函数知道该大小。
这是与到目前为止所提供的建议不同的建议,它将起作用:将指针传递给数组。该建议与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 */
如果该函数应该能够在任何大小的数组上运行,那么您将必须为函数提供大小作为附加信息。
我对这个问题的解决方案是将数组的长度保存到结构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;
}
但是,您必须关心设置要存储的数组的正确长度,因为就像我们的朋友大量解释的那样,这是无法检查该长度的方法。
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,无论它指向什么。因为指针通过存储其地址指向其他元素。
#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;
}
}
在字符串'\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 );
}
NULL
可能是仅size
直接存储单独元素的效率最低的替代方法。特别是如果您一直在使用此额外的间接层。