it-swarm.com.de

Gibt es eine maximale Array-Längenbeschränkung in C ++?

Gibt es eine maximale Länge für ein Array in C++?

Handelt es sich um ein C++ - Limit oder hängt es von meinem Computer ab? Ist es einstellbar? Kommt es auf den Typ des Arrays an?

Kann ich diese Grenze irgendwie überschreiten oder muss ich nach einer besseren Möglichkeit suchen, Informationen zu speichern? Und was soll der einfachste Weg sein?

Ich muss long long int in einem Array speichern, ich arbeite in einer Linux-Umgebung. Meine Frage ist: Was muss ich tun, wenn ich ein Array von N langen langen ganzen Zahlen mit N> 10 Ziffern speichern muss?

Ich brauche das, weil ich einen kryptografischen Algorithmus (wie zum Beispiel den p-Pollard) für die Schule schreibe und auf diese Wand aus ganzen Zahlen und Länge der Array-Darstellung treffe.

163
luiss

Es gibt zwei Grenzen, die nicht von C++, sondern von der Hardware vorgegeben werden.

Die erste Grenze (sollte niemals erreicht werden) wird durch die Beschränkungen des Größentyps festgelegt, der zur Beschreibung eines Index im Array (und seiner Größe) verwendet wird. Es wird durch den Maximalwert angegeben, den das System std::size_t Annehmen kann. Dieser Datentyp sollte immer der größte ganzzahlige Typ eines Systems sein.

Die andere Grenze ist eine physikalische Speichergrenze. Je größer Ihre Objekte im Array sind, desto eher wird dieses Limit erreicht, da der Speicher voll ist. Zum Beispiel benötigt ein vector<int> Mit einer bestimmten Größe n in der Regel etwa viermal so viel Speicher wie ein Array vom Typ vector<char> (Abzüglich eines kleinen konstanten Werts). Daher kann ein vector<char> Mehr Elemente als ein vector<int> Enthalten, bevor der Speicher voll ist. Gleiches gilt für die nativen Arrays im C-Stil int[] Und char[].

Darüber hinaus kann diese Obergrenze durch den Typ von allocator beeinflusst werden, der zum Erstellen von vector verwendet wird, da ein allocator frei ist, um den Speicher nach Belieben zu verwalten. Ein sehr seltsamer, aber dennoch denkbarer Allokator könnte den Speicher so bündeln, dass identische Instanzen eines Objekts Ressourcen gemeinsam nutzen. Auf diese Weise können Sie viele identische Objekte in einen Container einfügen, der sonst den gesamten verfügbaren Speicher beansprucht.

Ansonsten setzt C++ keine Grenzen.

155
Konrad Rudolph

Niemand erwähnte die Begrenzung der Größe des stapelrahmen.

Es können zwei Speicherplätze zugewiesen werden:

  • Auf dem Heap (dynamisch zugewiesener Speicher).
    Die Größenbeschränkung ist eine Kombination aus verfügbarer Hardware und der Fähigkeit des Betriebssystems, Speicherplatz zu simulieren, indem andere Geräte zum temporären Speichern nicht verwendeter Daten verwendet werden (d.h. Seiten auf Festplatte verschieben).
  • Auf dem Stack (lokal deklarierte Variablen).
    Die Größenbeschränkung hier ist vom Compiler definiert (mit möglichen Hardware-Beschränkungen). Wenn Sie die Compiler-Dokumentation lesen, können Sie diese Größe häufig optimieren.

Wenn Sie also ein Array dynamisch zuweisen (das Limit ist groß und wird von anderen Posts ausführlich beschrieben).

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

Alternativ, wenn das Array auf dem Stapel zugewiesen ist, sind Sie durch die Größe des Stapelrahmens begrenzt. N.B. Vektoren und andere Container sind im Stapel nur geringfügig vorhanden, aber normalerweise befindet sich der Großteil der Daten auf dem Heap.

int a2[SIZE]; // SIZE limited by COMPILER to the size of the stack frame
155
Martin York

Aus praktischer und nicht aus theoretischer Sicht beträgt auf einem 32-Bit-Windows-System der maximale verfügbare Gesamtspeicher für einen einzelnen Prozess 2 GB. Sie können die Grenze überschreiten, indem Sie auf ein 64-Bit-Betriebssystem mit viel mehr physischem Speicher zugreifen. Ob Sie dies tun oder nach Alternativen suchen, hängt jedoch stark von Ihren beabsichtigten Benutzern und ihren Budgets ab. Sie können es auch mit PAE etwas erweitern.

Der Typ des Arrays ist sehr wichtig, da die Standardstrukturausrichtung auf vielen Compilern 8 Byte beträgt. Dies ist sehr verschwenderisch, wenn die Speichernutzung ein Problem darstellt. Wenn Sie Visual C++ für Windows verwenden, lesen Sie die Anweisung # pragma pack , um dies zu umgehen.

Eine andere Sache, die Sie tun müssen, ist zu prüfen, welche Techniken der Speicherkomprimierung Ihnen helfen könnten, wie beispielsweise dünne Matrizen, schnelle Komprimierung usw. Auch dies ist stark anwendungsabhängig. Wenn Sie Ihren Beitrag bearbeiten, um mehr Informationen darüber zu erhalten, was sich tatsächlich in Ihren Arrays befindet, erhalten Sie möglicherweise nützlichere Antworten.

Bearbeiten: Wenn Sie ein bisschen mehr Informationen zu Ihren genauen Anforderungen erhalten, scheint Ihr Speicherbedarf zwischen 7,6 GB und 76 GB unkomprimiert zu sein. Dies würde eine recht teure 64-Bit-Box erfordern, um sie in C++ als Array im Speicher zu speichern. Es wirft die Frage auf, warum Sie die Daten im Speicher speichern möchten, wo man für die Geschwindigkeit des Zugriffs davon ausgeht, und um einen wahlfreien Zugriff zu ermöglichen. Der beste Weg, um diese Daten außerhalb eines Arrays zu speichern, hängt davon ab, wie Sie darauf zugreifen möchten. Wenn Sie zufällig auf Array-Mitglieder zugreifen müssen, gibt es für die meisten Anwendungen Möglichkeiten, Datengruppen zu gruppieren, auf die zumeist gleichzeitig zugegriffen wird. In großen GIS- und Geodatenbanken werden Daten häufig nach geografischem Gebiet zusammengefasst. In C++ können Sie den Array-Operator [] überschreiben, um Teile Ihrer Daten nach Bedarf von einem externen Speicher abzurufen.

13
SmacL

Um die Antworten zusammenzufassen, zu erweitern und Ihre Frage direkt zu beantworten:

Nein, C++ legt keine Grenzen für die Dimensionen eines Arrays fest.

Da das Array jedoch irgendwo im Speicher abgelegt werden muss, gelten speicherbezogene Beschränkungen, die von anderen Teilen des Computersystems auferlegt werden. Beachten Sie, dass sich diese Grenzwerte nicht direkt auf Dimensionen (= Anzahl der Elemente) des Arrays beziehen, sondern auf Größe (= belegte Speicherkapazität). Abmessungen ( D ) und Speichergröße ( S ) eines Arrays sind nicht dasselbe, da sie durch das Gedächtnis eines einzelnen Elements zusammenhängen ( E ): S = D * E .

Nun E hängt ab von:

  • die Art der Array-Elemente (Elemente können kleiner oder größer sein)
  • speicherausrichtung (um die Leistung zu erhöhen, werden Elemente an Adressen platziert, die ein Vielfaches eines Wertes darstellen, was einleitet)
    „Verschwendeter Platz“ (Auffüllen) zwischen Elementen
  • größe statischer Teile von Objekten (bei der objektorientierten Programmierung werden statische Komponenten von Objekten desselben Typs nur einmal gespeichert, unabhängig von der Anzahl solcher Objekte desselben Typs)

