在c++中数组有最大长度吗?
这是c++的限制还是取决于我的机器?它是否可以调整?它取决于数组的类型吗?
我能以某种方式打破这个限制吗?还是我必须寻找更好的存储信息的方式?最简单的方法是什么?
我要做的是在一个数组中存储long long int,我在Linux环境中工作。我的问题是:如果我需要存储一个包含N个长整数和N个>个10位数字的数组,我该怎么做?
我需要这个,因为我正在为学校写一些加密算法(例如p-Pollard),并遇到了整数和数组长度表示的这堵墙。
在c++中数组有最大长度吗?
这是c++的限制还是取决于我的机器?它是否可以调整?它取决于数组的类型吗?
我能以某种方式打破这个限制吗?还是我必须寻找更好的存储信息的方式?最简单的方法是什么?
我要做的是在一个数组中存储long long int,我在Linux环境中工作。我的问题是:如果我需要存储一个包含N个长整数和N个>个10位数字的数组,我该怎么做?
我需要这个,因为我正在为学校写一些加密算法(例如p-Pollard),并遇到了整数和数组长度表示的这堵墙。
当前回答
尽管目前所有的答案都不明确,但令人恼火的是,它们大多是正确的,但也有许多不常被提及的警告。要点是,你有两个上限,其中只有一个是真正定义的,所以YMMV:
1. 编译时的限制
基本上,你的编译器将允许什么。对于x64 Windows 10盒子上的Visual c++ 2017,这是我在产生2GB限制之前的编译时的最大限制,
unsigned __int64 max_ints[255999996]{0};
如果我这样做,
unsigned __int64 max_ints[255999997]{0};
我得到:
错误C1126自动分配超过2G
我不确定2G如何与255999996/7相关联。我谷歌了这两个数字,我能找到的唯一可能相关的是这个关于dc精度问题的*nix问答。不管怎样,你要填充哪种类型的int数组似乎并不重要,重要的是可以分配多少元素。
2. 运行时的限制
你的堆栈和堆有它们自己的限制。这些限制都是基于可用的系统资源以及应用本身的“重量”而改变的值。例如,使用我当前的系统资源,我可以运行这个:
int main()
{
int max_ints[257400]{ 0 };
return 0;
}
但如果我稍微调整一下……
int main()
{
int max_ints[257500]{ 0 };
return 0;
}
砰!堆栈溢出!
在memchk.exe中的0x00007FF7DC6B1B38抛出异常:0xC00000FD: 堆栈溢出(参数:0x0000000000000001, 0x000000AA8DE03000)。 在memchk.exe中的0x00007FF7DC6B1B38未处理的异常:0xC00000FD: 堆栈溢出(参数:0x0000000000000001, 0x000000AA8DE03000)。
为了详细说明你的应用点的沉重程度,这是很好的:
int main()
{
int maxish_ints[257000]{ 0 };
int more_ints[400]{ 0 };
return 0;
}
但是这会导致堆栈溢出:
int main()
{
int maxish_ints[257000]{ 0 };
int more_ints[500]{ 0 };
return 0;
}
其他回答
我会通过创建一个2d动态数组来解决这个问题:
long long** a = new long long*[x];
for (unsigned i = 0; i < x; i++) a[i] = new long long[y];
更多信息请访问https://stackoverflow.com/a/936702/3517001
我很惊讶std::vector的max_size()成员函数在这里没有提到。
返回由于系统或库实现限制,容器能够容纳的最大元素数,即对于最大的容器std::distance(begin(), end())。
我们知道std::vector在底层是作为一个动态数组实现的,因此max_size()应该给出与您机器上动态数组的最大长度非常接近的值。
下面的程序为各种数据类型构建一个近似最大数组长度的表。
#include <iostream>
#include <vector>
#include <string>
#include <limits>
template <typename T>
std::string mx(T e) {
std::vector<T> v;
return std::to_string(v.max_size());
}
std::size_t maxColWidth(std::vector<std::string> v) {
std::size_t maxWidth = 0;
for (const auto &s: v)
if (s.length() > maxWidth)
maxWidth = s.length();
// Add 2 for space on each side
return maxWidth + 2;
}
constexpr long double maxStdSize_t = std::numeric_limits<std::size_t>::max();
// cs stands for compared to std::size_t
template <typename T>
std::string cs(T e) {
std::vector<T> v;
long double maxSize = v.max_size();
long double quotient = maxStdSize_t / maxSize;
return std::to_string(quotient);
}
int main() {
bool v0 = 0;
char v1 = 0;
int8_t v2 = 0;
int16_t v3 = 0;
int32_t v4 = 0;
int64_t v5 = 0;
uint8_t v6 = 0;
uint16_t v7 = 0;
uint32_t v8 = 0;
uint64_t v9 = 0;
std::size_t v10 = 0;
double v11 = 0;
long double v12 = 0;
std::vector<std::string> types = {"data types", "bool", "char", "int8_t", "int16_t",
"int32_t", "int64_t", "uint8_t", "uint16_t",
"uint32_t", "uint64_t", "size_t", "double",
"long double"};
std::vector<std::string> sizes = {"approx max array length", mx(v0), mx(v1), mx(v2),
mx(v3), mx(v4), mx(v5), mx(v6), mx(v7), mx(v8),
mx(v9), mx(v10), mx(v11), mx(v12)};
std::vector<std::string> quotients = {"max std::size_t / max array size", cs(v0),
cs(v1), cs(v2), cs(v3), cs(v4), cs(v5), cs(v6),
cs(v7), cs(v8), cs(v9), cs(v10), cs(v11), cs(v12)};
std::size_t max1 = maxColWidth(types);
std::size_t max2 = maxColWidth(sizes);
std::size_t max3 = maxColWidth(quotients);
for (std::size_t i = 0; i < types.size(); ++i) {
while (types[i].length() < (max1 - 1)) {
types[i] = " " + types[i];
}
types[i] += " ";
for (int j = 0; sizes[i].length() < max2; ++j)
sizes[i] = (j % 2 == 0) ? " " + sizes[i] : sizes[i] + " ";
for (int j = 0; quotients[i].length() < max3; ++j)
quotients[i] = (j % 2 == 0) ? " " + quotients[i] : quotients[i] + " ";
std::cout << "|" << types[i] << "|" << sizes[i] << "|" << quotients[i] << "|\n";
}
std::cout << std::endl;
std::cout << "N.B. max std::size_t is: " <<
std::numeric_limits<std::size_t>::max() << std::endl;
return 0;
}
在我的macOS (clang版本5.0.1)上,我得到了以下结果:
| data types | approx max array length | max std::size_t / max array size |
| bool | 9223372036854775807 | 2.000000 |
| char | 9223372036854775807 | 2.000000 |
| int8_t | 9223372036854775807 | 2.000000 |
| int16_t | 9223372036854775807 | 2.000000 |
| int32_t | 4611686018427387903 | 4.000000 |
| int64_t | 2305843009213693951 | 8.000000 |
| uint8_t | 9223372036854775807 | 2.000000 |
| uint16_t | 9223372036854775807 | 2.000000 |
| uint32_t | 4611686018427387903 | 4.000000 |
| uint64_t | 2305843009213693951 | 8.000000 |
| size_t | 2305843009213693951 | 8.000000 |
| double | 2305843009213693951 | 8.000000 |
| long double | 1152921504606846975 | 16.000000 |
N.B. max std::size_t is: 18446744073709551615
在ideone gcc 8.3我得到:
| data types | approx max array length | max std::size_t / max array size |
| bool | 9223372036854775744 | 2.000000 |
| char | 18446744073709551615 | 1.000000 |
| int8_t | 18446744073709551615 | 1.000000 |
| int16_t | 9223372036854775807 | 2.000000 |
| int32_t | 4611686018427387903 | 4.000000 |
| int64_t | 2305843009213693951 | 8.000000 |
| uint8_t | 18446744073709551615 | 1.000000 |
| uint16_t | 9223372036854775807 | 2.000000 |
| uint32_t | 4611686018427387903 | 4.000000 |
| uint64_t | 2305843009213693951 | 8.000000 |
| size_t | 2305843009213693951 | 8.000000 |
| double | 2305843009213693951 | 8.000000 |
| long double | 1152921504606846975 | 16.000000 |
N.B. max std::size_t is: 18446744073709551615
需要注意的是,这是一个理论上的限制,在大多数计算机上,您将在达到这个限制之前耗尽内存。例如,对于gcc上的char类型,最大元素数等于std::size_t的最大值。尝试这个,我们得到错误:
prog.cpp: In function ‘int main()’:
prog.cpp:5:61: error: size of array is too large
char* a1 = new char[std::numeric_limits<std::size_t>::max()];
最后,正如@MartinYork指出的,对于静态数组,最大大小受限于堆栈的大小。
如果你必须处理这么大的数据,你就需要把它分成易于管理的块。在任何小型计算机的内存中都装不下这些数据。你可以 从磁盘加载一部分数据(任何合理合适的数据),执行计算并对其进行更改,将其存储到磁盘,然后重复操作,直到完成。
正如许多优秀的答案所指出的,有很多限制取决于你的c++编译器版本、操作系统和计算机特性。但是,我建议使用以下Python脚本检查机器上的限制。
它使用二进制搜索,并在每次迭代中通过创建一个尝试创建该大小的数组的代码来检查中间大小是否可行。脚本尝试编译它(对不起,这部分只在Linux上工作),并根据成功与否调整二进制搜索。看看吧:
import os
cpp_source = 'int a[{}]; int main() {{ return 0; }}'
def check_if_array_size_compiles(size):
# Write to file 1.cpp
f = open(name='1.cpp', mode='w')
f.write(cpp_source.format(m))
f.close()
# Attempt to compile
os.system('g++ 1.cpp 2> errors')
# Read the errors files
errors = open('errors', 'r').read()
# Return if there is no errors
return len(errors) == 0
# Make a binary search. Try to create array with size m and
# adjust the r and l border depending on wheather we succeeded
# or not
l = 0
r = 10 ** 50
while r - l > 1:
m = (r + l) // 2
if check_if_array_size_compiles(m):
l = m
else:
r = m
answer = l + check_if_array_size_compiles(r)
print '{} is the maximum avaliable length'.format(answer)
您可以将它保存到您的机器并启动它,它将打印您可以创建的最大尺寸。我的机器是2305843009213693951。
To summarize the responses, extend them, and to answer your question directly: No, C++ does not impose any limits for the dimensions of an array. But as the array has to be stored somewhere in memory, so memory-related limits imposed by other parts of the computer system apply. Note that these limits do not directly relate to the dimensions (=number of elements) of the array, but rather to its size (=amount of memory taken). Dimensions (D) and in-memory size (S) of an array is not the same, as they are related by memory taken by a single element (E): S=D * E. Now E depends on:
数组元素的类型(元素可以更小也可以更大) 内存对齐(为了提高性能,元素被放置在某个值的倍数的地址上,这会引入 元素之间的“浪费空间”(填充) 对象静态部分的大小(在面向对象编程中,相同类型对象的静态组件只存储一次,与此类相同类型对象的数量无关)
Also note that you generally get different memory-related limitations by allocating the array data on stack (as an automatic variable: int t[N]), or on heap (dynamic alocation with malloc()/new or using STL mechanisms), or in the static part of process memory (as a static variable: static int t[N]). Even when allocating on heap, you still need some tiny amount of memory on stack to store references to the heap-allocated blocks of memory (but this is negligible, usually). The size of size_t type has no influence on the programmer (I assume programmer uses size_t type for indexing, as it is designed for it), as compiler provider has to typedef it to an integer type big enough to address maximal amount of memory possible for the given platform architecture. The sources of the memory-size limitations stem from
进程可用的内存数量(对于32位应用程序,即使在64位操作系统内核上,也仅限于2^32字节), 进程内存的划分(例如,为堆栈或堆设计的进程内存的数量), 物理内存的碎片化(许多分散的小的空闲内存片段不适用于存储一个整体结构), 物理内存的数量, 以及虚拟内存的数量。
They can not be ‘tweaked’ at the application level, but you are free to use a different compiler (to change stack size limits), or port your application to 64-bits, or port it to another OS, or change the physical/virtual memory configuration of the (virtual? physical?) machine. It is not uncommon (and even advisable) to treat all the above factors as external disturbances and thus as possible sources of runtime errors, and to carefully check&react to memory-allocation related errors in your program code. So finally: while C++ does not impose any limits, you still have to check for adverse memory-related conditions when running your code... :-)