Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Любая длина строки входного потока (ANSI C)

74K
11 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
Привет всем!
Я не студент, это не курсовая, не лаба, ничего такого. Я изучаю Си (Ansi C) самостоятельно, мне это интересно. Я работаю около года программистом PHP, пишу на нём лет 5, но там всё намного проще.
В общем читаю сейчас книгу Б.Кернигана и Д.Ритчи. Читаю, разбираю примеры, выполняю упражнения. И вот столкнулся с одним заданием, которое никак не могу разрешить. Как ни странно, но уже в первой главе.
Глава 1.9 Массивы символов. Сама тема полностью понятна, там нет ничего сложного. Работа листинга, который иллюстрирует материал - тоже ясна. Этот код считывает набор строк из входного потока и выводит в выходной самую длинную из них. Вот код (задолбался раскрашивать):

[FONT="Courier New"][COLOR="sienna"]#include <stdio.h>[/COLOR]
[COLOR="sienna"]#define MAXLINE 1000[/COLOR] [COLOR="seagreen"]/* максимальная длина строки в потоке */[/COLOR]

[COLOR="magenta"]int[/COLOR] getline([COLOR="magenta"]char[/COLOR] line[], [COLOR="magenta"]int[/COLOR] maxline);
[COLOR="magenta"]void[/COLOR] copy([COLOR="magenta"]char[/COLOR] to[], [COLOR="magenta"]char[/COLOR] from[]);

[COLOR="seagreen"]/* вывод самой длинной строки в потоке */[/COLOR]
main() [COLOR="darkred"]{[/COLOR][INDENT] [COLOR="magenta"]int[/COLOR] len; [COLOR="seagreen"]/* длина текущей строки */[/COLOR]
[COLOR="magenta"]int[/COLOR] max; [COLOR="seagreen"]/* текущая максивальная длина */[/COLOR]
[COLOR="magenta"]char[/COLOR] line[MAXLINE]; [COLOR="seagreen"]/* текущая введённая строка */[/COLOR]
[COLOR="magenta"]char[/COLOR] longest[MAXLINE]; [COLOR="seagreen"]/* самая длинная строка из введённых */[/COLOR]

max = 0;
[COLOR="blue"]while[/COLOR]((len = getline(line, MAXLINE)) > 0)[INDENT] [COLOR="blue"]if[/COLOR](len > max) [COLOR="darkred"]{[/COLOR][INDENT] max = len;
copy(longest, line);[/INDENT] [COLOR="darkred"]}[/COLOR][/INDENT] [COLOR="blue"]if[/COLOR](max > 0) [COLOR="seagreen"]/* была непустая строка */[/COLOR][INDENT] printf([COLOR="gray"]"%s"[/COLOR], longest);[/INDENT] [COLOR="blue"]return[/COLOR] 0;[/INDENT][COLOR="darkred"]}[/COLOR]

[COLOR="seagreen"]/* getline: считывает строку в s, возвращает ее длину */[/COLOR]
[COLOR="magenta"]int[/COLOR] getline([COLOR="magenta"]char[/COLOR] s[], [COLOR="magenta"]int[/COLOR] lim) [COLOR="darkred"]{[/COLOR][INDENT] [COLOR="magenta"]int[/COLOR] c, i;

[COLOR="blue"]for[/COLOR](i = 0; i < lim - 1 && (c = getchar()) != EOF && c != [COLOR="gray"]'\n'[/COLOR]; ++i)[INDENT] s = c;[/INDENT] [COLOR="blue"]if[/COLOR](c == [COLOR="gray"]'\n'[/COLOR]) [COLOR="darkred"]{[/COLOR][INDENT] s = c;
++i;[/INDENT] [COLOR="darkred"]}[/COLOR]
s = [COLOR="gray"]'\0'[/COLOR];
[COLOR="blue"]return[/COLOR] i;[/INDENT][COLOR="darkred"]}[/COLOR]

