Как найти максимальный размер массива

I’m surprised the max_size() member function of std::vector has not been mentioned here.

“Returns the maximum number of elements the container is able to hold due to system or library implementation limitations, i.e. std::distance(begin(), end()) for the largest container.”

We know that std::vector is implemented as a dynamic array underneath the hood, so max_size() should give a very close approximation of the maximum length of a dynamic array on your machine.

The following program builds a table of approximate maximum array length for various data types.

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

On my macOS (clang version 5.0.1), I get the following:

|  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

On ideone gcc 8.3 I get:

|  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

It should be noted that this is a theoretical limit and that on most computers, you will run out of memory far before you reach this limit. For example, we see that for type char on gcc, the maximum number of elements is equal to the max of std::size_t. Trying this, we get the error:

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()];

Lastly, as @MartinYork points out, for static arrays the maximum size is limited by the size of your stack.

I have a simple question:

Below I’m filling an array with random values and finding the Max. I’d like to know the maximum size of the array that I can define (as the command line argument), without getting an OutOfMemory Exception. Right now I’m trying to alternate between big and small values in a binary search kind of way.

Any better solutions? And also.. what determines this value in a practical system?

java Arrays 7890000 ===>
Exception in thread “main” java.lang.OutOfMemoryError

java Arrays 7890 ===> Max is 0.9999444707701561

  public class Arrays {
      public static void main(String[] args ) {
      int N = Integer.parseInt(args[0]);

      //Initialize to rnadom values between 0 and 1 
      double[] a = new double[N];
      for ( int i=0; i<N;i++) 
        a[i] = Math.random();

      //find the maximum 
      double max = Double.NEGATIVE_INFINITY;
      for (int i = 0;  i < N ;i++)   
        if(a[i] > max ) max = a[i];
      System.out.println("Max is    "+max);
  }
}

asked Sep 17, 2013 at 19:56

Nikhil's user avatar

NikhilNikhil

7975 gold badges12 silver badges30 bronze badges

8

Large arrays are placed in the tenured space and it is the longest continuous region which can be allocated after a GC is performed or Integer. MAX_VALUE which determines the maximum size. There is no way of knowing what this is without triggering a GC and you don’t know what you might get without an OOME. Ie unless you get one you might have allocated more.

This seams like you are going about it the wrong way. You should only be allocating memory if you need it so you shouldn’t be trying to see how much memory you don’t need you might get.

if you have a 64-bit JVM you can store your data in a off heap in a memory mapped file and you are only limited by the free space on your drive which could be TB.

answered Sep 17, 2013 at 22:33

Peter Lawrey's user avatar

Peter LawreyPeter Lawrey

524k77 gold badges749 silver badges1128 bronze badges

1

Как узнать максимально возможный размер массива в С++?



Ученик

(171),
закрыт



10 лет назад

Николай Веселуха

Высший разум

(334025)


10 лет назад

Есть UINT_MAX в limits.h в 4294967295 элемента. Вопрос в том, какая разрядность у операционной системы, каков размер переменной и хватит ли оперативной памяти и файла подкачки для этого массива, а также сколько адресного пространства поддерживает процессор?

Krab Bark

Искусственный Интеллект

(191490)


10 лет назад

Максимально – это size_t в <cstring>
Реально может быть меньше – ограничена памятью, которая выделяется программе.
P.S. Капитан, ну да – это тип, который определяется через другой целый тип по typedef, а уже возможности того типа определяют допустимый диапазон.

Источник: http://www.cplusplus.com/reference/cstring/size_t/

Капитан Гугл

Искусственный Интеллект

(145967)


10 лет назад

Для статического, теоретически – std::numeric_limits<int>::max() из limits или INT_MAX из climits. Практически – минус то, что занимает остальная программа и еще некоторые вещи. Но это если хватает оперативной памяти.
Для динамического – где-то так же, но скорее всего система откажется такой массив выдавать.

Краб, это как – максимальный размер size_t? size_t, вообще-то, тип…

