Как да научим да преодоляваме трудности и същевременно да пишем цикли

Въпреки че темата е основна, тази статия е написана за опитни специалисти. Целта е да се покажат заблужденията, с които се срещат начинаещите програмисти. За практикуващите разработчици тези проблеми отдавна са решени, забравени или изобщо не забелязвани. Статията може да бъде полезна, ако случайно ви се наложи да помогнете на някого с тази тема. В статията се правят паралели с материали от различни книги по програмиране на Шилдт, Страуструп и Окулов.

Темата за цикли е избрана, защото много хора отпадат, когато се учат на програмиране.

Тази методика е предназначена за студенти със слаби умения. Обикновено, силните студенти не затъват в тази тема и не е необходимо да се измислят особени методики за тях. Второстепенната цел на статията е да прехвърли тази методика от класа "работи за всички студенти, но само при един преподавател" в клас "работи за всички студенти и преподаватели". Не претендирам за абсолютна оригиналност. Ако вече прилагате подобна методика за обучение по тази тема, моля, споделете с какво вашият вариант се различава. Ако решите да я приложите, споделете как мина всичко. Ако подобна методика е описана в някоя книга, моля, напишете заглавието.


Работих по тази методика 4 години, занимавайки се индивидуално с студенти с различно ниво на подготовка. Общият брой студенти е около петдесет и две хиляди часа занимания. Поначало в тази тема студентите затъваха и отпадаха. След всеки студент методиката и материалите се коригираха. През последната година студентите вече не затъват в тази тема, така че реших да споделя натрупаните знания.

Защо толкова много букви? Циклите са елементарни!

Както споменах по-горе, за практикуващите разработчици и силните студенти, сложността на концепцията за цикли може да бъде недооценявана. Например, може да се изнесе дълга лекция, да се видят кимващи глави и умни лица. Но при опит за решаване на някаква задача, започва блокада и необясними проблеми. След лекцията на студентите несъмнено им е останало само частично разбиране. Ситуацията се усложнява от факта, че студентите не могат сами да формулират в какво точно се състои тяхното заблуждение.
Веднъж осъзнах, че студентите възприемат примерите ми като йероглифи. Тоест, като неделими парчета текст, в които трябва да добавят някаква "магическа" буква, за да заработят.
Понякога забелязвах, че студентите смятат, че за решаването на конкретна задача е необходима поредна друга конструкция, за която просто не съм говорил още. Въпреки че за решението беше нужно само да модифицирам примера.

Затова стигнах до идеята, че основното внимание трябва да бъде върху синтаксиса на изразите, а върху концепцията за рефакториране на повтарящ се код с помощта на цикли. Щом веднъж учениците усвоят тази идея, всякакъв синтаксис ще дойде с малко упражнения.

Кому и защо преподавам

Тъй като няма входни изпити, в занятията могат да присъстват както силни, така и много слаби студенти. По-подробно за моите студенти можете да прочетете в статията Портрет на слушателите на вечерните курсове
Стремя се да направя така, че програмирането да бъде достъпно за всички, които го желаят.
Занятията ми се провеждат индивидуално и студентът плаща за всяко. Още по-очевидно е, че студентите ще оптимизират разходите и ще искат минимум. Въпреки това, хората посещават присъствени занятия с жив преподавател не само за знания, а за увереност относно това, което са усвоили, за усещането за напредък и за одобрение от експерт (преподавател). Ако студентите не усещат напредък в обучението си, те ще си тръгнат. Като цяло, занятията могат да бъдат построени така, че студентите да усещат напредък в увеличаването на познатите им конструкции. Тоест, първо подробно изучаваме while, после for, след това do while и ето, че имаме курс за хиляда и една нощ, в който два месеца изучаваме само цикли, а накрая - студент, който е написал стандартната библиотека под диктовка. Въпреки това, за да решават практически задачи, е необходимо не само знание на материала, но и самостоятелност в неговото прилагане и търсене на нова информация. Затова за присъствените курсове смятам, че е правилен принципът - да научим минимум и да насърчава самостоятелното изучаване на нюанси и свързани теми. В темата за цикли, минимумът, който смятам, е конструкцията while. На нея може да се разбере принципът. Знаейки принципа, може да се овладее и for, и do-while самостоятелно.