[COLOR="seagreen"]/* copy: копирует строку 'from' в 'to'; длина to считается достаточной */[/COLOR]
[COLOR="magenta"]void[/COLOR] copy([COLOR="magenta"]char[/COLOR] to[], [COLOR="magenta"]char[/COLOR] from[]) [COLOR="darkred"]{[/COLOR][INDENT] [COLOR="magenta"]int[/COLOR] i;

i = 0;
[COLOR="blue"]while[/COLOR]((to = from) != [COLOR="gray"]'\0'[/COLOR])[INDENT] ++i;[/INDENT][/INDENT][COLOR="darkred"]}[/COLOR][/FONT]

И с этим кодом всё ясно. В этом примере есть ограничение на максимально допустимую длину строки в 1000 символов. После главы идёт упражнение. Задание звучит так:
Цитата:
Доработайте главный модуль программы определения самой длинной строки так, чтобы она выводила правильное значение для какой угодно длины строк входного потока, насколько это позволяет текст.


До этого момента все задачи решались запросто. И дальше этой главы не сложные задания. Но это... Не пойму что-то никак. На php это решилось бы в несколько строк, а тут... Я гуглил и гугл вывел меня на этот сайт, я нашёл решение - динамические массивы и функция realloc, НО! В книге пока об этой функции ещё не рассказывалось! Соответственно авторы имеют ввиду какое-то другое решение. Кроме того, для решения упражнения, realloc здесь нужно встроить в функцию getline(). Однако в задаче говорится, что доработать нужно именно главный модуль программы (т.е. функцию main). Также добавлю, что ссылки на переменные и массивы массивов - тоже будет только в последующих главах. Пока об этом не упоминалось.
Вот ума не приложу, что же за решение такое должно быть у этой задачи? Что имели ввиду Керниган и Ритчи, когда придумывали это упражнение после этой главы, в самом начале книги?... В общем, подскажите, кто что думает, знает.

277
11 ноября 2011 года
arrjj
1.7K / / 26.01.2011
Ну вообще можно #define MAXLINE 1000 заменить на #define MAXLINE MAX_INT .... Также можно использовать вместо char массива std::string... Также если без вывода строки можно просто при вводе длину считать

P.S. [ code=cpp ]#include <blabla>[ /code ] (без пробелов)
 
Код:
#include <blabla>
11
11 ноября 2011 года
oxotnik333
2.9K / / 03.08.2007
интересно, а сколько ТС код раскрашивал?
уважуха за настойчивость
260
11 ноября 2011 года
Ramon
1.1K / / 16.08.2003
realloc
77K
11 ноября 2011 года
DayE
1 / / 11.11.2011
Я сделал много лет назад такую фунциклюшку и с тех пор горя не знаю

char *fgm(FILE *f) /* Чтение строки с выделением памяти */
{ char *b; int c, j=0, l=81;

if (f==NULL || feof(f)) return(NULL);
b = malloc(l);
a: c = getc(f);
if (c=='\n' || c==EOF) {
b[j++] = '\0';
if (j!=l) b = realloc(b,j);
return(b);
}
if (j >= l-1) { l += 80; b = realloc(b,l); }
b[j++] = c;
goto a;
}
/**********************/
Можно, конечно, ее сделать и поаккуратнее, но идея, надеюсь, понятна
74K
11 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
Раскришивал примерно 10-15 минут. Я попробовал воспользоваться тегом code, но толи я чё-то натупил, толи он ничего не подсвечивает. Вот подсказали - теперь буду знать про code=cpp.
По поводу #define MAXLINE MAX_INT
Я думал о чём-то таком (правда без MAX_INT, а просто на калькуляторе посчитал эти 2 миллиарда с чем-то). Но если учесть, что один елемент массива типа char занимает байт, то MAX_INT - это будет два с лишним гигабайта, получается. Не думаю, что такое могло имется ввиду. Кроме того, я пробовал создавать огромные массивы - не даёт. Ещё пока не знаю, почему, но мне кажется, что когда массив создаётся как
char arr[length];
то он помещается в кеш процессора, а не в оперативную память. А там места не так много. Мне на моём старом-престаром компе не удаётся создать массив более 12180 элементов (выяснено экспериментально - играл в "быки и коровы" с компилятором).
ОС даст приложению 2 гига оперативки, если в системе всего 512 М? :)
Цитата:
Также можно использовать вместо char массива std::string


