Czy istnieje maksymalna długość tablicy w C ++?
Czy jest to limit C ++, czy zależy to od mojego komputera? Czy można to zmienić? Czy to zależy od typu, z którego składa się tablica?
Czy mogę jakoś przekroczyć ten limit, czy też muszę szukać lepszego sposobu przechowywania informacji? A jaki powinien być najprostszy sposób?
To, co muszę zrobić, to przechowywać long long int na tablicy, pracuję w środowisku Linux. Moje pytanie brzmi: co mam zrobić, jeśli potrzebuję zapisać tablicę N długich liczb całkowitych z N> 10 cyframi?
Potrzebuję tego, ponieważ piszę jakiś algorytm kryptograficzny (jak na przykład p-Pollard) dla szkoły i trafiam w tę ścianę reprezentacji liczb całkowitych i długości tablic.
new
lubmalloc
. Dostęp do fragmentu pamięci większej niż tablica można uzyskać za pomocą wskaźnika.Nikt nie wspomniał o ograniczeniu rozmiaru ramki stosu .
Istnieją dwa miejsca, w których można przydzielić pamięć:
Limit rozmiaru jest tutaj połączeniem dostępnego sprzętu i zdolności systemu operacyjnego do symulowania miejsca przy użyciu innych urządzeń do tymczasowego przechowywania nieużywanych danych ( tj. Przenoszenia stron na dysk twardy).
Limit rozmiaru jest tutaj zdefiniowany przez kompilator (z możliwymi ograniczeniami sprzętowymi). Jeśli czytasz dokumentację kompilatora, często możesz dostosować ten rozmiar.
Tak więc, jeśli przydzielasz tablicę dynamicznie (limit jest duży i szczegółowo opisany w innych postach.
Alternatywnie, jeśli tablica jest alokowana na stosie, jesteś ograniczony przez rozmiar ramki stosu. Uwaga: wektory i inne pojemniki mają niewielką ilość w stosie, ale zwykle większość danych będzie na stercie.
źródło
new
lubmalloc
).Global Arrays
chociaż nie jest to piękno i najlepiej go unikać, nie podlegają one ograniczeniomstack
i nie musiszmalloc
/free
nie pracujesz z nimi.Patrząc na to z praktycznego, a nie teoretycznego punktu widzenia, w 32-bitowym systemie Windows maksymalna całkowita ilość pamięci dostępnej dla pojedynczego procesu wynosi 2 GB. Możesz przekroczyć ten limit, przechodząc do 64-bitowego systemu operacyjnego ze znacznie większą pamięcią fizyczną, ale to, czy to zrobić, czy poszukać alternatyw, zależy w dużej mierze od zamierzonych użytkowników i ich budżetów. Możesz również nieco go rozszerzyć za pomocą PAE .
Typ tablicy jest bardzo ważny, ponieważ domyślne wyrównanie struktury w wielu kompilatorach wynosi 8 bajtów, co jest bardzo marnotrawne, jeśli problemem jest użycie pamięci. Jeśli używasz języka Visual C ++ do kierowania na system Windows, zapoznaj się z dyrektywą #pragma pack, aby rozwiązać ten problem.
Inną rzeczą do zrobienia jest przyjrzenie się, co mogą pomóc w technikach kompresji pamięci, takich jak rzadkie macierze, kompresja w locie itp. Znowu jest to wysoce zależne od aplikacji. Jeśli zmodyfikujesz swój post, aby podać więcej informacji na temat tego, co faktycznie znajduje się w twoich tablicach, możesz uzyskać bardziej przydatne odpowiedzi.
Edycja: biorąc pod uwagę nieco więcej informacji na temat dokładnych wymagań, Twoje potrzeby w zakresie przechowywania wydają się wynosić od 7,6 GB do 76 GB bez kompresji, co wymagałoby raczej drogiego 64-bitowego pudełka do przechowywania jako tablicy w pamięci w C ++. Powstaje pytanie, dlaczego chcesz przechowywać dane w pamięci, w której zakłada się szybkość dostępu i zezwalasz na dostęp losowy. Najlepszy sposób na przechowywanie tych danych poza tablicą zależy w dużej mierze od tego, jak chcesz uzyskać do nich dostęp. Jeśli potrzebujesz losowego dostępu do elementów tablicy, w przypadku większości aplikacji istnieją sposoby grupowania grup danych, które mają tendencję do uzyskiwania dostępu w tym samym czasie. Na przykład w dużych GIS i bazach danych przestrzennych dane często są dzielone według obszaru geograficznego. W terminach programowania C ++ można zastąpić operator tablicy [], aby w razie potrzeby pobrać porcje danych z pamięci zewnętrznej.
źródło
Zgodziłbym się z powyższym, jeśli chcesz zainicjować swoją tablicę z
wtedy ROZMIAR jest ograniczony rozmiarem liczby całkowitej. Ale zawsze możesz malloc kawałek pamięci i mieć do niego wskaźnik, tak duży, jak chcesz, o ile malloc nie zwraca NULL.
źródło
int oops[INT_MAX]{0};
generuje,C2148 - total size of array must not exceed 0x7fffffff bytes
66%
pamięcią używaną obecnie przed uruchomieniem mojej aplikacji jako debugowania w systemie Windows 10 z VS2017, mam nieokreślony limit dotyczący wielkości tablicy wewnętrznej, którą mogę zainicjować0
. Czasami mogę to zrobić z ~ 257k elementami, czasami stosuję przepełnienie. Jeśli dodam cokolwiek do mojej aplikacji oprócz main i tablicy, liczba ta spadnie (oczywiście). Musiałem poeksperymentować, aby określić tę liczbę, więc nie widzę, na czym można polegać, poza znajomością teoretycznych ograniczeń w próżni.Podsumowując odpowiedzi, rozszerz je i odpowiadając bezpośrednio na Twoje pytanie:
Nie, C ++ nie narzuca żadnych ograniczeń co do wymiarów tablicy.
Ale ponieważ tablica musi być przechowywana gdzieś w pamięci, obowiązują ograniczenia związane z pamięcią narzucone przez inne części systemu komputerowego. Zauważ, że te ograniczenia nie odnoszą się bezpośrednio do wymiarów (= liczby elementów) tablicy, ale raczej do jej rozmiaru (= ilości zajętej pamięci). Wymiary ( D ) i rozmiar w pamięci ( S ) tablicy nie są takie same, ponieważ są powiązane z pamięcią pobieraną przez pojedynczy element ( E ): S = D * E . mi zależy od:
Teraz
`` zmarnowaną przestrzeń '' (dopełnienie) między elementami
Należy również zauważyć, że generalnie uzyskuje się różne ograniczenia związane z pamięcią, przydzielając dane tablicowe na stosie (jako zmienna automatyczna:)
int t[N]
lub na stercie ( alokacja dynamiczna zmalloc()
/new
lub przy użyciu mechanizmów STL) lub w statycznej części pamięci procesu (jako zmienna statyczna:)static int t[N]
. Nawet w przypadku alokowania na stercie nadal potrzebujesz niewielkiej ilości pamięci na stosie, aby przechowywać odwołania do bloków pamięci przydzielonych na stercie (ale zwykle jest to pomijalne).Rozmiar
size_t
typu nie ma wpływu na programistę (zakładam, że programista używasize_t
typu do indeksowania, ponieważ jest do tego przeznaczony), ponieważ musi to zrobić dostawca kompilatoratypedef
to zrobić na typ całkowity wystarczająco duży, aby zaadresować maksymalną ilość pamięci możliwą dla danej platformy architektura.Źródła ograniczeń rozmiaru pamięci wynikają z
Nie można ich modyfikować na poziomie aplikacji, ale możesz użyć innego kompilatora (w celu zmiany limitów rozmiaru stosu), przenieść aplikację na 64-bitowe lub przenieść ją na inny system operacyjny lub zmienić fizyczny / konfiguracja pamięci wirtualnej maszyny (wirtualnej? fizycznej?).
Nie jest niczym niezwykłym (a nawet zalecane) traktowanie wszystkich powyższych czynników jako zewnętrznych zakłóceń, a zatem jako możliwych źródeł błędów w czasie wykonywania, oraz dokładne sprawdzanie i reagowanie na błędy związane z alokacją pamięci w kodzie programu.
W końcu: chociaż C ++ nie narzuca żadnych ograniczeń, nadal musisz sprawdzać niekorzystne warunki związane z pamięcią podczas uruchamiania kodu ... :-)
źródło
Jak zauważyło wiele doskonałych odpowiedzi, istnieje wiele ograniczeń, które zależą od wersji kompilatora C ++, systemu operacyjnego i charakterystyki komputera. Sugeruję jednak następujący skrypt w Pythonie, który sprawdza limit na twojej maszynie.
Używa wyszukiwania binarnego i przy każdej iteracji sprawdza, czy średni rozmiar jest możliwy, tworząc kod, który próbuje utworzyć tablicę o tym rozmiarze. Skrypt próbuje go skompilować (przepraszam, ta część działa tylko na Linuksie) i dostosować wyszukiwanie binarne w zależności od sukcesu. Sprawdź to:
Możesz zapisać go na swoim urządzeniu i uruchomić, a wydrukuje w maksymalnym możliwym rozmiarze. W przypadku mojej maszyny jest to 2305843009213693951.
źródło
Jedna rzecz, o której nie sądzę, została wspomniana w poprzednich odpowiedziach.
Zawsze wyczuwam „nieprzyjemny zapach” w sensie refaktoryzacji, kiedy ludzie używają takich rzeczy w swoich projektach.
To ogromna tablica i prawdopodobnie nie jest to najlepszy sposób reprezentowania danych zarówno z punktu widzenia wydajności, jak i punktu widzenia wydajności.
Twoje zdrowie,
Obrabować
źródło
Jeśli masz do czynienia z tak dużymi danymi, musisz podzielić je na łatwe do zarządzania części. Nie wszystko zmieści się w pamięci dowolnego małego komputera. Prawdopodobnie możesz załadować część danych z dysku (cokolwiek rozsądnie pasuje), wykonać obliczenia i zmiany w nim, zapisać je na dysku, a następnie powtarzać aż do zakończenia.
źródło
Choć wszystkie obecne odpowiedzi są irytująco niesprecyzowane, w większości mają rację, ale z wieloma zastrzeżeniami, które nie zawsze są wspomniane. Istota jest taka, że masz dwie górne granice, a tylko jedna z nich jest faktycznie zdefiniowana, więc YMMV :
1. Terminy kompilacji
Zasadniczo na to, na co pozwoli Twój kompilator. W przypadku programu Visual C ++ 2017 na pudełku z systemem Windows 10 x64 jest to mój maksymalny limit w czasie kompilacji przed naliczeniem limitu 2 GB,
Gdybym zamiast tego zrobił to,
Dostałbym:
Nie jestem pewien, jak 2G odpowiada
255999996
/7
. Przeszukałem oba numery i jedyną rzeczą, jaką mogłem znaleźć, która była prawdopodobnie powiązana, było pytanie * nix dotyczące problemu z precyzjądc
. Tak czy inaczej, nie ma znaczenia, jaki typ tablicy int próbujesz wypełnić, tylko ile elementów można przydzielić.2. Limity czasu pracy
Twój stack i sterta mają swoje własne ograniczenia. Te limity to zarówno wartości, które zmieniają się w zależności od dostępnych zasobów systemowych, jak i tego, jak „ciężka” jest sama aplikacja. Na przykład przy moich obecnych zasobach systemowych mogę uruchomić to:
Ale jeśli poprawię to tylko trochę ...
Bam! Przepełnienie stosu!
Aby szczegółowo opisać całą wagę punktu aplikacji, dobrze było:
Ale to spowodowało przepełnienie stosu:
źródło
Dziwię się MAX_SIZE () funkcji członka z std :: vector nie zostały tutaj wymienione.
Wiemy, że
std::vector
jest zaimplementowany jako dynamiczna tablica pod maską, więcmax_size()
powinna być bardzo zbliżona do maksymalnej długości tablicy dynamicznej na twoim komputerze.Poniższy program tworzy tabelę przybliżonej maksymalnej długości tablicy dla różnych typów danych.
Na moim macOS (wersja Clang 5.0.1) otrzymuję następujące informacje:
Na ideone gcc 8.3 otrzymuję:
Należy zauważyć, że jest to teoretyczny limit i na większości komputerów zabraknie pamięci na długo przed osiągnięciem tego limitu. Na przykład widzimy, że dla typu
char
ongcc
maksymalna liczba elementów jest równa maksymalnejstd::size_t
. Próbując tego , otrzymujemy błąd:Wreszcie, jak wskazuje @MartinYork, w przypadku tablic statycznych maksymalny rozmiar jest ograniczony rozmiarem stosu.
źródło
Jak już wspomniano, rozmiar tablicy jest ograniczony przez twój sprzęt i system operacyjny (man ulimit). Twoje oprogramowanie może być jednak ograniczone tylko przez twoją kreatywność. Na przykład, czy możesz przechowywać swoją „macierz” na dysku? Czy naprawdę potrzebujesz długich, długich int? Czy naprawdę potrzebujesz gęstej tablicy? Czy w ogóle potrzebujesz tablicy?
Jednym prostym rozwiązaniem byłoby użycie 64-bitowego Linuksa. Nawet jeśli fizycznie nie masz wystarczającej ilości pamięci RAM dla swojej macierzy, system operacyjny pozwoli ci przydzielić pamięć tak, jak gdybyś to zrobił, ponieważ pamięć wirtualna dostępna dla twojego procesu jest prawdopodobnie znacznie większa niż pamięć fizyczna. Jeśli naprawdę potrzebujesz dostępu do wszystkiego w tablicy, oznacza to przechowywanie go na dysku. W zależności od twoich wzorców dostępu, mogą istnieć bardziej efektywne sposoby zrobienia tego (np. Użycie mmap () lub po prostu przechowywanie danych sekwencyjnie w pliku (w takim przypadku wystarczy 32-bitowy Linux)).
źródło
obejdę to, tworząc dynamiczną tablicę 2D:
więcej na ten temat tutaj https://stackoverflow.com/a/936702/3517001
źródło