Любая длина строки входного потока (ANSI C)
Я не студент, это не курсовая, не лаба, ничего такого. Я изучаю Си (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). Также добавлю, что ссылки на переменные и массивы массивов - тоже будет только в последующих главах. Пока об этом не упоминалось.
Вот ума не приложу, что же за решение такое должно быть у этой задачи? Что имели ввиду Керниган и Ритчи, когда придумывали это упражнение после этой главы, в самом начале книги?... В общем, подскажите, кто что думает, знает.
P.S. [ code=cpp ]#include <blabla>[ /code ] (без пробелов)
уважуха за настойчивость
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;
}
/**********************/
Можно, конечно, ее сделать и поаккуратнее, но идея, надеюсь, понятна
По поводу #define MAXLINE MAX_INT
Я думал о чём-то таком (правда без MAX_INT, а просто на калькуляторе посчитал эти 2 миллиарда с чем-то). Но если учесть, что один елемент массива типа char занимает байт, то MAX_INT - это будет два с лишним гигабайта, получается. Не думаю, что такое могло имется ввиду. Кроме того, я пробовал создавать огромные массивы - не даёт. Ещё пока не знаю, почему, но мне кажется, что когда массив создаётся как
char arr[length];
то он помещается в кеш процессора, а не в оперативную память. А там места не так много. Мне на моём старом-престаром компе не удаётся создать массив более 12180 элементов (выяснено экспериментально - играл в "быки и коровы" с компилятором).
ОС даст приложению 2 гига оперативки, если в системе всего 512 М? :)
std::string - тоже пока об этом в книге ничего не говорилось.
Строки выводить надо. Если бы не выводить - то тоже задача имела бы простое и понятное решение.
А так я не догоняю чего-то...
Такое ощущение, что эти Керниган с Ритчем решили поглумиться над читателями :-)
Либо переводчик что-то не совсем корректно перевёл.
Либо может ошибка какая произошла и это упражнение должно было идти где-то позже, после другой какой-то главы...
Про realloc я знаю. Но ты наверно не прочитал до конца мой пост. Я не в обиде, там правда много текста. Но если интересно, почему я интересуюсь, возможно ли обойтись без realloc - можешь перечитать первый пост полностью.
у тебя в коде тоже используется realloc, его ещё не было в учебнике, соответственно я предполагаю, что упражнение должно решиться без него. И ссылок не было. И работа с файловой системой - тоже ещё не рассматривалась.
Всё-таки, наверно, это какая-то ошибка переводчика или упражнение не из той главы оказалось в начале книги.
ПыСы. Мне кажется главным модулем можно назвать модуль содержащий ф-ию main() а не саму ее.
Да в том-то и дело, что динамических массивов ещё не было. И ссылок не было и про динамическую память не было. Я собственно и спросил о том, существует ли какое-то другое решение, без realloc?
А вообще благодарю всех отписавшихся. И извиняюсь, если кому-то показалось обидным или не уважительным то, что я обратился на ты. Как-то уже привык так...
Ни о каких указателях, динамическом выделении памяти речи еще не было, это первая глава книги. И уж конечно в учебнике по языку C не могло быть речи о std::string. Поэтому правильная трактовка задания (imho) содержится в моем предыдущем, незамеченном никем, посте.
Ага, благодарю за подсказку! Наверно, так оно и есть.
Просто как-то не проассоциировалась у меня фраза "чтобы она выводила правильное значение для какой угодно длины строк" именно с длиной строки. Та программа, которая приводится в пример в данной главе и которую нужно доработать - ведь не выводит вообще длины строк, только сами строки. И я подумал, что строку и нужно вывести :-)
Неправильная трактовка. Выводить неполную строку не есть решение задачи. Поэтому твой пост и остался без внимания.
Ну, зачем же так категорично? Результатом работы программы должно быть определение строки с максимальным количеством символов, а не вывод этой строки на консоль. Существуют же в Windows, например, усеченные варианты путей с использованием замещающего символа "тильда".
Для обратной совместимости с дос-программами где жесткое ограничение на имя файла 8.3 . А с твоим подходом проще вообще ничего никуда не копировать (как я и высказал предложение)
Не в этом суть.
Вот это действительно важно. Об этом и я говорил. Если не брать во внимание ситуацию, когда две "запредельные строки" отличаются по длине на один символ в конце одной из них, то вывод даже усеченной до MAXLINE строки может дать пользователю исчерпывающую информацию.
Мне кажется, что если учесть, что мы не можем пользоваться динамической памятью, не можем создавать динамические массивы, не можем пользоваться указателями, а всё что есть для решения - это простой одномерный символьный массив заданного размера, а из памяти - только стек, то тут ничего и не придумаешь. И вывести самую большую из введённых строк полностью, не ограничивая жёстко её размер - тут не получится. Если бы мы получали строки, например, из файла - то можно было бы пройтись по всем строкам дважды - сперва получили бы длину самой большой, а потом уже создали массив с достаточным для её сохранения количеством элеметов и сохранили. А по вводу из консоли дважды не пройдёшься, не сохранив его... Ну, не просить же пользователя:
... Ваш ПК ...
-> _
А если так - то остаётся только та трактовка задачи, о которой написал sem2711.
Но если есть какие-то мысли о том, как всё-таки можно организовать решение с выводом полной строки (не ограничивая её размер) - было бы интересно узнать.
Я Си начал изучать совсем недавно и как-то непривык пока к подобным ограничениям. Я работаю с PHP, а там всё намного проще. Си - он ближе к железу, типа что-то между ассемблером и PHP тем же. Когда пишешь на PHP - вообще можно не думать о том, как всё устроено в компьютере, о том, как устроены массивы данных в памяти и т.д., а тут - приходится :-)))
Смелое утверждение.
Будет время, найду английский вар-т книжки (где-то валялся), погляжу
А собственно вот. Отрываем переводчику все лишнее и торчащее:
sem2711 достается пол-очка. Ну потому что не доказал свою т.з. :)
sem2711 достается пол-очка.
:) Да я ж не за очки... Просто человеку помочь хотел
Не знаю, может и погорячился слегка, но в большинстве случаев достаточно знать сам PHP. По крайней мере о работе с памятью думать не приходится. :-)
sem2711, Phodopus
Благодарю за помощь :-)))