std::string - тоже пока об этом в книге ничего не говорилось.
Строки выводить надо. Если бы не выводить - то тоже задача имела бы простое и понятное решение.
А так я не догоняю чего-то...
Такое ощущение, что эти Керниган с Ритчем решили поглумиться над читателями :-)
Либо переводчик что-то не совсем корректно перевёл.
Либо может ошибка какая произошла и это упражнение должно было идти где-то позже, после другой какой-то главы...

74K
11 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
Цитата: Ramon



Про realloc я знаю. Но ты наверно не прочитал до конца мой пост. Я не в обиде, там правда много текста. Но если интересно, почему я интересуюсь, возможно ли обойтись без realloc - можешь перечитать первый пост полностью.

74K
11 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
DayE,
у тебя в коде тоже используется realloc, его ещё не было в учебнике, соответственно я предполагаю, что упражнение должно решиться без него. И ссылок не было. И работа с файловой системой - тоже ещё не рассматривалась.
Всё-таки, наверно, это какая-то ошибка переводчика или упражнение не из той главы оказалось в начале книги.
20K
11 ноября 2011 года
sem2711
124 / / 23.09.2009
Прочитал задание в книге и пришло на ум следующее: нужно, чтобы функция getline() копировала только MAXLINE символов и усекала более длинную строку, но при этом возвращала длину исходной входной строки. То бишь, после s = '\0' считывание из потока ввода продолжается, счетчик символов увеличивается, но в строку s уже ничего не добавляется.
14
12 ноября 2011 года
Phodopus
3.3K / / 19.06.2008
Так а про динамические массивы уже было в учебнике? Может быть авторы имели в виду что-то другое?
ПыСы. Мне кажется главным модулем можно назвать модуль содержащий ф-ию main() а не саму ее.
74K
12 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
Phodopus
Да в том-то и дело, что динамических массивов ещё не было. И ссылок не было и про динамическую память не было. Я собственно и спросил о том, существует ли какое-то другое решение, без realloc?

А вообще благодарю всех отписавшихся. И извиняюсь, если кому-то показалось обидным или не уважительным то, что я обратился на ты. Как-то уже привык так...
14
12 ноября 2011 года
Phodopus
3.3K / / 19.06.2008
а указатели были?
74K
12 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
Не-а... Это вообще практически самое начало. 43-я страница. А начинается первая глава на 19-й (сперва там введения всякие и благодарности).
20K
12 ноября 2011 года
sem2711
124 / / 23.09.2009
Такое впечатление, что я - человек-невидимка, публикующий невидимые посты. Может, я как то неясно выразил свою мысль? Авторы имели ввиду ровно то, что в книге написано:
Цитата:
"... даже такая крохотная программка, как эта, содержит несколько нерешенных технических вопросов. Например, что делать функции main(), если ей встречается строка длиннее предельной длины? Функция getline() в этом отношении безопасна, поскольку прекращает ввод, как только массив заполнился, даже если еще не встретился символ конца строки. Проверяя длину строки и последний введенный символ, функция main() может определить, не чрезмерную ли длину имеет строка, а затем обработать эту ситуацию по своему усмотрению. Для краткости мы эту проблему пока игнорируем. Пользователь функции getline() никак не может знать заранее, какой длины будет вводимая строка, поэтому getline() производит проверку на переполнение. С другой стороны, пользователь copy() уже знает (или может выяснить) длину строки, поэтому мы решили не добавлять в нее контроль ошибок."


Ни о каких указателях, динамическом выделении памяти речи еще не было, это первая глава книги. И уж конечно в учебнике по языку C не могло быть речи о std::string. Поэтому правильная трактовка задания (imho) содержится в моем предыдущем, незамеченном никем, посте.

74K
12 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
sem2711,
Ага, благодарю за подсказку! Наверно, так оно и есть.
Просто как-то не проассоциировалась у меня фраза "чтобы она выводила правильное значение для какой угодно длины строк" именно с длиной строки. Та программа, которая приводится в пример в данной главе и которую нужно доработать - ведь не выводит вообще длины строк, только сами строки. И я подумал, что строку и нужно вывести :-)
277
12 ноября 2011 года
arrjj
1.7K / / 26.01.2011
Цитата: sem2711
Поэтому правильная трактовка задания (imho) содержится в моем предыдущем, незамеченном никем, посте.



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