Всем привет, продолжу рубрику для начинающих. В первой части цикла я привел ряд популярных задач по С++. Во втором цикле я немного сменю формат и постараюсь более доступно объяснить материал. Поговорим мы в этот раз о таком мистическом элементе программирования как массив. По ходу описания теории , приведу примеры и типовые задачи, которые дают на лабораторных работах и контрольных в колледжах и институтах. Наверное нет популярнее вопроса у новичков: «Как найти минимальный и/или максимальный размер массива». Что же, вы скоро узнаете, как это сделать на примере написанной программы. Все программы я написал в среде Visual Studio 2015, вы можете использовать любой другой инструмент, например Code::Blocks или онлайн компиляторы.

images

Итак, что такое массив, это такой контейнер или коробочка в которую можно записывать переменные, литералы и значения. Допустим у нас есть яблоки, яблоки нам необходимо поместить в коробочку с секциями. В каждую секцию мы положим столько, сколько необходимо. Количество яблок в каждой секции — целое, т.е 1,2,5, 17 и тд. Покусанное яблоко или половинку мы в контейнер не помещаем. Соответственно тип нашего массива будет целочисленным — int. С++ строго типизированный язык программирования, поэтому мы не можем в целочисленный массив записать вещественное число (float или double) или символ (char).

Статья

Начинаем складывать яблоки в секции (ячейки) контейнера(массив). Как видно из рисунка, нумерация секции(ячейки массива) начинается с нуля. В нулевую ячейку мы кладем два яблока, в первую — одно яблоко, во вторую три яблока, в третью — шесть яблок, в четвертую кладем ноль яблок, в пятую — восемь яблок, в шестую — четыре яблока. Таким образом мы инициализировали массив! Вы спросите, как это будет выглядеть в коде, да очень просто:

#include<iostream> // Стандартная библиотека ввода вывода
#include<iomanip>// Библиотека манипуляторов для форматирования потока


#define SIZE 7      // Обозначаем размер нашего контейнера(массива) для яблок
					// он будет состоять из семи секций(ячеек)
using namespace std; // используем стандартное пространство имен библиотеки iostream

int main(int argc, char* argv[])
{
	// Русский язык в консольном приложении
	setlocale(LC_ALL, "Rus");
	// наш контейнер с яблоками в каждой из
	// секций которой лежит определенное количество яблок
	int apples[SIZE] = { 2, 1, 3, 6, 0, 8, 4 };

	cout << "Выводим массив на экран" << endl;
	// Это цикл, в котором мы идем и заглядываем в каждую секцию
	// после чего печатаем количество каждой секции на экран
	// секций у нас 7, это макрос SIZE
	// setw(4) это форматирование строки на экране, 4 - это примерно
	// 4 пробела между символами.
	for (size_t i = 0; i < SIZE; i++) {
		cout << apples[i] << setw(4);
	}
	cout << endl;
	system("pause"); // Задержка.
	return 0;
}

Теперь можно дать определение массиву. Что нам говорит по этому поводу Википедия:

Массив (в некоторых языках программирования также таблица, ряд, матрица) — тип или структура данных в виде набора компонентов (элементов массива), расположенных в памяти непосредственно друг за другом. При этом доступ к отдельным элементам массива осуществляется с помощью индексации, то есть через ссылку на массив с указанием номера (индекса) нужного элемента. За счёт этого, в отличие от списка, массив является структурой данных, пригодной для осуществления произвольного доступа к её ячейкам.

Очень удобно не правда-ли? Допустим нам нужно отдать тете Маше три яблока, а секции 2, 3, 4, 5, 6 зарезервированы для других людей. Значит мы можем взять яблоки из 0 и 1 секции, сложить их вместе, и отдать тете Маше.

#include<iostream> // Стандартная библиотека ввода вывода
#include<iomanip>// Библиотека манипуляторов для форматирования потока


#define SIZE 7      // Обозначаем размер нашего контейнера(массива) для яблок
// он будет состоять из семи секций(ячеек)
using namespace std; // используем стандартное пространство имен библиотеки iostream