За да се постигне усвояването на материала от по-слабите студенти, описанието на синтаксиса не е достатъчно. Нужно е да се дават повече прости, но разнообразни задачи и да се описват примери по-подробно. В крайна сметка скоростта на усвояване е ограничена от способността на студента да преобразува изрази и да търси закономерности. За по-умните студенти повечето задачи ще бъдат скучни. При занятия с тях не е задължително да се настойва на решаването на 100% от задачите. Моят материал може да се види на моят GitHub. Вярно е, че репозиторието повече прилича на гримуар на чернокнижник – никой, освен мен, няма да разбере какво и къде се намира, а ако провалите проверката, може да полудеете.

Методиката е ориентирана към практика.

Теорията се обяснява на примера на решаване на задача. На занятия по основите на програмирането, където се изучават разклонения и цикли, просто не може да се организира полезна лекция по една тема за цял час. 15-20 минути са достатъчни, за да се обясни концепцията. Основните затруднения се появяват при изпълнението на практическите задачи.
Начинаещите преподаватели могат да изброят оператори, разклонения, цикли и масиви за една лекция. Само че студентите им ще се сблъскат с проблема на усвояването на тази информация.
Нужно е не само да се разказва материал, но и да се уверим, че слушателите са го разбрали.

Фактът на усвояването на темата се определя от това как студентът се справя със самостоятелната работа.
Ако студентът е успял да реши задача по темата без помощта на преподавателя, значи темата е усвоена. За да се осигури самостоятелна проверка, за всяка задача се описва таблица с тестови сценарии. Задачите имат ясно изразен ред. Неправилно е да се пропускат задачи. Ако текущата задача е твърде сложна, преминаването към следващата е безполезно. Тя е още по-сложна. За да може студентът да се справи с текущата сложна задача, му се обясняват няколко техники на примера на първата задача. Всъщност, всичкото съдържание на темата се свежда до техники за преодоляване на трудности. Циклите са по-скоро страничен ефект.

Първата задача винаги е пример. Втората не се различава много и се изпълнява "самостоятелно" веднага след първата под наблюдението на преподавателя. Всички последващи задачи са насочени към това да обърнат внимание на различни детайли, които могат да предизвикат недоразумения.

Обяснението на примера представлява диалог, в който студентът трябва да извика обратно пропагиране и крос-сериеналиране, за да се увери в усвояването на част от материала.

Ще бъда банален и ще заявя, че първият пример по темата е много важен. При наличие на материал за обширна самостоятелна работа, пропускането на първия пример може да бъде поправено. Ако освен примера няма нищо друго, то студентът вероятно няма да усвои темата.

While или for?

Един от спорните въпроси е изборът на конструкция за примера: while или for. Един мой познат практикуващ разработчик без опит в преподаването ме убеждаваше един час, че цикълът for е най-простият за разбиране. Аргументите се свеждаха до „в него всичко е ясно и подредено“. Въпреки това, истинската причина за затрудненията на новаците е самата идея на цикъла, а не неговото написване. Ако човек не разбере тази идея, той ще има затруднения с синтаксиса. След като идеята е осъзната, проблемите с оформлението на кода изчезват.

В моите материали темата за циклите следва темата за разклонения. Външното сходство между if и while позволява да се проведе пряка аналогия: „когато условието в заглавието е истина, се изпълнява тялото“. Особенността на цикъла е, че тялото се изпълнява многократно.

Моят втори аргумент е, че while изисква по-малко оформлениe, отколкото for. По-малко оформлениe — по-малко глупави грешки с пропуснати запетаи и скобички. При новаците вниманието и прецизността не са достатъчно развити, за да избягват автоматично синтактични грешки.
Третият аргумент — в много добри книги while се обяснява първо.

Ако на студента му е лесно да преобразува изрази, то може да се разкаже за for между другото. Студентът ще избере какво му харесва повече. Ако обаче преобразуванията предизвикват затруднения, по-добре е да не разсейва вниманието. Нека първо студентът реши всичко с помощта на while. Когато темата за циклите е усвоена, може да се пренаписват решенията, за да се упражни преобразуването от while в for.
Циклите с постусловие са доста редък вид. За тях не отделям време изобщо. Ако студентът е усвоил идеите за откриване на закономерности и преобразуване на изрази, то той ще може да се справи без моя помощ.

При демонстрация на първия пример на силните студенти, акцентирам върху това, че в първия пример е важно да се запише не само решението, но и целият процес на действия, довели до резултата. Ленивите студенти могат да пренебрегнат написаното и да пренесат само окончателния алгоритъм. Трябва да ги убедим, че веднъж и за тях може да се случи сложна задача. За нейното решаване ще е необходимо да преминат стъпка по стъпка, както в този пример. Ето защо е важно да се запишат всички етапи. В следващите задачи може да се остави само финалният вариант на решението.