20K
12 ноября 2011 года
sem2711
124 / / 23.09.2009
Цитата: arrjj
Неправильная трактовка. Выводить неполную строку не есть решение задачи. Поэтому твой пост и остался без внимания.



Ну, зачем же так категорично? Результатом работы программы должно быть определение строки с максимальным количеством символов, а не вывод этой строки на консоль. Существуют же в Windows, например, усеченные варианты путей с использованием замещающего символа "тильда".

277
12 ноября 2011 года
arrjj
1.7K / / 26.01.2011
Цитата: sem2711
Существуют же в Windows, например, усеченные варианты путей с использованием замещающего символа "тильда".



Для обратной совместимости с дос-программами где жесткое ограничение на имя файла 8.3 . А с твоим подходом проще вообще ничего никуда не копировать (как я и высказал предложение)

20K
12 ноября 2011 года
sem2711
124 / / 23.09.2009
arrjj,
Не в этом суть.
Цитата:
как я и высказал предложение


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

74K
12 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
arrjj,
Мне кажется, что если учесть, что мы не можем пользоваться динамической памятью, не можем создавать динамические массивы, не можем пользоваться указателями, а всё что есть для решения - это простой одномерный символьный массив заданного размера, а из памяти - только стек, то тут ничего и не придумаешь. И вывести самую большую из введённых строк полностью, не ограничивая жёстко её размер - тут не получится. Если бы мы получали строки, например, из файла - то можно было бы пройтись по всем строкам дважды - сперва получили бы длину самой большой, а потом уже создали массив с достаточным для её сохранения количеством элеметов и сохранили. А по вводу из консоли дважды не пройдёшься, не сохранив его... Ну, не просить же пользователя:
Цитата:
Извините, я забыл, что вы тут мне написали. Напишите пожалуйста ещё раз!
... Ваш ПК ...
-> _


А если так - то остаётся только та трактовка задачи, о которой написал sem2711.

Но если есть какие-то мысли о том, как всё-таки можно организовать решение с выводом полной строки (не ограничивая её размер) - было бы интересно узнать.
Я Си начал изучать совсем недавно и как-то непривык пока к подобным ограничениям. Я работаю с PHP, а там всё намного проще. Си - он ближе к железу, типа что-то между ассемблером и PHP тем же. Когда пишешь на PHP - вообще можно не думать о том, как всё устроено в компьютере, о том, как устроены массивы данных в памяти и т.д., а тут - приходится :-)))

260
12 ноября 2011 года
Ramon
1.1K / / 16.08.2003
Цитата: OlegSobachnik
Когда пишешь на PHP - вообще можно не думать о том, как всё устроено в компьютере, о том, как устроены массивы данных в памяти и т.д., а тут - приходится :-)))


Смелое утверждение.

14
12 ноября 2011 года
Phodopus
3.3K / / 19.06.2008
Придумать можно. И вы даже озвучили как. Хотя я начинаю сомневаться в правильной трактовке задания, и оно мне нравится все меньше и меньше. Трактовка sem2711 меня тоже не устраивает. И вообще про что они тут

Цитата:
насколько это позволяет текст.



Будет время, найду английский вар-т книжки (где-то валялся), погляжу

14
12 ноября 2011 года
Phodopus
3.3K / / 19.06.2008
Цитата: Phodopus
Будет время, найду английский вар-т книжки (где-то валялся), погляжу


А собственно вот. Отрываем переводчику все лишнее и торчащее:

Цитата:
Exercise 1-16. Revise the main routine of the longest-line program so it will correctly print the length of arbitrarily long input lines, and as much as possible of the text.


sem2711 достается пол-очка. Ну потому что не доказал свою т.з. :)

20K
12 ноября 2011 года
sem2711
124 / / 23.09.2009
Цитата: Phodopus

sem2711 достается пол-очка.


:) Да я ж не за очки... Просто человеку помочь хотел

74K
13 ноября 2011 года
OlegSobachnik
14 / / 11.11.2011
Цитата: Ramon
Смелое утверждение.


Не знаю, может и погорячился слегка, но в большинстве случаев достаточно знать сам PHP. По крайней мере о работе с памятью думать не приходится. :-)
sem2711, Phodopus
Благодарю за помощь :-)))

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог