Existe-t-il une longueur maximale pour un tableau en C++?
Est-ce une limite C++ ou cela dépend-il de ma machine? Est-ce que c'est tweakable? Cela dépend-il du type de matrice?
Puis-je dépasser cette limite ou dois-je rechercher un meilleur moyen de stocker des informations? Et quel devrait être le moyen le plus simple?
Ce que je dois faire, c'est stocker long long int sur un tableau, je travaille dans un environnement Linux. Ma question est la suivante: que dois-je faire si je dois stocker un tableau de N entiers longs longs avec N> 10 chiffres?
J'ai besoin de cela parce que j'écris un algorithme cryptographique (comme par exemple le p-Pollard) pour l'école et que je heurte ce mur de nombres entiers et de longueurs de tableaux.
Il existe deux limites, non imposées par C++ mais par le matériel.
La première limite (ne doit jamais être atteinte) est définie par les restrictions du type de taille utilisé pour décrire un index dans le tableau (et sa taille). Elle est donnée par la valeur maximale que le std::size_t
du système peut prendre. Ce type de données doit toujours être le type entier le plus grand d'un système.
L'autre limite est une limite de mémoire physique. Plus vos objets dans le tableau sont grands, plus cette limite est atteinte rapidement car la mémoire est saturée. Par exemple, un vector<int>
d'une taille donnée n nécessite généralement environ quatre fois plus de mémoire qu'un tableau de type vector<char>
(moins une petite valeur constante). Par conséquent, un vector<char>
peut contenir plus d'éléments qu'un vector<int>
avant que la mémoire ne soit saturée. Il en va de même pour les tableaux de style C natifs int[]
et char[]
.
De plus, cette limite supérieure peut être influencée par le type de allocator
utilisé pour construire le vector
, car un allocator
est libre de gérer la mémoire comme il le souhaite. Un allocateur très étrange mais néanmoins concevable pourrait regrouper la mémoire de telle sorte que des instances identiques d’un objet partagent des ressources. De cette façon, vous pouvez insérer un grand nombre d'objets identiques dans un conteneur qui, autrement, utiliserait toute la mémoire disponible.
En dehors de cela, C++ n'impose aucune limite.
Personne n'a mentionné la limite de la taille de la cadre de pile.
La mémoire peut être allouée à deux endroits:
Ainsi, si vous allouez un tableau de manière dynamique (la limite est grande et décrite en détail par d’autres publications).
int* a1 = new int[SIZE]; // SIZE limited only by OS/Hardware
Alternativement, si le tableau est alloué sur la pile, vous êtes limité par la taille du cadre de la pile. N.B. les vecteurs et autres conteneurs ont une faible présence dans la pile, mais le gros des données se trouve généralement dans la pile.
int a2[SIZE]; // SIZE limited by COMPILER to the size of the stack frame
Sous un angle pratique plutôt que théorique, sur un système Windows 32 bits, la quantité totale de mémoire totale disponible pour un processus unique est de 2 Go. Vous pouvez dépasser la limite en optant pour un système d'exploitation 64 bits avec beaucoup plus de mémoire physique, mais le choix de le faire ou de rechercher une alternative dépend beaucoup de vos utilisateurs et de leurs budgets. Vous pouvez également l'étendre un peu en utilisant PAE .
Le type du tableau est très important, car l'alignement de la structure par défaut sur de nombreux compilateurs est de 8 octets, ce qui est très inutile si l'utilisation de la mémoire pose problème. Si vous utilisez Visual C++ pour cibler Windows, consultez la directive # pragma pack pour résoudre ce problème.
Une autre chose à faire est de regarder ce que les techniques de compression en mémoire peuvent vous aider, telles que les matrices creuses, la compression à la volée, etc. Encore une fois, cela dépend fortement de l'application. Si vous modifiez votre message pour donner plus d'informations sur ce qu'il y a réellement dans vos tableaux, vous obtiendrez peut-être des réponses plus utiles.
Éditer: Si vous donnez un peu plus d’informations sur vos besoins exacts, vos besoins de stockage semblent se situer entre 7,6 Go et 76 Go non compressés, ce qui nécessiterait le stockage d’un tableau 64 bits plutôt coûteux, en mémoire en C++. Cela soulève la question de savoir pourquoi vous voulez stocker les données en mémoire, où l’on suppose une vitesse d’accès et l’autorisation d’un accès aléatoire. La meilleure façon de stocker ces données en dehors d'un tableau dépend en grande partie de la façon dont vous voulez y accéder. Si vous devez accéder aux membres du groupe de manière aléatoire, pour la plupart des applications, il existe généralement des moyens de regrouper des groupes de données auxquels on a généralement accès en même temps. Par exemple, dans les grandes bases de données SIG et spatiales, les données sont souvent classées par zone géographique. En termes de programmation C++, vous pouvez remplacer l’opérateur de tableau [] pour extraire des parties de vos données du stockage externe selon vos besoins.
Pour résumer les réponses, développez-les et répondez directement à votre question:
Non, C++ n'impose aucune limite pour les dimensions d'un tableau.
Mais comme le tableau doit être stocké quelque part en mémoire, les limites relatives à la mémoire imposées par d'autres parties du système informatique s'appliquent. Notez que ces limites ne concernent pas directement les dimensions (= nombre d'éléments) du tableau, mais plutôt ses taille (= quantité de mémoire utilisée). Les dimensions (D) et la taille en mémoire (S) d'un tableau ne sont pas identiques, car elles sont liées par la mémoire prise par un seul élément ( E): S= D * E.
Maintenant E dépend de:
Notez également que vous obtenez généralement différentes limitations liées à la mémoire en allouant les données du tableau sur la pile (en tant que variable automatique: int t[N]
) ou sur le tas (allocation dynamique avec malloc()
/new
ou utilisant des mécanismes STL), ou dans la partie statique de la mémoire de processus (sous forme de variable statique: static int t[N]
). Même lors de l'allocation sur le tas, vous avez toujours besoin d'une petite quantité de mémoire sur la pile pour stocker les références aux blocs de mémoire alloués au tas (mais cela est généralement négligeable).
La taille du type size_t
n'a aucune influence sur le programmeur (je suppose que le programmeur utilise le type size_t
pour l'indexation, car il est conçu pour cela), car le fournisseur du compilateur doit typedef
_ à un type entier suffisamment grand pour gérer la quantité maximale de mémoire possible pour l’architecture de la plate-forme donnée.
Les sources de limitation de la taille de la mémoire proviennent de
Ils ne peuvent pas être modifiés au niveau de l'application, mais vous êtes libre d'utiliser un compilateur différent (pour modifier les limites de la pile), de transférer votre application en 64 bits, de la transférer vers un autre système d'exploitation ou de modifier le paramètre physique. configuration de la mémoire virtuelle de la machine (virtuelle? physique?).
Il n’est pas rare (et même conseillé) de traiter tous les facteurs ci-dessus comme des perturbations externes et donc comme des sources possibles d’erreurs d’exécution, et de vérifier soigneusement les erreurs liées à l’allocation de mémoire dans votre code de programme.
Donc enfin: bien que C++ n'impose aucune limite, vous devez toujours vérifier les conditions défavorables liées à la mémoire lors de l'exécution de votre code ...: -)
Je suis d’accord avec ce qui précède, que si vous initialisez votre tableau avec
int myArray[SIZE]
alors SIZE est limité par la taille d'un entier. Mais vous pouvez toujours malloc un morceau de mémoire et y avoir un pointeur, aussi gros que vous voulez tant que malloc ne renvoie pas la valeur NULL.
Comme beaucoup d'excellentes réponses ont été notées, de nombreuses limites dépendent de votre version du compilateur C++, des caractéristiques du système d'exploitation et de l'ordinateur. Cependant, je suggère le script suivant sur Python qui vérifie la limite sur votre ordinateur.
Il utilise la recherche binaire et vérifie à chaque itération si la taille moyenne est possible en créant un code qui tente de créer un tableau de la taille. Le script tente de le compiler (désolé, cette partie ne fonctionne que sous Linux) et d’ajuster la recherche binaire en fonction du succès. Vérifiez-le:
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)
Vous pouvez l'enregistrer sur votre ordinateur et le lancer. Il imprimera la taille maximale que vous pouvez créer. Pour ma machine, il s’agit de 2305843009213693951.
Une chose que je ne pense pas a été mentionnée dans les réponses précédentes.
Je ressens toujours une "mauvaise odeur" dans le sens du refactoring lorsque les gens utilisent de telles choses dans leur conception.
Il s'agit d'un vaste ensemble et peut-être pas la meilleure façon de représenter vos données à la fois du point de vue de l'efficacité et du point de vue des performances.
à votre santé,
Rob
Si vous devez gérer des données aussi volumineuses, vous devrez les diviser en plusieurs parties gérables. Tout ne rentrera pas dans la mémoire d'un petit ordinateur. Vous pouvez probablement charger une partie des données à partir du disque (à votre convenance), effectuer vos calculs et les modifier, les stocker sur un disque, puis répéter l'opération jusqu'à la fin.
Aussi ennuyeuses que soient les réponses actuelles, elles sont généralement correctes, mais comportent de nombreuses mises en garde qui ne sont pas toujours mentionnées. En résumé, vous avez deux limites supérieures et une seule d'entre elles est définie, donc YMMV :
Fondamentalement, ce que votre compilateur permettra. Pour Visual C++ 2017 sur une zone x64 Windows 10, il s'agit de ma limite maximale au moment de la compilation avant d'engager la limite de 2 Go.
unsigned __int64 max_ints[255999996]{0};
Si je faisais ça à la place,
unsigned __int64 max_ints[255999997]{0};
J'aurais:
Error C1126 automatic allocation exceeds 2G
Je ne sais pas comment 2G corrèle en 255999996
/7
. J'ai googlé les deux chiffres, et la seule chose que je pouvais trouver qui était probablement liée était ce * nix Q & A sur un problème de précision avec dc
. Quoi qu'il en soit, le type d'éléments de tableau int que vous essayez de remplir n'a pas d'importance, mais le nombre d'éléments pouvant être alloués.
Votre pile et votre tas ont leurs propres limites. Ces limites sont à la fois des valeurs qui changent en fonction des ressources système disponibles, ainsi que de la lourdeur de votre application. Par exemple, avec mes ressources système actuelles, je peux le faire exécuter:
int main()
{
int max_ints[257400]{ 0 };
return 0;
}
Mais si je Tweak juste un peu ...
int main()
{
int max_ints[257500]{ 0 };
return 0;
}
Bam! Débordement de pile!
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).
Et juste pour détailler toute la lourdeur de votre point d'application, c'était bon à faire:
int main()
{
int maxish_ints[257000]{ 0 };
int more_ints[400]{ 0 };
return 0;
}
Mais cela a provoqué un débordement de pile:
int main()
{
int maxish_ints[257000]{ 0 };
int more_ints[500]{ 0 };
return 0;
}
je ferais le tour en faisant un tableau dynamique en 2D:
long long** a = new long long*[x];
for (unsigned i = 0; i < x; i++) a[i] = new long long[y];
plus à ce sujet ici https://stackoverflow.com/a/936702/3517001
Comme cela a déjà été souligné, la taille de la matrice est limitée par votre matériel et votre système d'exploitation (man ulimit). Cependant, votre logiciel ne peut être limité que par votre créativité. Par exemple, pouvez-vous stocker votre "matrice" sur le disque? Avez-vous vraiment besoin de longs moments? Avez-vous vraiment besoin d'un tableau dense? Avez-vous même besoin d'un tableau du tout?
Une solution simple serait d’utiliser Linux 64 bits. Même si vous n'avez pas physiquement assez de RAM pour votre baie, le système d'exploitation vous permettra d'allouer de la mémoire comme si vous le faisiez, car la mémoire virtuelle disponible pour votre processus est probablement beaucoup plus grande que la mémoire physique. Si vous avez vraiment besoin d'accéder à tout ce qui se trouve dans la matrice, cela revient à la stocker sur disque. Selon vos schémas d'accès, il peut y avoir des moyens plus efficaces de le faire (par exemple: utiliser mmap () ou simplement stocker les données de manière séquentielle dans un fichier (auquel cas Linux 32 bits suffirait)).