Основната идея на автоматизацията е, че възлагаме на компютъра да изпълнява рутинната работа вместо човека. Един от основните подходи е писането на цикли. Той се прилага, когато в програмата последователно се извършват няколко еднакви повторяющи се действия.

Явното е по-добре от неявното

Може да изглежда добра идея в първата задача с цикли да се изведе на екрана някаква еднаква фраза няколко пъти. Например:

Ура, работи!
Ура, работи!
Ура, работи!
Ура, работи!
Ура, работи!
Ура, работи!
Ура, работи!
Ура, работи!

Тази версия е лоша, защото в извода не се вижда стойността на брояча. Това е проблем за начинаещите. Не трябва да се подценява. Поначало тази задача беше първа, а задачата за извеждане на поредица от числа по нарастване — втора. Приходеше се до въвеждането на допълнителни термини „цикъл N пъти“ и „цикъл от A до B“, които по същество са едно и също. За да не се множат ненужни единици, реших да покажа само примера с извеждането на поредицата от числа. Малцина успяват без подготовка да запомнят брояча и да моделират поведението на програмата в главата си. Някои студенти за първи път срещат моделирането „в ума“ именно по темата за циклите.
След известно практикуване, задачата за повторение на еднакъв текст я давам за самостоятелно решаване. Ако първо се даде видим брояч, а след това невидим, студентите изпитват по-малко проблеми. Понякога е достатъчна подсказката „не пиши брояча на екрана“.

Как се обяснява при другите?

В повечето учебни материали в интернет, синтаксис на цикъла се представя в рамките на "лекция". Например, на developer.mozilla.org (в момента) заедно с цикъла while се описват още няколко конструкции. При това, самите конструкции се дават единствено под формата на шаблони. Резултатът от тяхното изпълнение се описва с думи, а илюстрация липсва. Според мен, такова представяне на темата намалява полезността на материалите до нула. Учениците могат да препишат кода и да го стартират сами, но все пак им е нужен еталон за сравнение. Как да разберем, че примерът е изпълнен правилно, ако нямаме с какво да сравним резултата?
Когато се дава единствено шаблон, без пример, на студента става още по-трудно. Как да разбере, че фрагментите от кода са подредени правилно в шаблона? Може да опита да напише по някакъв начин, а след това да го стартира. Но ако няма еталон за сравнение на резултата, то стартирането също няма да помогне.

В курса по C++ на интуите синтаксисът на цикъла е заровен на третата страница на лекция 4 по темата "оператори". При обяснението на синтаксиса на циклите се акцентира особено на термина "оператор". Терминът се подава под формата на набор от факти като "символ; това е оператор", "{} е съставен оператор", "тялото на цикъла трябва да бъде оператор". Такъв подход не ми харесва, защото по някакъв начин прикрива важни взаимовръзки зад един термин. Анализът на изходния код на програмата на такова ниво е необходим на разработчиците на компилатори за реализиране на спецификацията на езика, но определено не и на студентите в началото. Начинаещите в програмирането рядко притежават достатъчно педантичност, за да се отнасят толкова внимателно към термините. Рядък човек запомня и разбира нови думи от първия път. Практически никой не може правилно да приложи термин, който току-що е научил. Затова у студентите възникват куп грешки като "написах while(a<7);{, а програмата не работи".
Според мен, в началото е по-добре да се даде синтаксисът на конструкцията веднага с къдричките. Вариантът без къдрички да се обяснява единствено ако на ученика възникне конкретен въпрос "защо тук без къдрички и работи".

В книгата на Окулов "Основи на програмирането" от 2012 г. запознаването с цикли започва с шаблона for, след това се дават препоръки за неговото използване, а после следва експерименталната част на занятието. Разбирам, че книгата е написана за малцинството от много способни ученици, които рядко идват на моите занятия.

В популярните книги винаги се описва резултатът от фрагменти от код. Например, в книгата на Шилдт "Java 8. Пълно ръководство" от 2015 г. Първо се дава шаблон, после примерна програма и веднага след това — резултатът от изпълнението.

Като пример ще разгледаме цикъла while, в който се изпълнява обратен
отсчет, започвайки от 10, и се извеждат точно 10 реда "тактове":

//Продемонстрировать применение оператора цикла while
class While {
    public static void main(String args []) {
        int n = 10;
        while (n > 0) {
            System.out.println("такт " + n);
            n--;
        }
    }
}

