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, которую собственно вам и требуется реализовать. Надеюсь условия задания теперь понятны. Теперь касательно свободной памяти, тут вопрос не о количестве байт, а количестве выделенных участков. Так как размер строки, которую нужно прочитать не известен заранее, вполне возможно, что придется перевыделять память, и нужно позаботится о том, что старый участок памяти будет освобожден. Т. е. в результате функция должна вернуть указатель на единственный выделенный участок памяти, в котором будет храниться прочитанная строка, а все остальные выделенные участки памяти (если, конечно, они были выделены) должны быть освобождены.

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

★★

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

Ты выделяешь 1000 байт под строку и все, а надо при достижении выделенного размера - делать realloc массива.

grondek ()

неужели хоть один с нормальным форматированием и вменяемым кодом? успех.

Убери 1000 и сделай динамически.

smilessss ★★★★★ ()

Ну и вообще, ты ничего не возвращаешь из функции, все, что ты выделил, ты и уничтожил в delete [] b

grondek ()

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

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

Ну да 1000 байт это я так сказать по незнанию сделал... т.е. нужно выделить небольшой участок под массив, затем в цикле проверять его заполненность, и если не хватает, то добавлять еще и в конце подчистить выделенный массив под введенную строку? Правильно?

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

1. Выделить массив какой-то длины.

2. Заполнять его входными данными.

3. Если массив переполнился, выделить большей длины, скопировать в него прочитанное, старый удалить. Перейти на п.2.

4. Если дошел до конца входных данных - вернуть прочитанное из функции. МАССИВ НЕ УДАЛЯТЬ!

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

Функцию тестировал, и она работает... но мне кажется, что я чего то недопонимаю в задании. Поэтому и обратился на форум.

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

И у тебя как минимум компилятор должен ругаться no return statement

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

Функцию тестировал, и она работает

Подсказка: что она должна возвращать?

Gvidon ★★★★ ()

Функцию тестировал, и она работает....

warning: no return statement in function returning non-void

Deleted ()

«instead of realloc(), try a vector» ©

© B. Stroustrupp, цитаты великих людей. Я бы заталкивал в вектор прочитанные char'ы, и после полученного '\0' (с учётом того, что количество прочитанных символов нам известно в переменной readSymbolsCount) вызывал бы конструктор char *returnArray = new char[readSymbolsCount];
И у меня, как у препода C++, вопрос: с какого виндузятника реализация функции getline() выводит что‑то, а потом удаляет прочитанное, вместо того, чтобы вернуть прочитанную инфу?!

Northsoft ★★ ()

Ну и в чём прикол так курс проходить?:)

Тем более, авторы просили не делать так как делаешь ты.

batbko ()

Вот исправил функцию, но все равно она не проходит тест на сайте курса:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

char *getline() {

	int i = 0;
	char c = '\0';
	char * b = new char[1];
	while (cin.get(c)) {
		i++;
		if (c == '\n')
			break;
	    b[i-1] = c;
	    b = (char *) realloc (b, 1+i * sizeof(char));
	}
	return b;
}
Pirr ★★ ()
Ответ на: комментарий от Pirr

Читай задание внимательней:

т. е. либо доходит до символа '\n', либо до конца входного потока

Товарищи со степика бы ли бы рады :)

batbko ()

Ты походу с http://www.stepic.org :)
Там можно только new/delete и new[]/delete[] использовать.
При чтении каждого символа делай новый массив на 1 больше предыдущего и копируй в него содержимое предыдущего + новый символ, не забывая перед возвратом добавлять длину строки с двоеточием.

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

Да со степика, решаю задачи.

Спасибо, сейчас попробую переписать функцию.

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

Что такое символ '\n' я понимаю, и отлавливаю его в своей функции... а вот, что такое «конец входного потока» с трудом представляю, но думаю что цикл while (cin.get(c)) {...} как раз и отловит этот «конец».

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

как преподу трёх курсов

http://ideone.com/4HrF1L так норм? Валидный код на плюсах. D: Но помимо этого? Кстати больше 4096 всё равно нельзя, realloc совершенно лишний. Но это на случай изменённого юзкейса, хотя тогда нужно проверять строку на \0, вместо \n.

wakuwaku ★★★★ ()
Последнее исправление: wakuwaku (всего исправлений: 3)
Ответ на: комментарий от Pirr

Вот исправил функцию, но все равно она не проходит тест на сайте курса:

И правильно, что не проходит:

char * b = new char[1];
b = (char *) realloc (b, 1+i * sizeof(char));

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

delete nmae;

я не умею в плюсы, наверное. :> Или, точнее, совершенно не умею связывать плюсы и си.

wakuwaku ★★★★ ()
Последнее исправление: wakuwaku (всего исправлений: 1)
Ответ на: комментарий от andreyu

Вот нашел кусок кода:

char* new_tmp = new (char*)[mtmp];
for (int n=0;n<min(mtmp,oldSize);n++) new_tmp[n] = tmp[n];
delete [] tmp;  // free up tmp
tmp = new_tmp;

Подскажите, если я это влеплю в свою функцию это поможет?
Pirr ★★ ()
Ответ на: комментарий от Pirr