int main(int argc, char* argv[])
{
	// Русский язык в консольном приложении
	setlocale(LC_ALL, "Rus");
	// наш контейнер с яблоками в каждой из
	// секций которой лежит определенное количество яблок
	int apples[SIZE] = { 2, 1, 3, 6, 0, 8, 4 };
	// Для удобства завели новую переменную
	int sumOfAplles;

	sumOfAplles = apples[0] + apples[1];
	cout << "Отдаем тете Маше " << sumOfAplles << " яблока" << endl;
	// Можно и так, без дополнительной переменной
	// cout << "Отдаем тете Маше " << apples[0] + apples[1] << " яблока" << endl;
	system("pause"); // Задержка.
	return 0;
}

По ходу написания программы мы можем изменять количество яблок в секциях контейнера, например в нулевую секцию поместить восемь яблок, а в четвертую сто яблок (размер каждой секции зависит от типа контейнера, он у нас int, а в C++ размер этого типа равен от -2 147 483 648 до 2 147 483 648). А вот размер контейнера(SIZE) мы изменять уже не сможем, для этой цели в языке С++ служат динамические массивы, позже мы о них поговорим.
В массив мы можем записать вещественные числа, символы и строки:

int main(int argc, char* argv[])
{
	// Русский язык в консольном приложении
	setlocale(LC_ALL, "Rus");
	// наш контейнер с яблоками в каждой из
	// секций которой лежит определенное количсетво яблок
	int apples[SIZE] = { 2, 1, 3, 6, 0, 8, 4 };
	// Можно и без указания размера при инициализации,
	// компилятор автоматически создаст массив с необходимым размером
	int apple[] = { 2, 1, 3, 6, 0, 8, 4 };
	char chars[SIZE] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
	float reals[SIZE] = { 2.1, 1.3, 3.4, 6.8, 0.2, 8.3, 4.9 };
	double doubleReals[SIZE] = { 2.14, 1.333, 3.45, 6.882, 0.223, 8.123, 4.999 };;
	string strings[SIZE] = {
	"Vasya", "Ivan", "Petya", "Sergey",
	"Vadim", "Curtis", "Gucci Mane"
	};
	return 0;
}

Думаю, теперь вам стало ясно, что такое одномерный массив? Тогда поехали дальше. Будем разбирать простые задачки с применением массивов. Что делать, если нам необходимо самим в ручную, во время исполнения программы записать данные в массив. Делается это просто, мы объявляем необходимый тип массива и в цикле вводим с клавиатуры значения до тех пор, пока не заполним весь массив согласно его размеру:

#include<iostream> // Стандартная библиотека ввода вывода
#include<iomanip>// Библиотека манипуляторов для форматирования потока

#define SIZE 7      // Обозначаем размер нашего контейнера(массива) для яблок
// он будет состоять из семи секций(ячеек)
using namespace std; // используем стандартное пространство имен библиотеки iostream

int main(int argc, char* argv[])
{
	// Русский язык в консольном приложении
	setlocale(LC_ALL, "Rus");
	// наш контейнер с яблоками в каждой из
	// секций которой лежит определенное количество яблок
	int apples[SIZE];

	for (size_t i = 0; i < SIZE; i++)	{

		cout << "Введите количество яблок в каждой секции" << endl;
		cin >> apples[i];
		cout << "apples[" << i << "]= " << apples[i] << endl;
	}
	
	cout << "Выводим полученный массив" << endl;

	for (size_t i = 0; i < SIZE; i++)	{
		cout << apples[i] << setw(2);
	}
	cout << endl;

	system("pause");
	return 0;
}

Все, теперь мы умеем сами заполнять одномерный массив с клавиатуры. Имейте ввиду, что вводить необходимо только целые числа. Если вы введете символ или вещественное число — будет ошибка во время исполнения программы. В данном примере нет обработки такой ошибки, так как это совсем другая тема. Теперь заполним наш массив числами от 0 до 6, нам необходимо заменить строку

cin >> apples[i];

на

 apples[i] = i;:
#include<iostream> // Стандартная библиотека ввода вывода
#include<iomanip>// Библиотека манипуляторов для форматирования потока

#define SIZE 7      // Обозначаем размер нашего контейнера(массива) для яблок
// он будет состоять из семи секций(ячеек)
using namespace std; // используем стандартное пространство имен библиотеки iostream