Beachten Sie auch, dass Sie im Allgemeinen unterschiedliche speicherbezogene Einschränkungen erhalten, wenn Sie die Array-Daten auf dem Stack (als automatische Variable: int t[N]) Oder auf dem Heap (dynamische Zuordnung mit malloc()/new oder mit AWL-Mechanismen) oder im statischen Teil des Prozessspeichers (als statische Variable: static int t[N]). Selbst wenn Sie auf dem Heap reservieren, benötigen Sie noch eine kleine Menge Speicher auf dem Stack, um Verweise auf die auf dem Heap reservierten Speicherblöcke zu speichern (dies ist jedoch in der Regel vernachlässigbar).

Die Größe des Typs size_t Hat keinen Einfluss auf den Programmierer (ich gehe davon aus, dass der Programmierer den Typ size_t Für die Indizierung verwendet, da er für diesen vorgesehen ist), da der Compiler-Anbieter typedef es ist ein Integer-Typ, der groß genug ist, um die für die gegebene Plattformarchitektur maximal mögliche Speicherkapazität zu adressieren.

Die Ursachen für die Speichergrößenbeschränkungen liegen in

  • für den Prozess verfügbarer Arbeitsspeicher (der für 32-Bit-Anwendungen auf 2 ^ 32 Byte begrenzt ist, auch auf 64-Bit-Betriebssystemkerneln),
  • die Aufteilung des Prozessspeichers (z. B. die Größe des Prozessspeichers, der für Stapel oder Heap ausgelegt ist),
  • die Fragmentierung des physischen Speichers (viele verstreute kleine Fragmente des freien Speichers können nicht zum Speichern einer monolithischen Struktur verwendet werden),
  • menge an physischem Speicher,
  • und die Größe des virtuellen Speichers.

Sie können nicht auf Anwendungsebene optimiert werden, aber Sie können einen anderen Compiler verwenden (um die Stapelgrößenbeschränkungen zu ändern), Ihre Anwendung auf 64-Bit portieren oder sie auf ein anderes Betriebssystem portieren oder die physischen/Konfiguration des virtuellen Speichers der (virtuellen? physischen?) Maschine.

Es ist nicht ungewöhnlich (und sogar ratsam), alle oben genannten Faktoren als externe Störungen und damit mögliche Ursachen von Laufzeitfehlern zu behandeln und Speicherzuordnungsfehler in Ihrem Programmcode sorgfältig zu überprüfen und darauf zu reagieren.

Also zum Schluss: Während C++ keine Beschränkungen auferlegt, müssen Sie beim Ausführen Ihres Codes immer noch nach widrigen Speicherbedingungen suchen ...: -)

4
Artur Opalinski

Ich stimme dem oben Gesagten zu, wenn Sie Ihr Array mit initialisieren

 int myArray[SIZE] 

dann ist SIZE durch die Größe einer ganzen Zahl begrenzt. Aber Sie können immer einen Teil des Speichers malloc und einen Zeiger darauf haben, so groß Sie wollen, solange malloc nicht NULL zurückgibt.

4
Tarski

Wie bereits erwähnt, gibt es viele Einschränkungen, die von Ihrer Version des C++ - Compilers, dem Betriebssystem und den Computereigenschaften abhängen. Ich schlage jedoch das folgende Skript auf Python vor, das das Limit auf Ihrem Computer überprüft.

Es verwendet die binäre Suche und überprüft bei jeder Iteration, ob die mittlere Größe möglich ist, indem ein Code erstellt wird, der versucht, ein Array der Größe zu erstellen. Das Skript versucht, es zu kompilieren (Entschuldigung, dieser Teil funktioniert nur unter Linux) und die Binärsuche je nach Erfolg anzupassen. Hör zu:

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)

Sie können es auf Ihrem Computer speichern und starten, und es wird die maximale Größe gedruckt, die Sie erstellen können. Für meine Maschine ist es 2305843009213693951.

3
Dmitry Torba

Eine Sache, von der ich glaube, dass sie in den vorherigen Antworten nicht erwähnt wurde.

Ich spüre immer einen "schlechten Geruch" im Refactoring-Sinne, wenn Leute solche Dinge in ihrem Design verwenden.

Dies ist ein riesiges Array und möglicherweise nicht die beste Möglichkeit, Ihre Daten sowohl aus Sicht der Effizienz als auch der Leistung darzustellen.

prost,

Rauben

2
Rob Wells

Wenn Sie mit so großen Daten arbeiten müssen, müssen Sie diese in überschaubare Teile aufteilen. Es passt nicht alles in den Speicher eines kleinen Computers. Sie können wahrscheinlich einen Teil der Daten von der Festplatte laden (was auch immer angemessen passt), Ihre Berechnungen und Änderungen daran durchführen, auf der Festplatte speichern und dann wiederholen, bis sie vollständig sind.

2
Jay

So ärgerlich unspezifisch alle aktuellen Antworten auch sind, sie haben größtenteils recht, aber mit vielen Einschränkungen, die nicht immer erwähnt werden. Das Wesentliche ist, Sie haben zwei Obergrenzen, und nur eine davon ist tatsächlich definiert, also YMMV :

1. Zeitlimits für die Kompilierung

Grundsätzlich, was Ihr Compiler zulässt. Für Visual C++ 2017 auf einer x64-Windows 10-Box ist dies mein maximales Limit zur Kompilierungszeit, bevor das 2-GB-Limit erreicht wird.

unsigned __int64 max_ints[255999996]{0};

Wenn ich das stattdessen tat,

unsigned __int64 max_ints[255999997]{0};

Ich würde bekommen:

Error C1126 automatic allocation exceeds 2G

Ich bin nicht sicher, wie 2G zu 255999996/7 korreliert. Ich habe beide Zahlen gegoogelt, und das einzige, was ich finden konnte, was möglicherweise damit zusammenhängt, war diese * nix-Frage & Antwort zu einem Genauigkeitsproblem mit dc . In beiden Fällen scheint es unerheblich zu sein, welche Art von Int-Array Sie ausfüllen möchten und wie viele Elemente zugewiesen werden können.

2. Laufzeitlimits

Ihr Stapel und Haufen haben ihre eigenen Einschränkungen. Diese Grenzwerte sind sowohl Werte, die sich basierend auf den verfügbaren Systemressourcen ändern, als auch, wie "schwer" Ihre App selbst ist. Mit meinen aktuellen Systemressourcen kann ich beispielsweise Folgendes ausführen:

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

Aber wenn ich es nur ein bisschen optimiere ...

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

Bam! Paketüberfluss!

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).

Und nur um die ganze Schwere Ihres App-Punktes zu beschreiben, war dies ein guter Anfang:

int main()
{
    int maxish_ints[257000]{ 0 };
    int more_ints[400]{ 0 };
    return 0;
}  

Dies führte jedoch zu einem Stapelüberlauf:

int main()
{
    int maxish_ints[257000]{ 0 };
    int more_ints[500]{ 0 };
    return 0;
}  
1

ich würde das umgehen, indem ich ein 2d dynamisches Array mache:

long long** a = new long long*[x];
for (unsigned i = 0; i < x; i++) a[i] = new long long[y];

mehr dazu hier https://stackoverflow.com/a/936702/3517001

0
Three

Wie bereits erwähnt, ist die Array-Größe durch Ihre Hardware und Ihr Betriebssystem (man ulimit) begrenzt. Ihre Software kann jedoch nur durch Ihre Kreativität eingeschränkt sein. Können Sie beispielsweise Ihr "Array" auf der Festplatte speichern? Brauchen Sie wirklich lange lange ints? Benötigen Sie wirklich ein dichtes Array? Benötigen Sie überhaupt ein Array?

Eine einfache Lösung wäre die Verwendung von 64-Bit-Linux. Selbst wenn Sie physisch nicht über genügend RAM für Ihr Array verfügen, können Sie über das Betriebssystem wie gewohnt Speicher zuweisen, da der für Ihren Prozess verfügbare virtuelle Speicher wahrscheinlich viel größer ist als der physische Speicher. Wenn Sie wirklich auf alles im Array zugreifen müssen, müssen Sie es auf der Festplatte speichern. Abhängig von Ihren Zugriffsmustern gibt es effizientere Möglichkeiten, dies zu tun (z. B. mit mmap () oder einfach die Daten nacheinander in einer Datei zu speichern (in diesem Fall würde 32-Bit-Linux ausreichen)).

0
ejgottl