Страницы

Поиск по вопросам

четверг, 11 июля 2019 г.

Как прочитать с консоли строку неизвестной заранее длины не используя string?

Я прекрасно понимаю, что можно использовать класс string и просто написать cin>> str; а затем получить количество элементов. Я даже видел веселое решение при помощи malloc и realloc функций из C. но все же, интересно, есть ведь какой-то способ при помощи средств C++, а конкретно их потоков ввода и стандартных строк в виде массива символов прочитать из консоли строку, не имея понятия о ее размере, получить впоследствии ее размер и положить в динамически выделенный массив такого размера?? Вопрос не к спеху и не для какого-то задания, все чисто ради интереса, так что ваши ответы, типа "не парься и пользуйся тем, что дают" также приветствуются )


Ответ

cin >> str; запишет только до первого разделителя: http://ideone.com/Y5CJxD.
Если под строкой понимается последовательность, которая заканчивается переводом строки ('
'), то вам: std::getline() нужен: http://www.cplusplus.com/reference/string/string/getline/
А так, std::string это и так стандартное средство в C++. Если же хочется извратиться, то нужно читать блоками, проверять - есть ли перевод строки и агрегировать код, но лишнее нужно как-то хранить между вызовами. Либо, что проще, но медленнее - читать посимвольно, проверяя конец строки, например так:
istream& getline(istream& is, char *&buffer) { std::istream::sentry s(is); if (s) { std::istreambuf_iterator it(is); std::istreambuf_iterator end;
size_t size = 64; size_t grow = 64; size_t len = 0;
buffer = new char[size];
while (it != end && *it != '
') { if (len == (size - 1)) { buffer = buffer_realloc(buffer, size, size + grow); size += grow; }
buffer[len++] = *it++; }
buffer[len] = '\0'; }
return is; }
Здесь я не привожу функцию buffer_realloc() - она простая. Использовать как-то так:
char *line = nullptr; while (getline(std::cin, line)) { if (line) { cout << line << endl; delete[] line; } }
Либо вот вариант, где использует вектор:
istream& getline(istream& is, vector &buffer) { std::istream::sentry s(is); if (s) { std::istreambuf_iterator it(is); std::istreambuf_iterator end;
const size_t grow = 64; buffer.reserve(grow);
while (it != end && *it != '
') { if (buffer.size() == buffer.capacity() - 1) { buffer.reserve(buffer.size() + grow); }
buffer.push_back(*it++); } buffer.push_back('\0'); }
return is; }
Использовать как-то так:
vector line; while (getline(std::cin, line)) { if (!line.empty()) { cout << line.data() << endl; line.clear(); } }
Тут реаллокация памяти ложится на плечи vector'а. От вас только почистить его (а можно и в гетлайн всунуть). Плюс бонусом сразу длинна строки за O(1): line.size() - 1
Вот законченные примеры:
http://ideone.com/Huj4eQ http://ideone.com/CxNfg4
Но повторюсь: std::string стандартны для С++. Я слабо представляю условия, где есть потоки, но нет строк :)

Комментариев нет:

Отправить комментарий