c++中有最大数组长度限制吗?

在c++中数组有最大长度吗?

这是c++的限制还是取决于我的机器?它是否可以调整?它取决于数组的类型吗?

我能以某种方式打破这个限制吗?还是我必须寻找更好的存储信息的方式?最简单的方法是什么?

我要做的是在一个数组中存储long long int,我在Linux环境中工作。我的问题是:如果我需要存储一个包含N个长整数和N个>个10位数字的数组,我该怎么做?

我需要这个,因为我正在为学校写一些加密算法(例如p-Pollard),并遇到了整数和数组长度表示的这堵墙。

337497 次浏览

有两个限制,都不是由c++强制执行的,而是由硬件强制执行的。

第一个限制(不应达到)由用于描述数组中索引的size类型的限制(及其大小)设置。它由系统的std::size_t可以取的最大值给出。此数据类型足够大,可以包含任何对象的字节大小

另一个限制是物理内存限制。数组中的对象越大,这个限制就越快达到,因为内存已经满了。例如,给定大小的nvector<int>通常占用的内存是vector<char>类型数组的数倍(减去一个小的常量值),因为int通常比char大。因此,在内存满之前,vector<char>可能包含比vector<int>更多的项。对于像int[]char[]这样的原始c风格数组也是如此。

此外,这个上限可能受到用于构造vectorallocator类型的影响,因为allocator可以自由地以任何它想要的方式管理内存。一个非常奇怪但仍然可以想象的分配器可以以这样一种方式池内存,即对象的相同实例共享资源。通过这种方式,您可以将许多相同的对象插入到容器中,否则将耗尽所有可用内存。

除此之外,c++没有强制任何限制。

我同意上面的观点,如果你用

 int myArray[SIZE]

那么SIZE受限于一个整数的大小。但是你总是可以malloc一个内存块,并有一个指向它的指针,只要malloc不返回NULL。

从实际而非理论的角度来看,在32位Windows系统上,单个进程可用的最大内存总量是2 GB。您可以通过使用具有更多物理内存的64位操作系统来打破这个限制,但是是这样做还是寻找替代方案在很大程度上取决于您的预期用户和他们的预算。你也可以使用PAE扩展它。

数组的类型非常重要,因为许多编译器上的默认结构对齐是8字节,如果内存使用有问题,这是非常浪费的。如果你使用Visual c++瞄准Windows,检查# pragma包指令作为克服这个问题的一种方法。

另一件要做的事情是看看哪些内存压缩技术可以帮助你,比如稀疏矩阵,动态压缩等等……这也是高度依赖于应用程序的。如果你编辑你的文章来提供更多关于数组中实际内容的信息,你可能会得到更有用的答案。

编辑:根据您的确切需求,您的存储需求似乎在7.6 GB到76 GB未压缩之间,这将需要一个相当昂贵的64位盒子来存储在c++的内存中作为数组。这就提出了一个问题,为什么要将数据存储在内存中,而其中一个假设是访问速度,并允许随机访问。在数组之外存储这些数据的最佳方法基本上取决于您想要如何访问它。如果您需要随机访问数组成员,对于大多数应用程序来说,往往会有对同时访问的数据块进行分组的方法。例如,在大型GIS和空间数据库中,数据通常按地理区域平铺。在c++编程术语中,您可以覆盖[]数组操作符,以便根据需要从外部存储中获取部分数据。

有一件事我认为在之前的回答中没有提到。

当人们在设计中使用这些东西时,我总是感觉到重构的“臭味”。

这是一个巨大的数组,从效率和性能的角度来看,这可能不是表示数据的最佳方式。

欢呼,

抢劫

前面已经指出,数组大小受硬件和操作系统的限制(man ulimit)。不过,你的软件可能只受限于你的创造力。例如,您可以将“数组”存储在磁盘上吗?你真的需要长整型吗?你真的需要密集数组吗?你需要数组吗?