int main(int argc, char* argv[])
{
	// Русский язык в консольном приложении
	setlocale(LC_ALL, "Rus");
	// наш контейнер с яблоками в каждой из
	// секций которой лежит определенное количество яблок
	int apples[SIZE];
	cout << "Количество яблок в каждой секции" << endl;
	// При каждой итерации мы записываем значение переменной i
	// в ячейку массива, изначально i у нас 0
	// поэтому в первую ячейку массива запишется 0,
	// а дальше все так же, только i+1
	for (size_t i = 0; i < SIZE; i++) {
		apples[i] = i;
		cout << "apples[" << i << "]= " << apples[i] << endl;
	}   system("pause");
	return 0;
}

Еще одна частая задача, которая возникает в процессе программирования, это заполнения массива случайными числами. Для этого нам необходимо переделать вышеописанную программу, добавив дополнительную библиотеку и функцию:

#include<iostream> // Стандартная библиотека ввода вывода
#include<iomanip>// Библиотека манипуляторов для форматирования потока
#include<time.h> // Библиотека времени

#define SIZE 7      // Обозначаем размер нашего контейнера(массива) для яблок
// он будет состоять из семи секций(ячеек)
using namespace std; // используем стандартное пространство имен библиотеки iostream

int main(int argc, char* argv[])
{
	// Русский язык в консольном приложении
	setlocale(LC_ALL, "Rus");
	// наш контейнер с яблоками в каждой из
	// секций которой лежит определенное количество яблок
	int apples[SIZE];
	cout << "Количество яблок в каждой секции : " << endl;
	// При каждой итерации мы записываем случайное значение
	// в ячейку массива

	for (size_t i = 0; i < SIZE; i++) {
		// Заполняем случайными числами от 0 до 20
		apples[i] = rand() % 20;
		cout << "apples[" << i << "] = " << apples[i] << endl;
	}
	system("pause");
	return 0;
}

Screenshot_1

Получим вот такой результат:

Как мы видим, функция rand() % 20; позволила нам заполнить массив случайными числами от 0 до 20. Но есть одна проблема, этот код генерирует случайные числа только один раз. При следующих запусках программы, в массив будут записаны те же случайные числа, что и в первый раз. Добавим необходимую функцию

(srand(time(NULL));)

в эту же программу:

#include<iostream> // Стандартная библиотека ввода вывода
#include<iomanip>// Библиотека манипуляторов для форматирования потока
#include<time.h> // Библиотека времени

#define SIZE 7      // Обозначаем размер нашего контейнера(массива) для яблок
// он будет состоять из семи секций(ячеек)
using namespace std; // используем стандартное пространство имен библиотеки iostream

int main(int argc, char* argv[])
{
	// Русский язык в консольном приложении
	setlocale(LC_ALL, "Rus");
	// количество секунд, прошедших с 00:00:00 1970 года,
	// их можно преобразовывать в разные части времени с помощью остальных функций из time.h
	srand(time(NULL));
	// наш контейнер с яблоками в каждой из
	// секций которой лежит определенное количество яблок
	int apples[SIZE];
	cout << "Количество яблок в каждой секции" << endl;
	// При каждой итерации мы записываем случайное значение
	// в ячейку массива
	for (size_t i = 0; i < SIZE; i++) {
		// Заполняем случайными числами от 0 до 20
		apples[i] = rand() % 20;
		cout << "apples[" << i << "]= " << apples[i] << endl;
	}
	system("pause");
	return 0;
}

Теперь при каждом запуске программы генерируются различные числа в заданном диапазоне.

А что, если нам необходимо заполнить массив отрицательными числами, например от -20 до 0? В этом случае в нашей программе изменим строку

apples[i] = rand() % 20;

на

apples[i] = rand() % 20 + (-19);

и наш массив заполнится отрицательными числами в заданном диапазоне.

Вот и подошли мы к концу статьи, и в этой части мы найдем эти злополучные максимум и минимум в нашем массиве. За основу мы возьмем нашу программу с яблочками. Как мы видим, в нашем массиве

int apples[SIZE] = { 2, 1, 3, 6, 0, 8, 4 };

