以编程方式确定 C++ 数组的大小?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/197839/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Determine the size of a C++ array programmatically?
提问by Kip
This question was inspired by a similar question: How does delete[] “know” the size of the operand array?
这个问题的灵感来自一个类似的问题:delete[] 如何“知道”操作数数组的大小?
My question is a little different: Is there any way to determine the size of a C++ array programmatically? And if not, why?Every function I've seen that takes an array also requires an integer parameter to give it the size. But as the linked question pointed out, delete[]
must know the size of the memory to be deallocated.
我的问题有点不同: 有没有办法以编程方式确定 C++ 数组的大小?如果不是,为什么?我见过的每个接受数组的函数也需要一个整数参数来给它大小。但是正如链接的问题所指出的,delete[]
必须知道要释放的内存的大小。
Consider this C++ code:
考虑这个 C++ 代码:
int* arr = new int[256];
printf("Size of arr: %d\n", sizeof(arr));
This prints "Size of arr: 4
", which is just the size of the pointer. It would be nice to have some function which prints 256, but I don't think one exists in C++. (Again, part of the question is why it doesn't exist.)
这将打印“ Size of arr: 4
”,这只是指针的大小。有一些打印 256 的函数会很好,但我认为 C++ 中不存在。(同样,问题的一部分是为什么它不存在。)
Clarification: I know that if I declared the array on the stack instead of the heap (i.e. "int arr[256];
") that the sizeof
operator would return 1024 (array length * sizeof(int)).
澄清:我知道如果我在堆栈而不是堆(即“ int arr[256];
”)上声明数组,则sizeof
运算符将返回 1024(数组长度 * sizeof(int))。
回答by Dima
delete []
does know the size that was allocated. However, that knowledge resides in the runtime or in the operating system's memory manager, meaning that it is not available to the compiler during compilation. And sizeof()
is not a real function, it is actually evaluated to a constant by the compiler, which is something it cannot do for dynamically allocated arrays, whose size is not known during compilation.
delete []
确实知道分配的大小。但是,该知识驻留在运行时或操作系统的内存管理器中,这意味着编译器在编译期间无法使用它。并且sizeof()
不是一个真正的函数,它实际上被编译器评估为一个常量,这对于动态分配的数组是无法做到的,它的大小在编译过程中是未知的。
Also, consider this example:
另外,请考虑以下示例:
int *arr = new int[256];
int *p = &arr[100];
printf("Size: %d\n", sizeof(p));
How would the compiler know what the size of p
is? The root of the problem is that arrays in C and C++ are not first-class objects. They decay to pointers, and there is no way for the compiler or the program itself to know whether a pointer points to the beginning of a chunk of memory allocated by new
, or to a single object, or to some place in the middle of a chunk of memory allocated by new
.
编译器如何知道的大小p
是多少?问题的根源在于 C 和 C++ 中的数组不是一等对象。它们衰减为指针,编译器或程序本身无法知道指针是指向由 分配的内存块的开头new
,还是指向单个对象,还是指向块中间的某个位置分配的内存new
。
One reason for this is that C and C++ leave memory management to the programmer and to the operating system, which is also why they do not have garbage collection. Implementation of new
and delete
is not part of the C++ standard, because C++ is meant to be used on a variety of platforms, which may manage their memory in very different ways. It may be possible to let C++ keep track of all the allocated arrays and their sizes if you are writing a word processor for a windows box running on the latest Intel CPU, but it may be completely infeasible when you are writing an embedded system running on a DSP.
原因之一是 C 和 C++ 将内存管理留给程序员和操作系统,这也是它们没有垃圾收集的原因。实现new
和delete
不是 C++ 标准的一部分,因为 C++ 旨在用于各种平台,这些平台可能以非常不同的方式管理它们的内存。如果您正在为运行在最新英特尔 CPU 上的 Windows 框编写文字处理器,则可以让 C++ 跟踪所有分配的数组及其大小,但是当您编写运行在其上的嵌入式系统时,这可能完全不可行。一个DSP。
回答by James Curran
No, there is no way to do that in Standard C++.
不,在标准 C++ 中没有办法做到这一点。
There is no really good reason why not that I'm aware of. Probably, the size was considered an implementation detail, and best not exposed. Note that when you say malloc(1000), there is no guarantee that the block returned is 1000 bytes --- only that it's at least1000 bytes. Most likely it's about 1020 (1K minus 4 bytes for overhead). In that case, the "1020" size is the important one for the run-time library to remember. And of course, that would change between implementations.
没有真正好的理由为什么我不知道。也许,大小被认为是一个实现细节,最好不要暴露。请注意,当你说 malloc(1000) 时,不能保证返回的块是 1000 字节——只是它至少是1000 字节。最有可能是大约 1020(1K 减去 4 个字节的开销)。在这种情况下,“1020”大小是运行时库要记住的重要大小。当然,这会在实现之间发生变化。
Which is why the Standards committee added std:vector<>, which does keep track of it exact size.
这就是标准委员会添加 std:vector<> 的原因,它会跟踪它的确切大小。
回答by Jo?o Augusto
Well there is actually a way to determine the size, but it's not "safe" and will be diferent from compiler to compiler.... so it shouldn't be used at all.
好吧,实际上有一种方法可以确定大小,但它不是“安全的”,并且因编译器而异....所以根本不应该使用它。
When you do: int* arr = new int[256];
当你这样做时: int* arr = new int[256];
The 256 is irrelevant you will be given 256*sizeof(int) assuming for this case 1024, this value will be stored probably at ( arr - 4 )
256 无关紧要,假设在这种情况下为 1024,您将获得 256*sizeof(int),该值可能会存储在 ( arr - 4 )
So to give you the number of "items"
所以给你“物品”的数量
int* p_iToSize = arr - 4;
int* p_iToSize = arr - 4;
printf("Number of items %d", *p_iToSize / sizeof(int));
printf("项目数 %d", *p_iToSize / sizeof(int));
For every malloc, new, whatever before the continuos memory block that you receive, there is also allocated a space reserved with some information regarding the block of memory you were given.
对于每个 malloc、new,无论在您收到的连续内存块之前,还会分配一个保留的空间,其中包含有关您获得的内存块的一些信息。
回答by Doug T.
Common way to handle this is to either use a vector
处理此问题的常用方法是使用向量
int main()
{
std::vector<int> v(256);
printf("size of v is %i capacity is %i\n", sizeof(int) * v.size(), sizeof(int) * v.capacity());
}
or predefine the size
或预定义大小
const int arrSize = 256;
int main()
{
int array[arrSize];
printf("Size of array is %i", sizeof(int) * arrSize);
}
回答by bearvarine
Depending on your application, you could create a "sentinel value" at the end of your array.
根据您的应用程序,您可以在数组末尾创建一个“哨兵值”。
The sentinel value must have some unique property.
哨兵值必须具有一些独特的属性。
You can then either process the array (or do a linear search) for the sentinel value, counting as you go. Once you reach the sentinel value, you have your array count.
然后,您可以处理数组(或进行线性搜索)以获取哨兵值,并在进行时计数。一旦达到哨兵值,您就有了数组计数。
For a simple C string, the terminating \0 is an example of a sentinel value.
对于简单的 C 字符串,终止的 \0 是标记值的一个示例。
回答by Zingam
Some magic:
一些魔法:
template <typename T, size_t S>
inline
size_t array_size(const T (&v)[S])
{
return S;
}
And this is how we do it in C++11:
这就是我们在 C++11 中的做法:
template<typename T, size_t S>
constexpr
auto array_size(const T (&)[S]) -> size_t
{
return S;
}
回答by Mykelyk
C++ decided to add new to do a typesafe malloc, than new must know both size e numbers of elements for calling ctors, so delete for calling dtors. In the early days you have to actually pass to delete the numbers a objects you passed to new.
C++ 决定添加 new 来执行类型安全的 malloc,而不是 new 必须知道调用 ctors 的元素的大小 e 数量,因此调用 dtors 时删除。在早期,您必须实际传递以删除传递给新对象的数字。
string* p = new string[5];
delete[5] p;
However they thought that if use new<type>[] the overhead of a number was small. So they decided that new[n] must remember n and pass it to delete. There are three main ways to implement it.
但是他们认为如果使用 new<type>[] 一个数字的开销很小。所以他们决定 new[n] 必须记住 n 并将它传递给 delete。主要有三种实现方式。
- keep a hash-table of pointer to size
- wrote it directly near the vector
- do something completely different
- 保持一个指向大小的指针的哈希表
- 直接写在向量附近
- 做一些完全不同的事情
Maybe is possible to obtain the size like that:
也许有可能获得这样的大小:
size_t* p = new size_t[10];
cout << p[-1] << endl;
// Or
cout << p[11] << endl;
Or hell none of those.
或者地狱都没有。
回答by Peter Kühne
That's because your variable arr is only a pointer. It holds the address of a particular location in memory, without knowing anything about it. You declare it to be int*, which gives the compiler some indication of what to do when you increment the pointer. Other than that, you could be pointing into the beginning or the end of the array or into the stack or into invalid memory. But I agree with you, not being able to call sizeof is very annoying :)
那是因为您的变量 arr 只是一个指针。它保存内存中特定位置的地址,但对此一无所知。您将其声明为 int*,这为编译器提供了在增加指针时要执行的操作的一些指示。除此之外,您可能指向数组的开头或结尾、堆栈或无效内存。但我同意你的看法,无法调用 sizeof 很烦人:)
QuantumPete
量子皮特
回答by Mr Fooz
There is no portable way of determining the size of a dynamically-allocated array in C++ given only its pointer. C++ is made to be very flexible and to give power to the user. For example, the standard does not define how memory allocators must work, e.g. by adding a required size header. Not requiring a header allows for a lot more flexibility.
没有可移植的方法来确定 C++ 中仅给定指针的动态分配数组的大小。C++ 被设计得非常灵活并赋予用户权力。例如,标准没有定义内存分配器必须如何工作,例如通过添加所需的大小头。不需要标题允许更大的灵活性。
As one example, consider a string implemented as a char * array. It's common to use pointers into the middle of the array to pick out substrings. As an example, see the strtok function in the standard C library. If some header were required to be embedded just before each array, you'd need to trash portions of the array before the substring.
作为一个例子,考虑一个实现为 char * 数组的字符串。通常使用指向数组中间的指针来挑选子字符串。例如,请参阅标准 C 库中的 strtok 函数。如果需要在每个数组之前嵌入某些标头,则需要在子字符串之前删除数组的一部分。
An alternative way to handle the headers would be to have array headers in one block of memory and have them point to the raw array memory elsewhere. In many situations, this would require two pointer lookups for each reference, which would be a big drag on performance. There are ways of overcoming these deficiencies, but they add complexity and reduce implementation flexibility.
处理头的另一种方法是将数组头放在一个内存块中,并让它们指向其他地方的原始数组内存。在许多情况下,这将需要对每个引用进行两次指针查找,这将极大地拖累性能。有一些方法可以克服这些缺陷,但它们会增加复杂性并降低实施灵活性。
The std::vector template is my favorite way of keeping the size of an array bound to the array itself.
std::vector 模板是我最喜欢的保持数组大小绑定到数组本身的方式。
C is portable assembly language with a better syntax.
C 是具有更好语法的可移植汇编语言。
回答by James Rose
In general, no. Arrays in C and C++ are just blocks of memory with no bookkeeping information attached. Without storing the length of the array in memory, and adding overhead to do so, it is impossible in the general case.
一般来说,没有。C 和 C++ 中的数组只是没有附加簿记信息的内存块。如果不将数组的长度存储在内存中,并增加开销,那么在一般情况下是不可能的。
There is an exception for arrays that are statically allocated. For instance, if you declare: int a[50]
then sizeof(a)
will work. This is possible because the [50] is part of the static type of the array: it is known to the compiler. sizeof is interpreted at compile time.
静态分配的数组有一个例外。例如,如果您声明:int a[50]
然后sizeof(a)
将工作。这是可能的,因为 [50] 是数组的静态类型的一部分:编译器知道它。sizeof 在编译时解释。
However, if you create a pointer: int *p = a
, then sizeof(p)
will return the size of the pointer as you mention, not the size of the array, because the compiler does not know what p points to.
但是,如果您创建一个指针:int *p = a
,那么sizeof(p)
将返回您提到的指针的大小,而不是数组的大小,因为编译器不知道 p 指向什么。