2

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

while(cin >>value) 
{
    arr1[i]=value;
    i+=1;
}

Знаю, что есть ф-ция strtok, может, она лучше подойдет? Использовать можно лишь простейшие функции, стандартные типы.

Nicolas Chabanovsky
  • 51,426
  • 87
  • 267
  • 507

1 Answers1

7

Как всегда, решение подобных задач может идти по одному из вариантов:

  1. Двойной проход: сначала сделать "холостой проход" по входным данным, в котором просто вычислить требуемый размер массива. Затем выделить массив требуемого размера. Затем выполнить второй проход по тем же входным данным, уже помещая их в готовый массив.

    Этот способ применим только тогда, когда есть возможность многопроходной обработки входных данных и выполнение двух проходов вместо одного не является слишком дорогой операцией.

  2. Перевыделение массива: читаемые данные помещаются в массив, размер которого по необходимости наращивается (путем перевыделения памяти) в процессе чтения.

    Этот способ требует перевыделения памяти (возможно многократной) с копированием все нарастающего и нарастающего объема данных. При большом объеме данных его эффективность (либо по скорости, либо по использованию памяти) может падать существенно.

  3. Использование промежуточной легко наращиваемой структуры данных: чтение данных осуществляется в легко наращиваемую структуру данных (например, список), которая по завершению чтения конвертируется в массив.

    Этот способ является попыткой соединить в себе преимущества первого и второго способа. Платой за это является повышенный расход памяти в процессе чтения (список вместо массива).

У каждого способа есть свои преимущества и недостатки. В вашем - простейшем - случае скорее всего применимы они все. Однако если никаких ограничений на количество входных чисел не накладывается, то, наверное, разумнее всего будет пойти по второму пути.

Схематично, работу по второму пути можно изобразить так

// Изначально у нас есть "массив" нулевого размера
std::size_t n = 0;
int *a = nullptr;

// Читаем значения
int value; for (std::size_t i = 0; std::cin >> value; ++i) { if (i >= n) { // Необходимо увеличить размер массива

// Вычисляем новый (больший) размер массива в соответствии с 
// какой-нибудь выбранной стратегией наращивания размера
std::size_t new_n = ...;
// Например
//   new_n = i + 1
// или
//   new_n = n > 0 ? n * 2 : 1;

// Выделяем новую память
int *new_a = new int[new_n];

// Как-то копируем уже существующие данные из старого массива в новый
...;

// Уничтожаем старый массив и переходим на использование нового
delete[] a;
n = new_n;
a = new_a;

}

// Записываем в массив прочитанное значение
a[i] = value; }

  • можно код, пожалуйста? – Julia Ponomareva Dec 30 '17 at 20:21
  • Думаю, вопрс заключался в том, как считывать числа до конца строки, а не файла. – Qwertiy Dec 30 '17 at 20:51
  • @Qwertiy: Возможно. Но если длина входной строки заранее не ограничена, то это - совершенно не принципиальное отличие. Хотя, конечно, возможность прочитать "сразу все" в std::string скрывает этот факт. – AnT stands with Russia Dec 30 '17 at 20:57
  • Так я считаю, что это не отличие, а сам вопрос. Потому что cin сам пропускает все пробельные символы при вводе чисел. – Qwertiy Dec 30 '17 at 21:02
  • 1
    Вот мне до сих пор не понятно, нужно ли явно реализовать отлов конца строки или не нужно. В примере кода от автора никаких попыток в этом направлении не делается. Я подозреваю, что автор вопроса сама не понимает принципиальности этого момента. Более того, мне кажется что на данном уровне задача все-такие не про это, а именно про "массивы заранее неизвестного размера". – AnT stands with Russia Dec 30 '17 at 21:04
  • Возможно и так. Но я по вопросу решил, что он именно в этом и заключается, потому что в портивном случае там вполне рабочий код (если считать, что arr1 объявлен как массив достаточного размера). Но может наоборот, твоя интерпритация правильная :) – Qwertiy Dec 30 '17 at 21:06
  • Если вариант 2) использует страничную переадресацию, то он, вероятно, именно поэтому самый лучший? –  Dec 30 '17 at 21:20
  • @Alexander Zonov: Верно, но это уже тема другого уровня. Более того, что-то похожее можно "приблизительно" реализовать и на уровне языка: выделять массивы блоками фиксированного размера ("страницами"). Когда заполнился текущий блок - выделять новый. Блоки хранить в списке или в массиве указателей. Тогда необходимость копирования данных пропадает. Но это как раз таки будет один из способов реализации третьего подхода. (И, разумеется, по завершению надо будет все собрать в один непрерывный массив, что не требуется в варианте с переадресацией.) – AnT stands with Russia Dec 30 '17 at 21:31