минимальный элемент это ноль, находящийся в ячейке под номером четыре (apples[4]), а максимальный равен восьми, находящийся в ячейке массива под номером 5 (apples[5]).

#include<iostream> // Стандартная библиотека ввода вывода
#include<iomanip>// Библиотека манипуляторов для форматирования потока
#include<time.h> // Библиотека времени

#define SIZE 50     // Обозначаем размер нашего контейнера(массива) для яблок
// он будет состоять из семи секций(ячеек)
using namespace std; // используем стандартное пространство имен библиотеки iostream

int main(int argc, char* argv[])
{
	//Русский язык в консольном приложении
	setlocale(LC_ALL, "Rus");
	// наш контейнер с яблоками в каждой из
	// секций которой лежит определенное количество яблок
	int apples[SIZE] = { 2, 1, 3, 6, 0, 8, 4 };
	// Для удобства заводим две новые переменные
	int min = apples[0], max = apples[0];
	for (size_t i = 0; i < SIZE; i++) {
		if (apples[i] < min) {
			min = apples[i];
		}
	}
	cout << "Минимальный элемент массива равен " << min << endl;

	for (size_t i = 0; i < SIZE; i++) {
		if (apples[i] > max) {
			max = apples[i];
		}
	}

	cout << "Максимальный элемент массива равен " << max << endl;
	system("pause"); // Задержка.
	return 0;
}

Что мы тут сделали, мы объявили две целочисленные переменные min и max и присвоили им первый элемент массива. А дальше мы бегаем по циклам и сравниваем элемент массива с первым элементом в массиве. В случае с минимальным значением, проверяем текущий элемент массива с нулевым индексом массива и если он меньше, записываем текущий индекс массива в переменную min. То же самое, только наоборот, с поиском максимального значения. Если текущий элемент массива больше первого элемента массива с нулевым индексом, то мы записываем значение в переменную max.

В следующий раз поговорим о двумерных массивах или, как их еще часто называют, матрицах. Продолжение следует…

cpp

Как и массивы, мы инициализируем std::array, просто присваивая ему значения во время объявления. Например, мы инициализируем целочисленный тип std::array с именем ‘n’ длины 5, как показано ниже; std::array<int, 5> n = {1, 2, 3, 4, 5};

В C++ мы используем оператор sizeof() для определения размера требуемого типа данных, переменных и констант. Это оператор выполнения во время компиляции. Мы можем найти размер массива с помощью оператора sizeof(), как показано ниже: // Находит размер arr[] и сохраняет в ‘size’ int size = sizeof(arr)/sizeof(arr[0]);

std::array содержит встроенный массив,который может быть инициализирован через список инициализаторов,чем и является внутреннее множество.Внешнее множество предназначено для совокупной инициализации.

std::array<T,N>::max_size

constexpr size_type max_size() const noexcept;
(since C++11)

Возвращает максимальное количество элементов, которое может содержать контейнер из-за ограничений реализации системы или библиотеки, т . е. std::distance(begin(), end()) для самого большого контейнера.

Parameters

(none).

Return value

Максимальное количество элементов.

Complexity

Constant.

Notes

Поскольку каждый std::array<T, N> является контейнером фиксированного размера, значение, возвращаемое max_size , равно N (которое также является значением, возвращаемым size ).

Example

#include <iostream>
#include <locale>
#include <array>
 
int main()
{
    std::array<char, 10> q;
    std::cout.imbue(std::locale("en_US.UTF-8"));    
    std::cout << "Maximum size of the std::array is " << q.max_size() << 'n';
}

Output:

Maximum size of the std::array is 10

See also

(C++11)

возвращает количество элементов
(функция публичного члена)


C++

  • std::array<T,N>::front

    Возвращает ссылку на первый элемент в контейнере.

  • std::get(std::array)

    Извлекает I-й элемент из массива.

  • std::array<T,N>::operator[]

    Возвращает ссылку на элемент в указанном месте pos.

  • std::array<T,N>::rbegin, std::array<T,N>::crbegin

    Возвращает обратный итератор первого элемента обращенного массива.

Добавить комментарий