1. Пользуйтесь тегами кода. - [code] ... [/code] 2. Точно указывайте язык, название и версию компилятора (интерпретатора). 3. Название темы должно быть информативным. В описании темы указываем язык!!!
Дан текстовый файл. Строки этого файла расположить в порядке убывания их длины и удалить пять самых коротких из них. Для размещения в памяти содержимого файлов использовать односвязные линейные списки.
Предполагаю заносить каждую строку в одно поле списка, но не знаю, как это сделать именно со строкой и сколько выделять памяти.
1) организацию циклов в С знаешь? Я имею в виду, синтаксис оператора цикла? for(начальное_присвоение;условие_окончания;и зменение_на_каждой_итерации) { собственно_операторы_тела_цикла; }
где начальное_присвоение - делается один раз перед началом цикла; условие_окончания - проверяется после завершения каждой итерации изменение_на_каждой_итерации - делается после завершения итерации ПЕРЕД проверкой условия_окончания
причем любой (!!!) из этих параметров может отсутствовать (моогут, кстати, отсутствовать и 2 и все 3 - тогда цикл будет "вечным", и выходе из него возможен будет только через break)...
А теперь с учетом этого - смотри, что происходит:
/* ВНЕШНИЙ цикл
Поскольку first передается как указатель на указатель (причину я объяснял выше), то L присваиваем значению разыменованного first (т.е. изначально L = указателю на голову списка)
Условие окончания внешнего цикла - (L->next) подразумевает НЕравенство этого значения нулю... То есть, как только значение L->next станет NULL, цикл завершится...
После обработки одной итерации продвигаемся по списку, путем L = L -> next */ for(L = *first; L -> next; L = L -> next)
/* ВНУТРЕННИЙ цикл изначально p = L -> next условие окончания: закончится цикл - когда p будет нулевым продвижение - понятно как осуществляется... */ for(p = L -> next; p; p = p -> next)
2)
Цитата
почему мы ставим здесь взятие адреса?
Потому, что я объяснил, зачем передается указатель на указатель, а чтобы передать его - надо взять адрес указателя...
3)
Цитата
здесь мы печатаем отсортированный по возрастанию длины список:
Опять же - смотри комментарии, и постарайся разобраться в принципе работы оператора цикла, я не могу каждый раз писать такие объемные комментарии...
/* изначально p = root окончание - когда p = NULL продвижение - p = p -> next */ for(p = root; p; p = p -> next) printf("%s\n", p -> number);
4)
Цитата
почему у нас тут такое условие завершения цикла?
Условие завершения может быть любым правильным логическим условием, в отличие от оператора For в Паскале... Что делается здесь: предварительно я n установил в 0, правда? После каждой итерации (т.е., после удаления очередного элемента) n увеличивается на 1, а так как нам надо удалить ЛИБО первые 5 элементов, ЛИБО, если их всего меньше 5, то все - мы ставим операцию AND, и как только одно из условий НЕ выполняется (или уже удалили 5 элементов и n = 5, или достигли конца цикла, и p = NULL) - то цикл завершается...
5)
Цитата
почему при печати оставшегося списка мы использует таокй цикл
я выше написал, что любой из параметров цикла может отсутствовать... Здесь отсутствует третий параметр - изменение значения после каждой итерации... Почему - потому, что это делается внутри цикла, и нет необходимости делать это еще раз...
for(p = root; p; ) { printf("%s\n", p -> number); p = (T = p) -> next; /* <--- вот эту строку ты разобрала, как она работает? */ free(T); }
в отмеченной строке происходит следующее: сначала выполняется действие в скобках, т.е. T = p, потом в p заносится новое значение, равное T -> next, то есть, фактически, старое p запоминается в переменной T, а потом p продвигается на следующий элемент списка...