След стартиране, тази програма извежда десет "тактове" по следния начин:
такт 10
такт 9
такт 8
такт 7
такт 6
такт 5
такт 4
такт 3
такт 2
такт 1

Подходът с описание на шаблона, примерна програма и резултата от работата на тази програма се използва и в книгата "Javascript за деца" и в курса по js на w3schools.com. Форматът на уеб страницата дори позволява да направите този пример интерактивен.

В книгата на Страуструп "Принципи и практика с използването на C++" от 2016 г. авторът е отишъл още по-далеч. Първо се обяснява какъв резултат трябва да се получи, а след това се показва текста на програмата. Като пример се взема не просто случайна програма, а се прави излет в историята. Това помага да се обърне внимание на нея "Виж, това не е просто някакъв безполезен текст. Виждаш нещо значимо."

Като пример за итерация ще разгледаме първата програма, изпълнена на машина с хранима програма (EDSAC). Тя е написана от Дейвид Уилер (David Wheeler) в компютърната лаборатория на Кеймбриджкия университет (Cambridge University, England) на 6 май 1949 г. Тази програма изчислява и отпечатва прост списък от квадрати.
0 0
1 1
2 4
3 9
4 16
...
98 9604
99 9801

Тук във всеки ред има число, следвано от знак за табулация ('t') и квадрата на това число. Версията на тази програма на език C++ изглежда така:

//Вычисляем и распечатываем таблицу квадратов чисел 0-99
int main()
{
    int i = 0; // Начинаем с нуля
    while(i < 100){
        cout << i << 't' << square(i) << 'n';
        ++i;
    }
}

Любопитно е, че шаблонът на синтаксиса в тази книга не се описва. Страуструп в ръководството за инструктори (превод) акцентира на това, че уважава интелекта на своите студенти. Вероятно умението да се открие шаблон в няколко примера и се счита за проявление на такъв интелект.

Както обяснявам аз сам

Подходът на Страуструп: описание на резултата, след това решение на проблема и накрая самостоятелен анализ от студента — изглежда най-продумано. Затова реших да взема за основа именно него, но да разкажа с по-малко исторически пример — задачата за извеждане на „съдържание“. Тя формира разпознаваемо заглавие, за да можем по-късно да кажем „помни задачата за съдържанието“ и студентите да помнят точно нея. В примера си се опитах да предупредя за още две от най-разпространените заблуди. По-нататък ще пиша за тях по-подробно.

На тази задача се запознаваме с методите за решаване на сложни проблеми. Първоначалното решение трябва да бъде примитивно и просто. А после може да помислим как да подобрим това решение.
Въведение
Глава 1
Глава 2
Глава 3
Глава 4
Глава 5
Глава 6
Глава 7
Заключение

Според моите наблюдения, подходът „шаблон-пример-резултат“ в различни комбинации все още води до това, че студентите възприемат цикълът като иероглиф. Това се проявява в това, че те не разбират защо трябва да пишат условие, как да избират между i++ и i— и други на пръв поглед очевидни неща. За да се избегнат тези заблуди, подходът към обяснението на цикли трябва да подчертае смисъла на повторението на идентични действия и едва след това — оформлението им с помощта на конструкцията. Затова преди да дам синтаксиса на цикъла, трябва да решим задачата „направо“. Примитивното решение на задачата за съдържание изглежда така:

Console.WriteLine("Въведение");
Console.WriteLine("Глава 1");
Console.WriteLine("Глава 2");
Console.WriteLine("Глава 3");
Console.WriteLine("Глава 4");
Console.WriteLine("Глава 5");
Console.WriteLine("Глава 6");
Console.WriteLine("Глава 7");
Console.WriteLine("Заключение");