一个简单的解决方案是使用64位Linux。即使你的数组没有足够的物理ram,操作系统也会允许你像分配内存一样分配内存,因为你的进程可用的虚拟内存可能比物理内存大得多。如果您确实需要访问数组中的所有内容,这相当于将其存储在磁盘上。根据您的访问模式,可能有更有效的方法来做到这一点(例如:使用mmap(),或简单地按顺序将数据存储在文件中(在这种情况下,32位Linux就足够了)。

没有人提到堆栈帧的大小限制。

有两个地方可以分配内存:

  • 在堆上(动态分配内存) 这里的大小限制是可用硬件和操作系统通过使用其他设备临时存储未使用的数据来模拟空间的能力(即。将页面移动到硬盘)的组合
  • 在堆栈上(局部声明变量) 这里的大小限制是编译器定义的(可能有硬件限制)。如果你阅读编译器文档,你经常可以调整这个大小

因此,如果你动态分配一个数组(限制很大,详见其他文章)。

int* a1 = new int[SIZE];  // SIZE limited only by OS/Hardware

或者,如果数组分配在堆栈上,则受限于堆栈帧的大小。注意:向量和其他容器在堆栈中有一个小的存在,但通常大部分数据将在堆上。

int a2[SIZE]; // SIZE limited by COMPILER to the size of the stack frame
如果你必须处理这么大的数据,你需要把它分成易于管理的块。在任何小型计算机的内存中都装不下这些数据。你可以 从磁盘加载一部分数据(任何合理合适的),执行计算并对其进行更改,将其存储到磁盘,然后重复直到完成

我会通过创建一个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

为了总结这些回答,扩展它们,直接回答你的问题:

不,c++没有对数组的维度施加任何限制。 < BR > < BR > 但是由于数组必须存储在内存中的某个地方,因此计算机系统的其他部分施加了与内存相关的限制。注意,这些限制与数组的(=元素数量)没有直接关系,而是与数组的大小(=占用的内存量)有关。数组的尺寸(D)和内存大小(年代)是不一样的,因为它们是由单个元素(E)占用的内存所关联的:年代=D * E。< BR > < BR > 现在E依赖于:

  • 数组元素的类型(元素可以更小也可以更大)
  • 内存对齐(为了提高性能,元素被放置在某个值的倍数的地址上,这引入了
    元素之间的'浪费空间'(填充)
  • 对象静态部分的大小(在面向对象编程中,相同类型对象的静态组件只存储一次,与此类相同类型对象的数量无关)
还要注意,通过在堆栈上(作为自动变量:int t[N])分配数组数据,或在堆上(使用malloc()/new或使用STL机制进行动态分配),或在进程内存的静态部分(作为静态变量:static int t[N]),通常会得到不同的内存相关限制。即使在堆上进行分配,你仍然需要在堆栈上使用少量的内存来存储对堆分配的内存块的引用(但这通常是可以忽略的) size_t类型的大小对程序员没有影响(我假设程序员使用size_t类型进行索引,因为它是为它设计的),因为编译器提供者必须typedef它为一个足够大的整数类型,以解决给定平台架构可能的最大内存量。< BR > < BR > 内存大小限制的来源来自

  • 进程可用的内存数量(对于32位应用程序,即使在64位操作系统内核上,也仅限于2^32字节),
  • 进程内存的划分(例如,为堆栈或堆设计的进程内存的数量),
  • 物理内存的碎片化(许多分散的小的空闲内存片段不适用于存储一个整体结构),
  • 物理内存的数量,
  • 以及虚拟内存的数量。
它们不能在应用程序级别上“调整”,但您可以自由地使用不同的编译器(更改堆栈大小限制),或将应用程序移植到64位,或移植到另一个操作系统,或更改物理/虚拟内存配置(虚拟?物理?)机器。< BR > < BR > 将上述所有因素视为外部干扰,从而作为运行时错误的可能来源,并仔细检查程序代码中与内存分配相关的错误,这并不罕见(甚至是可取的) 所以最后:虽然c++没有施加任何限制,但在运行代码时,您仍然需要检查与内存相关的不利条件……: -) < / em >

正如许多优秀的答案所指出的,有很多限制取决于你的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。

尽管目前所有的答案都不明确,但令人恼火的是,它们大多是正确的,但也有许多不常被提及的警告。要点是,你有两个上限,其中只有一个是实际定义的,所以YMMV:

1. 编译时的限制

基本上,你的编译器将允许什么。对于x64 Windows 10盒子上的Visual c++ 2017,这是我在产生2GB限制之前的编译时的最大限制,

unsigned __int64 max_ints[255999996]{0};

如果我这样做,

unsigned __int64 max_ints[255999997]{0};

我得到:

Error C1126 automatic allocation exceeds 2G

我不确定2G如何与255999996/7相关。我谷歌了这两个数字,我能找到的唯一可能相关的是这个关于精度问题与dc的*nix Q&A。不管怎样,你要填充哪种类型的int数组似乎并不重要,重要的是可以分配多少元素。

2. 运行时的限制

你的堆栈和堆有它们自己的限制。这些限制都是基于可用的系统资源以及应用本身的“重量”而改变的值。例如,使用我当前的系统资源,我可以运行这个:

int main()
{
int max_ints[257400]{ 0 };
return 0;
}

但如果我稍微调整一下……

int main()
{
int max_ints[257500]{ 0 };
return 0;
}

砰!堆栈溢出!

< p > Exception thrown at 0x00007FF7DC6B1B38 in memchk.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000AA8DE03000). Unhandled exception at 0x00007FF7DC6B1B38 in memchk.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000AA8DE03000). < / p >

为了详细说明你的应用点的沉重程度,这是很好的:

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

我很惊讶这里没有提到std::向量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的max。尝试,我们得到错误:

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指出的,对于静态数组,最大大小受限于堆栈的大小。