数组的大小....在C / C ++中?

时间:2011-11-04 15:09:29

标签: c++ c arrays

好的,你有一个数组A [] ...在一些函数中传递给你,比如说下面的函数原型:

void foo(int A[]);

好的,正如你所知,在不知道某种结束变量或已知大小的情况下很难找到该数组的大小......

这就是这笔交易。我似乎有些人在挑战问题上找到了解决方法,我不明白他们是如何做到这一点的。我当然无法看到他们的源代码,这就是我在这里问的原因。

有谁知道甚至可以远程查找该数组的大小?也许就像free()函数在C ??

中所做的那样

你怎么看待这个?

template<typename E, int size>
int ArrLength(E(&)[size]){return size;}

void main()
{
    int arr[17];
    int sizeofArray = ArrLength(arr);
}

10 个答案:

答案 0 :(得分:9)

该函数的签名不是采用数组的函数,而是指针int的签名。您无法在函数中获取数组的大小,并且必须将其作为函数的额外参数传递。

如果允许更改功能的签名,则有不同的选择:

C / C ++(简单):

void f( int *data, int size );             // function
f( array, sizeof array/sizeof array[0] );  // caller code

C ++:

template <int N>
void f( int (&array)[N] );                 // Inside f, size N embedded in type
f( array );                                // caller code

C ++(虽然是派遣):

template <int N>
void f( int (&array)[N] ) {                // Dispatcher
   f( array, N );
}
void f( int *array, int size );            // Actual function, as per option 1
f( array );                                // Compiler processes the type as per 2

答案 1 :(得分:2)

你做不到。要么有一个约定来表示数组的结尾(例如,它由非零整数后跟0组成),要么传输数组的大小(通常作为附加参数)。

如果你使用Boehm garbage collector(它有很多好处,特别是你用GC_malloc和朋友分配,但你不关心free - 显式内存),您可以使用GC_size函数为您提供GC_malloc内存区域的大小,但标准malloc没有此功能。

答案 2 :(得分:2)

您在问我们对以下代码的看法:

template<typename E, int size>
int ArrLength(E(&)[size]){return size;}

void main()
{
    int arr[17];
    int sizeofArray = ArrLength(arr);
}

嗯,void main从来都不是标准的,无论是在C还是在C ++中。

int main

关于ArrLength函数,正确的实现不适用于C ++ 98中的本地类型。它适用于C ++ 11规则的本地类型。但在C ++ 11中,您只需编写end(a) - begin(a)

您显示的实现不正确:它绝对不应该有int模板参数。将其设为ptrdiff_t。例如,在64位Windows中,类型int仍为32位。

最后,作为一般建议:

  • 使用std::vectorstd::array

这种方法的一个相关好处是它避免丢弃大小信息,即它避免了创建你问的问题。还有许多其他优点。所以,试试吧。

干杯&amp;第h

答案 3 :(得分:1)

第一个元素可以是计数,或者最后一个元素可以是哨兵。这就是我能想到的所有可以移植的东西。

在新代码中,对于容器不可知的代码,更喜欢传递两个迭代器(或C中的指针)作为比传递原始数组更好的解决方案。对于特定于容器的代码,请使用像vector这样的C ++容器。

答案 4 :(得分:1)

不,你不能。你的原型等同于

void foo(int * A);

显然没有尺寸信息。依赖于实现的技巧也无济于事:

  • 数组变量可以在堆栈上分配或者是静态的,因此malloc或朋友没有提供信息
  • 如果在堆上分配,则不强制该函数的用户使用分配的第一个元素调用它。

例如以下是有效的

int B[22];
foo(B);
int * A = new int[33];
foo(A + 25);

答案 5 :(得分:0)

这是我不建议做的事情,但是如果你知道数组开头的地址和定义的下一个变量/结构的地址,你可以减去地址。可能不是一个好主意。

答案 6 :(得分:0)

在编译时分配的数组可能在可执行文件的调试信息中包含有关其大小的信息。此外,可以在代码中搜索与编译时分配变量相对应的所有地址,并假设数组的大小减去其起始地址与任何变量的下一个最接近的起始地址之间的差值。

对于dinamically分配的变量,应该可以从堆数据结构中获取其大小。

它是hacky和系统相关的,但它仍然是一个可能的解决方案。

答案 7 :(得分:0)

一个估计如下:如果你有一个int的数组但是知道它们介于(愚蠢的例子)0..80000之间,那么第一个数组元素是负数或大于{ {1}}可能正好在数组的末尾。

这可以有时工作,因为超出数组末尾的内存(我假设它是动态分配的)将不会被程序初始化(因此可能包含垃圾值),但可能仍然是已分配页面的一部分,具体取决于数组的大小。在其他情况下,它会崩溃或无法提供有意义的输出。

答案 8 :(得分:0)

所有其他答案可能都更好,即您必须传递数组的长度或使用特殊的字节序列终止它。

以下方法不可移植,但在VS2005中适用于我:

int getSizeOfArray( int* ptr )
{
   int size = 0;
   void* ptrToStruct = ptr;
   long adr = (long)ptrToStruct;
   adr = adr - 0x10;
   void* ptrToSize = (void*)adr;
   size = *(int*)ptrToSize;
   size /= sizeof(int);
   return size;
}

这完全取决于编译器和系统的内存模型,因此它也不可移植。我敢打赌,其他平台有相同的方法。我绝不会在生产环境中使用它,只是将其作为替代方案。

答案 9 :(得分:-1)

您可以使用:int n = sizeof(A) / sizeof(A[0]);