LINUX.ORG.RU

Собственная функция getline

 


0

1

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

Задание

В этой задаче вам необходимо написать функцию getline, которая читает строку из стандартного потока ввода cin. Конец строки достигается, если прочитан символ '\n' или поток ввода прочитан полностью. Если прочитан символ '\n', то сохранять его в строку не нужно. Не забудьте, что строка должна оканчиваться нулевым символом. Всю выделенную динамически память, кроме результирующей строки, необходимо освободить - будьте внимательны! Указатель возвращенный из getline будет освобожден с помощью delete[].

Замечания:

выделяйте и освобождайте память в стиле C++, функция ничего не должна выводить (Sample Output в примере — это возвращаемое значении функции в формате длина:строка).

Sample Input:

Hello

, world!

Sample Output:

5:Hello

8:, world!

Дают шаблон функции:

#include <iostream>

using namespace std;

char *getline() {
    // put your code here
}

Я написал функцию:

#include <iostream>

using namespace std;

char *getline() {

	int i = 0;
	char c = '\0';
	char * b = new char[1000];
	while (cin.get(c)) {
		i++;
		if (c == '\n')
			break;
	    b[i-1] = c;
	}
	cout << i-1 << ":" << b;
	delete [] b;
}

Но она не проходит проверку на сайте курса, видимо где то я накосячил. И не совсем понятно как выделять память под строку размер которой ты не знаешь.

Вот дополнительные пояснения от преподавателя:

...нужно реализовать функцию getline, которая читает ровно одну строку, т. е. либо доходит до символа '\n', либо до конца входного потока (т. е. до состояния, когда в потоке не осталось символов). Больше ничего делать не надо (никакого дополнительного вывода, никакого main и тд). Функция main уже написана, она вызывает функцию getline, которую собственно вам и требуется реализовать. Надеюсь условия задания теперь понятны. Теперь касательно свободной памяти, тут вопрос не о количестве байт, а количестве выделенных участков. Так как размер строки, которую нужно прочитать не известен заранее, вполне возможно, что придется перевыделять память, и нужно позаботится о том, что старый участок памяти будет освобожден. Т. е. в результате функция должна вернуть указатель на единственный выделенный участок памяти, в котором будет храниться прочитанная строка, а все остальные выделенные участки памяти (если, конечно, они были выделены) должны быть освобождены.

Но один хрен, не пойму, что нужно сделать

★★

Последнее исправление: beastie (всего исправлений: 1)

Ответ на: комментарий от Pirr

Тестируй на разных наборах данных. Если в потоке пусто, возвращай NULL, а не «0:».

Shadow1251
()

выделяйте и освобождайте память в стиле C++

char *

Либо рыбка, либо сесть.

Deleted
()
Ответ на: комментарий от maloi

И да, c++ не очень хороший выбор для первого ЯП

maloi ★★★★★
()
Ответ на: комментарий от Pirr

Ну это как переливание из меньшей банки в большую, после чего меньшую банку удаляю

Только ты сначала всё наливаешь в меньшую, а потом пытаешься перелить.

Gvidon ★★★★
()
Ответ на: комментарий от grondek

realloc
выделяйте и освобождайте память в стиле C++

realloc - это СИ стиль. Юзай new.

ТС, тебе никакого шаблона (в C++ под шаблонами понимается это) не давали, а дали просто название функции.

Алгоритм твоего кода должен быть прост до безобразия - если тебе нельзя использовать строки в стиле C++, то создаешь при помощи операции new массив, скажем в 64 символа типа char. Далее, как только позиция вставляемого из потока в массив символа станет 64 (у тебя индексы идут с 0, 63 - последний), то ты создаешь новый массив в 2 раза больше предыдущего. Копируешь туда свой массив (только не по элементу а вспомнив, что элементы в массиве идут последовательно в памяти, т.е. юзаешь функцию memcpy, не забывая, что тебе третий параметр придётся умножать на количество элементов изначального массива (просто sizeof тут не прокатит, он тебе вернёт размер одного элемента, т.к. массив сделан через new). Потом удаляешь при помощи delete твой исходный массив и приравниваешь указателю на старый массив адрес нового, временного массива.

/thread

peregrine ★★★★★
()
Ответ на: комментарий от Gvidon

Спасибо всем принявшим участие в решении моей проблемы, вот рабочая функция которая проходит все тесты:

#include <iostream>

using namespace std;

char *getline() {

	int i = 0;
	char c;
	char * tmp = new char[1];
	while (cin.get(c) && (c != '\n')) {
		i++;
		tmp[i-1] = c;
		char * new_tmp = new char[i+1];
		for (int n=0;n<i;n++) new_tmp[n] = tmp[n];
		delete [] tmp;
		tmp = new_tmp;
	}
	tmp[i] = '\0';
	return tmp;
}
Pirr ★★
() автор топика
Ответ на: комментарий от peregrine

Прочитал, но наверно наши мозги по разному устроены. То, что Вы написали, далеко не «просто до безобразия», и вероятно потребует подключения дополнительных библиотек.

Pirr ★★
() автор топика
Ответ на: комментарий от anonymous

Нормально у него уже все в функции, неоптимально - да. Но утечек нет.

grondek
()

char *getline() {
...
delete [] b;}

Про возврат из функции нынче ничего не преподают?! Тред не читал, но осуждаю.

erfea ★★★★★
()
Ответ на: комментарий от Pirr

Да почти то же самое, только копировать массив не по элементу, а с помощью сишной функции memcopy.

peregrine ★★★★★
()

Но один хрен, не пойму, что нужно сделать

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

comp00 ★★★★
()
Ответ на: комментарий от erfea

Самое интересное, что в задании четко указано, что delete[] будет вызван в main'е. Но нет, его обязательно нужно вызывать, ведь пару слайдов назад преподаватель сказал, что выделенную память нужно обязательно очищать!

comp00 ★★★★
()
Ответ на: комментарий от Pirr

Ты хотя бы должен понимать, что такой код - ужас-ужас с точки зрения быстродействия. Годится только для сдачи задания на отвяжись.

В реальности такие вещи делают через выделение памяти большими блоками. Возможны минимум два подхода:

1) Связанный список из блоков, затем выделение «плоского» массива и копирование данных туда, затем удаление списка.

2) Перевыделение памяти с копированием каждый раз, когда кончается место в буфере. Несколько менее эффективно. Ты так и сделал, но увеличиваешь буфер на 1 байт - это чудовищно тормозит из-за медленного выделения памяти в куче.

В обоих случаях размер очередного выделяемого блока может каждый раз увеличиваться с целью минимизировать изпользование new - весьма затратной операции.

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

anonymous
()
Ответ на: комментарий от Pirr

Как проходящий этот же самый курс открою маленький секрет, если сразу выделить, скажем [10000], то программа проходит все проверки без дополнительных выделений. Это может не очень правильно с точки зрения экономии памяти, но в данном случае работает. Однако чисто для себя написал потом вариант с преферансом и поэтессами размером массива [64] и memcpy. Кстати ТС все правильно делает, копируя посимвольно: там в задании нужно ввести в окошко только саму функцию, даже main нет и подключать заголовочные файлы нельзя, так что не факт, что memcpy прокатит. «Перестать страдать фигней, отписаться от курса и заняться тем, что у тебя получается.» - позволю себе не согласиться, тренировка межушного узла, полезна при любой профессии, к тому же повышает шансы сохранить этот орган в здравии в глубокой старости.

AlonePasserby
()
Ответ на: комментарий от comp00

«Самое интересное, что в задании четко указано, что delete[] будет вызван в main'е.» Насколько я вижу он потом теряет доступ к этой памяти: tmp = new_tmp; А вот самая последняя версия да, очищается в main.

AlonePasserby
()
Ответ на: комментарий от AlonePasserby

Извините за беспокойство, прохожу тот же курс и ищу «коллег по несчастью» :) Застрял на паре задач и никак не могу сообразить, что к чему. Дедлайн уже прошел, но все равно, хотелось бы поглядеть на решение что бы для себя разобраться. Если не затруднит, напишите мне на tusechka111@yandex.ru

Kopay
()
Ответ на: комментарий от Pirr

char * tmp = new char[1];
...
char * new_tmp = new char[i+1];
...
delete [] tmp;
tmp = new_tmp;
...

Объясните пожалуйста почему в данном примере не происходит утечка памяти (или все же происходит?), в коде нет ни одного вызова delete [] new_tmp;

t1r
()
Ответ на: комментарий от t1r

С каждой итерацией цикла освобождается «предыдущий» new_tmp. Последний мы возвращаем из функции.

mix_mix ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.