Как може да бъде подобрено?
Да заменим еднообразните действия с цикъл.
Кои действия се повтарят последователно без изменения?
В този фрагмент такива няма. Впрочем командите за извеждане на дума „Глава“ с номера са много подобни една на друга.
Затова следваща стъпка е да се търси разликата между фрагментите. Само в тази задача всичко е очевидно, по-късно ще се повторят не отделни команди, а блокове код от 5 реда или повече. Ще се наложи да се търси не просто в списъка на командите, а в конструкциите на разклонение или цикъл.
В примера разликата между командите е в числото след думата „Глава“.
След като разликата е намерена, трябва да се разбере закономерността на изменението. Различаващият се фрагмент е число? То постоянно увеличава ли се или намалява? Как се изменя стойността на числото между двете команди една до друга?
В примера числото след думата «Глава» се увеличава с 1. Разликата е открита, закономерността е идентифицирана. Сега можем да заменим различаващия се фрагмент с променлива.
Трябва да обявим такава променлива преди първия от повтарящите се фрагменти. Тази променлива обикновено се нарича I или j, или нещо по-разширено. Началната й стойност трябва да бъде равна на първото изведено на екрана значение. В примера първото значение е 1.
Каква начална стойност трябва да вземем за извеждане на редица числа «100, 101, 102, 103, 104, 105»?
В тази редица първото число е 100.
След всяка команда за извеждане трябва да увеличим стойността на тази променлива с 1. Тази единица е стъпката на изменение.
Каква стъпка ще бъде в реда на числата «100, 102, 104, 106»?
В тази редица стъпката е 2.
След замяната на различаващия се фрагмент с променлива, кодът ще изглежда така:

Console.WriteLine("Въведение");
int i;
i = 0;
Console.WriteLine("Глава " + i);
i = i + 1;
Console.WriteLine("Глава " + i);
i = i + 1;
Console.WriteLine("Глава " + i);
i = i + 1;
Console.WriteLine("Глава " + i);
i = i + 1;
Console.WriteLine("Глава " + i);
i = i + 1;
Console.WriteLine("Глава " + i);
i = i + 1;
Console.WriteLine("Глава " + i);
i = i + 1;
Console.WriteLine("Заключение");

След прилагане на метода «изразяване на закономерността с променлива», в кода се получава няколко групи одинакови действия, които следват едно след друго. Сега повтарящите се действия могат да бъдат заменени с цикъл.

Последователността на решаване на задача, при която трябва да се използват цикли, се състои от следните етапи:

  1. Да решим „наудар“ с множество отделни команди
  2. Да намерим закономерност
  3. Да изразим закономерността с променлива
  4. Да оформим под формата на цикъл

След това се въвеждат нови термини, за да не се окаже студентът в ситуацията «всичко разбирам, но не мога да кажа»:
— брояч — винаги променлива, която е необходима за проследяване на количеството стъпки на цикъла. Обикновено е цяло число, което се сравнява с ограничение.
— стъпка на брояча — описание на закономерността на изменението на брояча.
— ограничение — число или променлива, с която се сравнява броячът, за да е алгоритъмът краен. Стойността на брояча се променя така, че да се приближава до ограничението.
— тяло на цикъла — набор от команди, които ще бъдат повтаряни. Когато се казва „командата е написана в тялото на цикъла“, се има предвид точно тялото.
— итерация на цикъла — еднократно изпълнение на тялото на цикъла.
— условие на цикъл — логическо изразяване, от което зависи дали ще се извърши още една итерация. (Тук е възможна объркване с конструкциите за разклонение)
Трябва да сме подготвени за това, че в началото студентите ще използват термините неправилно. Това важи както за силните, така и за слабите. Налагането на общ език е истинско изкуство. Сега ще напиша накратко: трябва да зададем задача "подчертай фрагмент от кода с ", и сами правилно да използваме тези термини в разговора.
След преобразуването с цикъл получаваме фрагмент:

Console.WriteLine("Въведение");
int i = 0;
while (i < 7) {
    Console.WriteLine("Глава " + i);
    i = i + 1;
}
Console.WriteLine("Заключение");

Основно заблуждение

Едно популярно заблуждение на студентите е, че те поставят в конструкцията на цикъла действия, които трябва да се извършат само веднъж. Например така:

;
int i = 0;
while (i < 7) {
    Console.WriteLine("Въведение")
    Console.WriteLine("Глава " + i);
    i = i + 1;
    Console.WriteLine("Заключение");
}

Учениците постоянно се сблъскват с този проблем, както в началото, така и в по-сложни задачи.
Основният съвет в този случай:

Колко пъти трябва да се повтаря написването на командата: веднъж или много?

Командите за изход на думите "Въведение" и "Заключение", както и обявяването и инициализацията на променливата i не приличат на другите повтарящи се действия. Те се изпълняват само веднъж, следователно трябва да бъдат написани извън тялото на цикъла.

