web-dev-qa-db-fra.com

Existe-t-il une limite maximale de longueur de tableau en C ++?

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.

163
luiss

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.

155
Konrad Rudolph

Personne n'a mentionné la limite de la taille de la cadre de pile.

La mémoire peut être allouée à deux endroits:

  • Sur le tas (mémoire allouée dynamiquement).
    La taille limite ici est une combinaison du matériel disponible et de la capacité du système d'exploitation à simuler de l'espace en utilisant d'autres périphériques pour stocker temporairement les données inutilisées (c'est à dire. déplacer les pages sur le disque dur).
  • Sur la pile (Variables déclarées localement).
    La taille limite est définie ici par le compilateur (avec les limites matérielles possibles). Si vous lisez la documentation du compilateur, vous pouvez souvent modifier cette taille.

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
155
Martin York

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.

13
SmacL

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:

  • le type des éléments du tableau (les éléments peuvent être plus petits ou plus gros)
  • alignement de la mémoire (pour augmenter les performances, les éléments sont placés à des adresses qui sont des multiplications de valeurs, ce qui introduit
    ‘Espace perdu’ (remplissage) entre les éléments
  • taille des parties statiques d'objets (dans la programmation orientée objet, les composants statiques d'objets du même type ne sont stockés qu'une seule fois, indépendamment du nombre d'objets de même type)

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

  • quantité de mémoire disponible pour le processus (limitée à 2 ^ 32 octets pour les applications 32 bits, même sur des noyaux de système d'exploitation 64 bits),
  • la division de la mémoire de processus (par exemple la quantité de la mémoire de processus conçue pour une pile ou un tas),
  • la fragmentation de la mémoire physique (de nombreux fragments de mémoire libre dispersés ne sont pas applicables au stockage d'une structure monolithique),
  • quantité de mémoire physique,
  • et la quantité de mémoire virtuelle.

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

4
Artur Opalinski

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.

4
Tarski

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.

3
Dmitry Torba

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

2
Rob Wells

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.

2
Jay

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 :

1. Délai de compilation

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.

2. Limites d'exécution

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

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

0
Three

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

0
ejgottl