Вот новая функция, что опять я делаю не так? У меня она работает а на сайте выдает: Failed test #3. Run time error: *** glibc detected *** ./main: malloc(): memory corruption (fast): Ну хоть до 3 теста, доходит и то хорошо.

#include <iostream>

using namespace std;

char *getline() {

	int i = 0;
	char c;
	char * tmp = new char[0];
	while (cin.get(c) && (c != '\n')) {
		i++;
		tmp[i-1] = c;
		char * new_tmp = new char[0];
		for (int n=0;n<i;n++) new_tmp[n] = tmp[n];
		delete [] tmp;
		tmp = new_tmp;
	}
	return tmp;
}

Pirr ★★ ()
Последнее исправление: Pirr (всего исправлений: 1)
Ответ на: комментарий от wakuwaku

кстати, если прочитать всё-таки условие задачи, необходимо добавить также проверку на EOF, там tl;dr , поэтому я не читал. (: и кроме того задача сделать это всё плюсовыми средствами, следовательно итераторы тут выглядят уместно. (:

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

C++

char *

Нет, я люблю пожаловаться на плюсы, но это даже для меня слишком

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

Компилить необходимо с -Wall как минимум. Тогда всё станет яснее.

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

Удивляюсь, зачем такие люди пишут тут комментарии? Ну не хочешь человеку помочь, ну пройди мимо. Нет... нужно обязательно вставить свою «многозначительную фразу» и отвернуться.

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

Суть в том, чтобы ты сам понял, а мы можем только подсказывать. (: Выше я привёл пример, выкинуть чисто сишные заморочки, подогнать по условия задачи и готово. :>

«конец входного потока» — это EOF, кмк, следовательно, условием цикла будет проверка на '\n', '\0', и EOF (ctrl-d/ctrl-z)

и ещё можно помещать результат в переменную точно необходимого размера, вместо выставления нуля в середине буфера, но на практике проблемы от потенциального оверхэда маловероятны и просто пустая трата временни и вычислительных ресурсов, хоть оно так и «не оккуратненько».

wakuwaku ★★★★ ()
Последнее исправление: wakuwaku (всего исправлений: 3)
Ответ на: комментарий от wakuwaku

EOF в плюсах более цивилизованным способом проверяется :)

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

strncpy, или может быть даже strlcpy, хотя конкретно в моём коде strcpy — самое то.

wakuwaku ★★★★ ()
Последнее исправление: wakuwaku (всего исправлений: 1)
Ответ на: комментарий от batbko

Я ценю все ответы на этом форуме, и не сколько не хочу, чтобы за меня решили задачу. Но в своем решении я не вижу очевидных ошибок, иначе бы исправил их.

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

Да я вообще не программист, и программистом никогда не стану. А курс прохожу для общего развития и чтобы мозг не усох :) Давно хотел познакомиться с С++ поближе, а тут как раз бесплатный курс подвернулся. Вот и наслаждаюсь так сказать процессом.

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

Ошибки:
1) Выделение куска памяти нулевого размера. Стандарт С++ в таком случае гарантирует, что оно сработает, но вернётся тебе какая-то неведомая вундервафля, с которой только и можно сделать, что засунуть в delete []. Не делай так, начни хотя бы с размера 1.
2) Перевыделяешь ты опять же нулевой размер. Чего ты этим хочешь добиться? Тебе нужно увеличивать твой буфер.
3) Нет проверки на EOF, уже писали выше
4) Тебе нужно вернуть сишную строку, об это в условии даже отдельно написано. Ноль в конец за тебя Пушкин ставить будет?

Это только то, что бросается в глаза сразу

Gvidon ★★★★ ()
Ответ на: комментарий от 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];
		for (int n=0;n<i;n++) new_tmp[n] = tmp[n];
		delete [] tmp;
		tmp = new_tmp;
	}
	tmp[i] = '\0';
	return tmp;
}

Вот я подправил функцию, но все равно она не проходит 3 тест на сайте. Может еще какие нибудь ошибки?

Failed test #3. Run time error: *** glibc detected *** ./main: invalid fastbin entry (free): 0x00000000015446d0 *** ======= Backtrace: ========= [0x46ff92] [0x474b77] [0x4009c6] [0x4003e3] [0x457e33] [0x400789] ======= Memory map: ======== 00400000-00521000 r-xp 00000000 ca:00 677348 /home/stepic/instances/master/arena/codejail-de3bok/main 00721000-00728000 rw-p 00121000 ca:00 677348 /home/stepic/instances/master/arena/codejail-de3bok/main 00728000-0073f000 rw-p 00000000 00:00 0 01542000-01565000 rw-p 00000000 00:00 0 [heap] 7feb18000000-7feb18021000 rw-p 00000000 00:00 0 7feb18021000-7feb1c000000 ---p 00000000 00:00 0 7feb1e55b000-7feb1e55c000 rw-p 00000000 00:00 0 7fff61d45000-7fff61d66000 rw-p 00000000 00:00 0 [stack] 7fff61dff000-7fff61e00000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

Pirr ★★ ()
Последнее исправление: Pirr (всего исправлений: 1)
Ответ на: комментарий от Pirr

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

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

Ну это как переливание из меньшей банки в большую, после чего меньшую банку удаляю. Только вот сейчас думаю... а действительно ли я создаю больший буфер? Но ведь все работает и функция выводит нужную строку.

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