В кода трябва да останат всичките три етапа на решението, за да можем по-късно да се позоваваме на тях в случай на затруднения. Първите две версии е достатъчно да коментираме, за да не пречат.
Вниманието на студента трябва да бъде насочено към следните факти:
— В условието на цикъла обикновено се сравняват броячът и ограничението. Броячът може да се променя в тялото на цикъла, а ограничението — не. За да нарушим това правило, трябва да формулираме основателни причини.
— Командите за изход на думите "Въведение" и "Заключение" са извън тялото на цикъла. Нужно е да ги изпълним 1 път. "Въведение" — преди повторението на действия, "Заключение" — след.
По време на усвояването на тази тема, изучаването на следващите, а също и при разискването на затруднения дори на силните студенти е полезно да се зададе въпросът: "А това действие колко пъти трябва да се извърши? Един или много?".

Развитие на допълнителни умения

В процеса на изучаване на цикли, при студентите се развива умението за диагностика и решаване на проблеми. За да проведе диагностика, на студента му е необходимо да представи желан резултат и да го сравни с фактическия резултат. От разликата между тях зависят действията за корекция.
Тъй като студентите на този етап все още слабо си представят "желания" резултат, те могат да се ориентират по тестовите данни. Обикновено никой на този етап не осъзнава какво може да се обърка и как да се справи с това. Затова давам под запис в тетрадката описание на типични проблеми и няколко начина за решаването им. Изборът на най-подходящото от тях е задача на самия студент.
Записът е необходим, за да се пита "Получило ли се е това, което се очакваше?", "Коя от тези ситуации се е получила сега?", "Помогна ли приложеното решение?".

  1. Броят на действията е с 1 по-малко или повече, отколкото се очаква. Начини за решаване:
    — увеличете началната стойност на брояча с 1.
    — заменете строгия оператор за сравнение () с нестрогия (=).
    — променете стойността на ограниченията с 1.
  2. Действията в цикъла се изпълняват без спиране, безкрайно. Начини за решаване:
    — добавете команда за промяна на брояча, ако тя липсва.
    — коригирайте командата за промяна на брояча, така че да се доближи до ограниченията.
    — премахнете командата за промяна на ограниченията, ако тя е в тялото на цикъла.
  3. Броят на действията в цикъла е с повече от 1 по-малко или повече, отколкото се очаква. Действието в цикъла не е било изпълнено нито веднъж. Първо трябва да изясните фактическите стойности на променливите непосредствено преди началото на цикъла. Начини за решаване:
    — променете началната стойност на ограниченията.
    — променете началната стойност на брояча.

Обикновено проблем 3 е свързан с използването на неподходяща променлива или ненулиране на брояча.

След това обяснение, на студента все още може да му останат различни заблуждения относно работата на циклите.
За да развея най-разпространените, давам задачи:

  1. В която ограничението, началната стойност на брояча или стъпката на брояча се въвежда от потребителя.
  2. В която стойността на брояча трябва да се използва в някакво аритметично изразяване. Желателно е с брояча в подкоренното изразяване или в знаменателя, за да бъде разликата нелинейна.
  3. В който стойността на брояча не се показва на екрана по време на работа на цикъла. Например, за извеждане на нужното количество еднакви текстови фрагменти или за нарисуване на фигура с черепашка графика.
  4. В който трябва първо да се изпълнят едни повтарящи се действия, а след това други.
  5. В който трябва да се изпълнят други действия преди и след повтарящите се.

За всяка задача трябва да се предоставят тестови данни и очакван резултат.

За да разберем колко бързо можем да напредваме, трябва да дадем на студента да прочете условията на задачите и да попитаме: „с какво се различават от примера?“, „Какво трябва да се промени в примера, за да ги решим?“. Ако студентът отговори осмислено, тогава нека реши поне една на урока, а останалите – самостоятелно вкъщи. Ако решението е успешно, можем да започнем обяснението относно условията в цикли.
Ако има трудности с самостоятелното решаване, трябва всичко да се отработи в час. За да не напомня решението на рисуване на сова, препоръчвам първо да решите задачата неуниверсално. Тоест така, че решението да премине първия тест и да не използва конструкция на цикъл. А след това да приложим преобразования, за да постигнем универсалност на решението.

Цикли и разклонения

Според мен е полезно да се даде темата „цикли в разклонения“ отделно. Така ще се види разликата между многократната проверка на условието и единичната.
Задачите за затвърдяване ще бъдат за извеждане на числа от А до В, зададени от потребителя:
— винаги по нарастващ ред.
— по нарастващ или намаляващ ред в зависимост от стойностите на А и В.

К темата „разклонения в цикли“ трябва да преминем само след като студентът е усвоил техниките: „замяна на закономерността с променлива“ и "замяна на повтарящи се действия с цикъл".
Основната причина за прилагането на разклонения в цикли е аномалии в закономерността. В средата тя се нарушава в зависимост от входните данни.
На тези студенти, които могат да търсят решение чрез комбиниране на прости техники, е достатъчно да се каже „разклоненията могат да се пишат в цикли“ и да се даде задача „за пример“ напълно за самостоятелно решаване.
Задача за пример:

Потребителят въвежда число Х. Изведете в колона числата от 0 до 9 и сложете знак ‘+’ срещу числото, което е равно на Х.

Ако е въведено 00+
1
2
3
4
5
6
7
8
9

Ако е въведено 60
1
2
3
4
5
6+
7
8
9

Ако е въведено 90
1
2
3
4
5
6
7
8
9+

Ако е въведено 7770
1
2
3
4
5
6
7
8
9

Ако краткото обяснение не е достатъчно, за да се напише с цикъл, трябва да се намери универсално решение на същата задача без цикъл.
Ще се получи един от два варианта:
Желан

string temp;
temp = Console.ReadLine();
int x;
x = int.Parse(temp);
if (x==0) {
    Console.WriteLine(0 + "+");
} else {
    Console.WriteLine(0);
}
if (x==1) {
    Console.WriteLine(1 + "+");
} else {
    Console.WriteLine(1);
}
if (x==2) {
    Console.WriteLine(2 + "+");
} else {
    Console.WriteLine(2);
}
if (x==3) {
    Console.WriteLine(3 + "+");
} else {
    Console.WriteLine(3);
}
if (x==4) {
    Console.WriteLine(4 + "+");
} else {
    Console.WriteLine(4);
}
if (x==5) {
    Console.WriteLine(5 + "+");
} else {
    Console.WriteLine(5);
}
if (x==6) {
    Console.WriteLine(6 + "+");
} else {
    Console.WriteLine(6);
}
if (x==7) {
    Console.WriteLine(7 + "+");
} else {
    Console.WriteLine(7);
}
if (x==8) {
    Console.WriteLine(8 + "+");
} else {
    Console.WriteLine(8);
}
if (x==9) {
    Console.WriteLine(9 + "+");
} else {
    Console.WriteLine(9);
}

Възможен

string temp;
temp = Console.ReadLine();
int x;
x = int.Parse(temp);
if (x==0) {
    Console.WriteLine("0+n1n2n3n4n5n6n7n8n9");
}
if (x==1) {
    Console.WriteLine("0n1+n2n3n4n5n6n7n8n9");
}
if (x==2) {
    Console.WriteLine("0n1n2+n3n4n5n6n7n8n9");
}
if (x==3) {
    Console.WriteLine("0n1n2n3+n4n5n6n7n8n9");
}
if (x==4) {
    Console.WriteLine("0n1n2n3n4+n5n6n7n8n9");
}
if (x==5) {
    Console.WriteLine("0n1n2n3n4n5+n6n7n8n9");
}
if (x==6) {
    Console.WriteLine("0n1n2n3n4n5n6+n7n8n9");
}
if (x==7) {
    Console.WriteLine("0n1n2n3n4n5n6n7+n8n9");
}
if (x==8) {
    Console.WriteLine("0n1n2n3n4n5n6n7n8+n9");
}
if (x==9) {
    Console.WriteLine("0n1n2n3n4n5n6n7n8n9+");
}

Подобна задача давам предварително, по време на изучаване на темата за разклонения.
Ако студентът е получил "възможен" вариант, трябва да се обясни, че решенията на същата задача могат да бъдат многобройни. Но те се различават по устойчивост към промени в изискванията. Задайте въпрос: "Колко места в кода ще трябва да се поправят, ако трябва да добавим още едно число?" В "възможния" вариант ще трябва да добавите още едно разклонение и да допишете новото число на 10 други места. В "желания" е достатъчно да добавите само едно разклонение.
Поставете задачата да се възпроизведе "желания" вариант, след което намерете закономерност в кода, извършете замяна на променливата и напишете цикъл.
Ако имате идея как да решите тази задача без цикъл по друг начин, моля, напишете в коментарите.

Цикли вътре в цикли

В тази тема трябва да се обърне внимание на следното:
— броячите за вътрешния и външния цикъл трябва да бъдат различни променливи.
— броячът за вътрешния цикъл трябва да се нулира много пъти (т.е. в тялото на външния цикъл).
— В задачите за извеждане на текст не може първо да напишете една буква в няколко реда, а след това друга. Трябва първо да извлечете всички букви от първия ред, след това всички букви от втория и така нататък.

Обяснението на темата за циклите вътре в цикли е най-добре да започне с обяснение за важността на нулирането на брояча.
Задача за пример:

Потребителят въвежда две числа: R и T. Да се извеждат два реда символи "#". В първия ред трябва да има R символа. Във втория ред T символа. Ако някое от числата е отрицателно, да се извежда съобщение за грешка.

R=5, T=11#####
###########

R=20, T=3####################
###

R=-1, T=6Стойността на R трябва да бъде неотрицателна

R=6, T=-2Стойността на T трябва да бъде неотрицателна

Очевидно, че тази задача има поне два варианта за решение.
Желан

string temp;
int R;
int T;
temp = Console.ReadLine();
R = int.Parse(temp);
temp = Console.ReadLine();
T = int.Parse(temp);
int i = 0;
while (i < R)
{
    Console.Write("#");
    i = i + 1;
}
Console.WriteLine();
i = 0;
while (i < T)
{
    Console.Write("#");
    i = i + 1;
}

Възможен №1

string temp;
int R;
int T;
temp = Console.ReadLine();
R = int.Parse(temp);
temp = Console.ReadLine();
T = int.Parse(temp);
int i = 0;
while (i < R)
{
    Console.Write("#");
    i = i + 1;
}
Console.WriteLine();
int j = 0;
j = 0;
while (j < T)
{
    Console.Write("#");
    j = j + 1;
}

Разликата е, че в "възможното" решение за извеждане на втория ред е използвана втора променлива. Трябва да настоявате за използването на една и съща променлива за двата цикъла. Аргументирането на това ограничение може да бъде, че решението с един брояч за два цикъла ще бъде илюстрация на термина "нулиране на брояча". Разбирането на този термин е необходимо при решаването на следващите задачи. Като компромис, можем да запазим и двете решения на задачата.

Типичен проблем с използването на една променлива-брояч за два цикъла се проявява така:
R=5, T=11#####
######

Броят на символите във втория ред не отговаря на стойността на T. Ако се нуждаете от помощ с този проблем, трябва "да насочите носа" към конспекта за типични проблеми с циклите. Това е симптом №3. Диагностицира се, ако добавите извеждане на стойността на брояча непосредствено преди втория цикъл. Изправя се чрез нулиране. Но по-добре е да не го разказвате веднага. Студентът трябва да се опита да формулира поне една хипотеза.

Разбира се, има и такъв вариант на решение. Но не съм го виждал у студентите досега. На етапа на изучаване на циклите, разказът за него ще разсейва вниманието. Можем да се върнем към него по-късно, при изучаване на функции за работа със стрингове.
Възможен №2

стринг temp;
int R;
int T;
temp = Console.ReadLine();
R = int.Parse(temp);
temp = Console.ReadLine();
T = int.Parse(temp);
Console.WriteLine(new String('#', R));
Console.WriteLine(new String('#', T));

Следваща задължителна задача:

Изведете на екран цифрите от 0 до 9. Всяка цифра трябва да бъде на отделен ред. Броят на цифрите в реда (W) се въвежда от клавиатурата.

W=10
1
2
3
4
5
6
7
8
9

W=100000000000
1111111111
2222222222
3333333333
4444444444
5555555555
6666666666
7777777777
8888888888
9999999999

Ако студентът е овладял приемането на променлива, той ще се справи доста бързо. Възможен проблем ще бъде отново с нулирането на променливата. Ако не успява с преобразуването, значи сте се забързали и трябва да решавате по-опростени задачи.

Благодаря за вниманието. Слагайте лайкове, абонирайте се за канала.

P.S. Ако сте намерили печатни грешки или грешки в текста, моля, уведомете ме. Можете да го направите, като маркирате част от текста и натиснете на Mac «⌘ + Enter», а на класическите клавиатури «Ctrl / Enter», или чрез лични съобщения. Ако тези опции не са налични, напишете за грешките в коментарите. Благодаря!

Само регистрирани потребители могат да участват в анкетата. Влезте, моля.

Анкета за читателите без карма

  • 20,0%Преподавам професионално, +12

  • 10,0%Преподавам професионално, -11

  • 70,0%Не преподавам, +17

  • 0,0%Не преподавам, -10

  • 0,0%Друго0

Гласували 10 потребители. Въздържали се 5 потребители.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster