Mimo że temat wydaje się podstawowy, ten artykuł jest napisany z myślą o doświadczonych specjalistach. Jego celem jest pokazanie typowych błędów, które popełniają nowicjusze w programowaniu. Dla praktykujących programistów te problemy są już dawno rozwiązane, zapomniane lub wręcz niezauważane. Artykuł może być pomocny, jeśli nagle będziesz musiał pomóc komuś w tej kwestii. W artykule porównano materiały z różnych książek na temat programowania autorstwa Shields, Stroustrupa, Okulowa.
Temat cykli został wybrany, ponieważ na nim odpada wielu ludzi podczas nauki programowania.
Ta metoda jest skierowana na słabszych studentów. Z reguły silni nie utkną na tym etapie i nie ma potrzeby wymyślania specjalnych metod dla nich. Drugorzędnym celem artykułu jest przetłumaczenie tej metody z klasy "działa na wszystkich studentach, ale tylko u jednego nauczyciela" do klasy "działa u wszystkich studentów, wszystkich nauczycieli". Nie roszczę pretensji do absolutnej oryginalności. Jeśli już stosujesz podobną metodę w nauczaniu tego tematu, proszę, napisz, czym twój wariant się różni. Jeśli zdecydujesz się na zastosowanie jej, daj znać po zakończeniu, jak wszystko poszło. Jeśli podobna metoda jest opisana w jakiejś książce, napisz proszę tytuł.
Pracowałem nad tą metodą przez 4 lata, prowadząc indywidualne zajęcia ze studentami o różnym poziomie przygotowania. Łącznie około pięćdziesięciu studentów i dwa tysiące godzin zajęć. Na początku na tym etapie studenci nieustannie utknęli i znikali. Po każdym studencie metoda i materiały były korygowane. Ostatni rok studenci już nie utknęli na tym etapie, więc postanowiłem podzielić się swoimi materiałami.
Czemu tyle słów? Cykle to przecież elementarna sprawa!
Jak już pisałem wcześniej, dla praktykujących programistów i silnych studentów trudność koncepcji cykli może być niedoceniana. Na przykład można przeprowadzić długą wykład, zobaczyć kiwające głowy i mądre oczy. Ale podczas rozwiązywania jakiegoś zadania pojawia się zawirowanie i niewytłumaczalne problemy. Po wykładzie studenci z pewnością mają tylko częściowe zrozumienie. Sytuację pogarsza to, że studenci nie potrafią sami sformułować, w czym dokładnie tkwi ich błąd.
Pewnego razu uświadomiłem sobie, że studenci postrzegają moje przykłady jak hieroglify. To znaczy, jak niepodzielne fragmenty tekstu, w które należy wpisać jakąś „magiczną” literę, by to zadziałało.
Czasami zauważałem, że studenci myślą, że do rozwiązania konkretnego zadania potrzebna jest jakakolwiek inna konstrukcja, o której po prostu jeszcze nie wspomniałem. Chociaż do rozwiązania wystarczyło jedynie nieco zmodyfikować przykład.
Dlatego doszedłem do wniosku, że należy skupić się nie na składni wyrażeń, ale na idei refaktoryzacji powtarzającego się kodu za pomocą pętli. Gdy tylko uczniowie opanują tę ideę, każdy składnia będzie przyswajana poprzez małe ćwiczenia.
Kogo i po co uczę
Ponieważ nie ma egzaminów wstępnych, na zajęciach mogą być zarówno silni, jak i bardzo słabi studenci. Więcej o moich studentach można przeczytać w artykule
Dążyłem do tego, aby programowanie opanowali wszyscy, którzy tego pragną.
Moje zajęcia odbywają się indywidualnie, a student płaci własne pieniądze za każde. Wydawałoby się, że studenci będą optymalizować koszty i domagać się minimum. Jednak ludzie przychodzą na zajęcia stacjonarne z żywym nauczycielem nie tylko po wiedzę, ale także po pewność, że zdążyli przyswoić materiał, poczucie postępu oraz akceptację ze strony eksperta (nauczyciela). Jeśli studenci nie będą czuli postępu w swoim nauczaniu, odejdą. Ogólnie zajęcia można tak budować, aby studenci odczuwali postęp w zwiększającej się liczbie znanych konstrukcji. To znaczy, najpierw dokładnie badamy while, potem uczymy się for, potem do while i oto mamy kurs na tysiąc i jedną noc, w którym przez dwa miesiące uczymy się tylko pętli, a na końcu — student, który od dyktanda napisał standardową bibliotekę. Jednak do rozwiązywania praktycznych zadań potrzebna jest nie tylko znajomość materiału, ale także samodzielność w jego zastosowaniu i w poszukiwaniu nowych informacji. Dlatego w przypadku kursów stacjonarnych uważam za słuszne podejście — nauczyć minimum i zachęcać do samodzielnego studiowania niuansów i pokrewnych tematów. W temacie pętli minimum stanowi konstrukcja while. Na jej podstawie można zrozumieć zasadę. Znając zasadę, można samodzielnie opanować for i do-while.
Aby osiągnąć przyswojenie materiału przez słabszych uczniów, opisanie składni nie wystarczy. Należy zadawać więcej prostych, ale różnorodnych zadań i dokładniej opisywać przykłady. Ostatecznie prędkość przyswajania ogranicza zdolność ucznia do przekształcania wyrażeń i wyszukiwania wzorców. Dla inteligentnych uczniów większość zadań będzie nudna. Podczas zajęć z nimi, nie trzeba upierać się przy rozwiązaniu 100% zadań. Mój materiał można zobaczyć na . Jednak repozytorium bardziej przypomina grimuar czarodzieja — nikt, poza mną, nie zrozumie, co gdzie się znajduje, a jeśli się zawali kontrola, można zwariować.
Metodyka koncentruje się na praktyce.
Teoria jest wyjaśniana na przykładzie rozwiązywania zadań. Na zajęciach wprowadzających do programowania, gdzie uczone są instrukcje warunkowe i pętle, po prostu nie da się zorganizować użytecznej wykładu na jeden temat przez całą godzinę. 15-20 minut wystarcza, aby wyjaśnić koncepcję. Główne trudności pojawiają się podczas wykonywania zadań praktycznych.
Zaczynający nauczyciele mogą wykładać operatory, instrukcje warunkowe, pętle i tablice na jednej lekcji. Tylko uczniowie napotkają problem z przyswajaniem tych informacji.
Trzeba nie tylko opowiedzieć materiał, ale także upewnić się, że słuchacze go zrozumieli.
Fakt przyswojenia tematu określa się po tym, jak uczeń radzi sobie z pracą samodzielną.
Jeśli uczniowi udało się rozwiązać zadanie na temat bez pomocy nauczyciela, to znaczy, że temat został przyswojony. Aby zapewnić samodzielną kontrolę, do każdego zadania dołączona jest tabela z testowymi scenariuszami. Zadania mają wyraźnie określoną kolejność. Nie zaleca się pomijania zadań. Jeśli obecne zadanie jest zbyt trudne, sens przechodzenia do następnego jest znikomy. Ono jest jeszcze trudniejsze. Aby uczeń mógł poradzić sobie z bieżącym trudnym zadaniem, tłumaczone mu są różne techniki na przykładzie pierwszego zadania. Właściwie cała treść tematu sprowadza się do technik pokonywania trudności. Pętle to raczej efekty uboczne.
Pierwsze zadanie zawsze jest przykładem. Drugie różni się niewiele i jest wykonywane "samodzielnie" natychmiast po pierwszym pod czujnym okiem nauczyciela. Wszystkie kolejne zadania mają na celu zwrócenie uwagi na różne szczegóły, które mogą prowadzić do nieporozumień.
Wyjaśnienie przykładu to dialog, w którym student musi wykonać propagację wsteczną oraz walidację krzyżową, aby upewnić się, że opanował część materiału.
Będę banałem i stwierdzę, że pierwszy przykład na temat - jest bardzo ważny. Posiadając materiał do szerokiej pracy samodzielnej, można naprawić pominięcia pierwszego przykładu. Jeśli poza przykładem nie ma nic więcej, to student prawdopodobnie nie opanuje tematu.
While czy for?
Jednym z kontrowersyjnych pytań jest wybór konstrukcji do przykładu: while czy for. Pewnego razu mój znajomy praktykujący programista bez doświadczenia w nauczaniu przez godzinę przekonywał mnie, że pętla for jest najprostsza do zrozumienia. Argumenty sprowadzały się do "wszystko jest zrozumiałe i uporządkowane". Jednak prawdziwym źródłem trudności dla początkujących jest sama idea pętli, a nie jej zapis. Jeżeli ktoś nie zrozumie tej idei, będzie miał trudności ze składnią. Gdy tylko idea zostanie zrozumiana, problemy z formatowaniem kodu znikają same.
W moich materiałach temat pętli następuje po temacie warunków. Zewnętrzne podobieństwo if i while pozwala na bezpośrednią analogię: "gdy warunek w nagłówku jest prawdziwy, wykonuje się ciało". Specyfika pętli polega jedynie na tym, że ciało jest wykonywane wiele razy.
Mój drugi argument jest taki, że while wymaga mniej formatowania niż for. Mniej formatowania - mniej głupich błędów z pominiętymi przecinkami i nawiasami. U początkujących uwaga i dokładność nie są jeszcze na tyle rozwinięte, żeby automatycznie unikać błędów składniowych.
Trzeci argument - w wielu dobrych książkach while wyjaśnia się jako pierwszy.
Jeżeli studentowi udaje się łatwo przekształcać wyrażenia, można wspomnieć o for mimochodem. Student później sam wybierze, co mu bardziej odpowiada. Jeśli jednak przekształcenia sprawiają trudności, lepiej nie rozpraszać uwagi. Niech najpierw student rozwiązuje wszystko przy użyciu while. Kiedy temat pętli zostanie opanowany, można przepisać rozwiązania, aby ćwiczyć przekształcanie while na for.
Pętle z warunkiem końcowym to dość rzadki zjawisko. Na ten temat w ogóle nie poświęcam czasu. Jeśli student opanował idee wykrywania wzorców i przekształcania wyrażeń, poradzi sobie bez mojej pomocy.
Podczas prezentacji pierwszego przykładu silnym studentom zwracam uwagę na to, że w pierwszym przykładzie ważne jest, aby utrwalić nie tylko rozwiązanie, ale także całą sekwencję działań, które doprowadziły do wyniku. Lenistwo studentów może prowadzić do tego, że zaniedbają spisanie kroków i przekażą sobie jedynie końcowy algorytm. Należy ich przekonać, że kiedyś napotkają trudne zadanie. Aby je rozwiązać, trzeba będzie postępować krok po kroku, jak w tym przykładzie. Dlatego tak ważne jest, aby uwiecznić wszystkie etapy. W następnych zadaniach można będzie zostawić tylko ostateczną wersję rozwiązania.
Główna idea automatyzacji polega na tym, że zlecając komputerowi wykonywanie rutynowej pracy za człowieka. Jednym z podstawowych sposobów jest pisanie pętli. Zastosowuje się je, gdy w programie realizuje się kilka tych samych powtarzających się działań pod rząd.
Jawne jest lepsze niż domyślne
Może się wydawać dobrą myślą w pierwszym zadaniu dotyczącym pętli wyświetlenie na ekranie jakiegoś powtarzającego się zdania kilka razy. Na przykład:
Hurra, działa!
Hurra, działa!
Hurra, działa!
Hurra, działa!
Hurra, działa!
Hurra, działa!
Hurra, działa!
Hurra, działa!
Taka opcja jest zła, ponieważ w wyniku nie widać wartości licznika. To problem dla początkujących. Nie należy go lekceważyć. Na początku to zadanie było pierwsze, a zadanie dotyczące wyświetlania ciągu liczb w porządku rosnącym — drugie. Trzeba było wprowadzać dodatkowe terminy „pętla N razy” i „pętla od A do B”, które w istocie są tym samym. Aby nie mnożyć zbędnych bytów, postanowiłem pokazać tylko przykład z wyświetlaniem ciągu liczb. Niewielu udaje się bez przygotowania nauczyć się utrzymać w głowie licznik i modelować zachowanie programu w myśli. Niektórzy studenci po raz pierwszy stykają się z modelowaniem „w myślach” na temat pętli.
Po pewnej praktyce zadanie polegające na powtarzaniu tego samego tekstu zadaję do samodzielnego rozwiązania. Jeśli najpierw podam widoczny licznik, a potem niewidoczny, studenci mają mniej problemów. Czasami wystarczy podpowiedź „nie pisz licznika na ekranie”.
Jak to jest wyjaśniane u innych?
W większości materiałów dydaktycznych w Internecie składnia pętli przedstawiana jest w ramach „wykładu”. Na przykład na developer.mozilla.org (obecnie) razem z pętlą while opisanych jest jeszcze kilka konstrukcji. Przy tym podawane są wyłącznie same konstrukcje w postaci szablonów. Wynik ich uruchomienia opisywany jest słowami, a ilustracja jest nieobecna. Moim zdaniem, taki sposób prezentacji tematu całkowicie ogranicza użyteczność takich materiałów. Uczeń może przepisać kod i uruchomić go sam, ale etalon do porównania i tak jest potrzebny. Jak zrozumieć, że przykład został poprawnie przepisany, jeśli nie ma czego porównać z wynikiem?
Kiedy podany jest tylko szablon, bez przykładu, studentowi staje się jeszcze trudniej. Jak zrozumieć, że fragmenty kodu są umieszczone w szablonie poprawnie? Można spróbować napisać jakoś, a potem uruchomić. Ale jeśli nie ma etalonu do porównania wyniku, to uruchomienie również nie pomoże.
W kursie C++ na Intuit synataks pętli jest zakopany na trzeciej stronie wykładu 4 na temat „operatory”. Przy wyjaśnieniu składni pętli kładzie się szczególny nacisk na termin „operator”. Termin ten przedstawiony jest w postaci zestawu faktów, takich jak „symbol; to operator”, „{} to operator złożony”, „ciało pętli musi być operatorem”. Taki sposób podejścia mi się nie podoba, ponieważ w pewien sposób ukrywa ważne powiązania za jednym terminem. Analiza kodu źródłowego programu na takim poziomie jest potrzebna deweloperom kompilatorów do realizacji specyfikacji języka, ale nikomu innemu na początku. Nowicjusze w programowaniu rzadko mają wystarczającą skrupulatność, by tak uważnie podchodzić do terminów. Nikt nie zapamiętuje i nie rozumie nowych słów za pierwszym razem. Praktycznie nikt nie potrafi poprawnie zastosować terminu, którego dopiero co się nauczył. Dlatego studenci mają mnóstwo błędów, takich jak „napisałem while(a<7);{, a program nie działa”.
Moim zdaniem, na początku lepiej jest podać składnię konstrukcji od razu ze wszystkimi nawiasami. Opcję bez nawiasów należy wyjaśniać tylko w przypadku, gdy uczeń zada konkretne pytanie „dlaczego tu bez nawiasów i działa?”.
W książce Okulowa „Podstawy programowania” z 2012 roku wprowadzenie do pętli zaczyna się od szablonu for, następnie podane są zalecenia dotyczące jego użycia, a potem od razu przechodzi się do eksperymentalnej części zajęć. Rozumiem, że książka została napisana dla tego mniejszości bardzo utalentowanych uczniów, którzy rzadko przychodzą na moje zajęcia.
W popularnych książkach zawsze podawany jest wynik fragmentów kodu. Na przykład w książce Schildta „Java 8. Pełne przewodnictwo” z 2015 roku. Najpierw podany jest szablon, potem przykład programu, a zaraz po nim — wynik wykonania.
Jako przykład rozważmy pętlę while, w której wykonywany jest odwrócony
odczyt, zaczynając od 10, i wyświetlane jest dokładnie 10 linii „takty”://Продемонстрировать применение оператора цикла while class While { public static void main(String args []) { int n = 10; while (n > 0) { System.out.println("такт " + n); n--; } } }Po uruchomieniu ten program wyświetla dziesięć „takty” w następujący sposób:
tak 10
tak 9
tak 8
tak 7
tak 6
tak 5
tak 4
tak 3
tak 2
tak 1
Podejście z opisem szablonu, przykładu programu i wyniku działania tego programu jest również używane w książce „Javascript dla dzieci” i w kursie js na w3schools.com. Format strony internetowej nawet umożliwia zrobienie tego przykładu interaktywnym.
W książce Stroustrupa „Zasady i praktyka przy użyciu C++” z 2016 roku autor poszedł jeszcze dalej. Najpierw wyjaśnia, jaki wynik powinien powstać, a dopiero potem pokazuje tekst programu. Co więcej, jako przykład nie biorą po prostu losowego programu, lecz oferują rzut oka w historię. To pomaga zwrócić uwagę na to „Spójrz, to nie jest tylko jakiś bezużyteczny tekst. Widzisz coś znaczącego”.
Jako przykład iteracji rozważmy pierwszy program wykonany na maszynie z pamięcią programu (EDSAC). Został on napisany przez Davida Wheelera w laboratorium komputerowym Uniwersytetu w Cambridge w Anglii 6 maja 1949 roku. Ten program oblicza i drukuje prostą listę kwadratów.
0 0
1 1
2 4
3 9
4 16
...
98 9604
99 9801
W każdej linii znajduje się liczba, za którą podąża znak tabulacji (‘t’) i kwadrat tej liczby. Wersja tego programu w języku C++ wygląda tak://Вычисляем и распечатываем таблицу квадратов чисел 0-99 int main() { int i = 0; // Начинаем с нуля while(i < 100){ cout << i << 't' << square(i) << 'n'; ++i; } }
Ciekawe, że szablon składni w tej książce nie jest opisywany. Stroustrup w przewodniku dla nauczycieli () kładzie nacisk na to, że szanuje inteligencję swoich studentów. Być może umiejętność dostrzegania wzoru w kilku przykładach jest uznawana za przejaw takiej inteligencji.
Jak ja sam tłumaczę
Podejście Stroustrupa: opis wyniku, następnie rozwiązanie problemu, a potem samodzielna analiza przez studenta — wydaje się najbardziej przemyślane. Dlatego postanowiłem wziąć za podstawę właśnie to, ale opowiedzieć na mniej historycznym przykładzie — zadaniu dotyczącym wyświetlenia «spisu treści». Tworzy to rozpoznawalny punkt zaczepienia, dzięki któremu można później powiedzieć „przypomnij sobie zadanie o spisie treści” i aby studenci dokładnie to zapamiętywali. W swoim przykładzie starałem się również ostrzec przed dwoma z najczęstszych błędów. Później opiszę je dokładniej.
W tym zadaniu poznajemy techniki rozwiązywania skomplikowanych problemów. Początkowe rozwiązanie powinno być proste i prymitywne. A potem możemy pomyśleć, jak to rozwiązanie ulepszyć.
Wprowadzenie
Rozdział 1
Rozdział 2
Rozdział 3
Rozdział 4
Rozdział 5
Rozdział 6
Rozdział 7
Podsumowanie
Z moich obserwacji wynika, że podejście „szablon-przykład-wynik” w różnych kombinacjach wciąż prowadzi do tego, że studenci postrzegają pętlę jako hieroglif. Przejawiało się to w tym, że nie rozumieli, dlaczego trzeba tam pisać warunek, jak wybierać między i++ a i-- i inne, wydawałoby się oczywiste rzeczy. Aby uniknąć tych nieporozumień, podejście do opowiadania o pętlach powinno podkreślać sens powtarzania tych samych działań, a dopiero potem — ich formę za pomocą konstrukcji. Dlatego przed podaniem składni pętli należy rozwiązać zadanie „prosto”. Prymitywne rozwiązanie zadania o spisie treści wygląda tak:
Console.WriteLine("Wprowadzenie");
Console.WriteLine("Rozdział 1");
Console.WriteLine("Rozdział 2");
Console.WriteLine("Rozdział 3");
Console.WriteLine("Rozdział 4");
Console.WriteLine("Rozdział 5");
Console.WriteLine("Rozdział 6");
Console.WriteLine("Rozdział 7");
Console.WriteLine("Zakończenie");
Jak można to poprawić?
Zastąpić jednorodne działania pętlą.
Jakie działania tutaj powtarzają się kolejno bez zmian?
W tym fragmencie takich nie ma. Z kolei polecenia do wyświetlania słowa „Rozdział” z numerem są bardzo podobne do siebie.
Dlatego następnym krokiem jest poszukiwanie różnic między fragmentami. Tylko w tym zadaniu wszystko jest oczywiste, potem będą się powtarzać nie pojedyncze polecenia, ale bloki kodu liczące 5 linii i więcej. Należy szukać nie tylko w liście poleceń, ale również w konstrukcjach warunkowych albo pętli.
W przykładzie różnica między poleceniami tkwi w liczbie po słowie „Rozdział”.
Gdy tylko różnica zostanie znaleziona, należy zrozumieć prawidłowość zmiany. Różniący się fragment to liczba? Czy ona się stale zwiększa, czy zmniejsza? Jak zmienia się wartość liczby między dwoma sąsiednimi poleceniami?
W przykładzie liczba po słowie „Rozdział” wzrasta o 1. Różnica została znaleziona, a wzór odkryty. Teraz możemy zastąpić różniący się fragment zmienną.
Taką zmienną należy zadeklarować przed pierwszym z powtarzających się fragmentów. Zazwyczaj nazywa się ją I lub j, albo w sposób bardziej rozwinięty. Jej początkowa wartość powinna być równa pierwszej wartości wyświetlanej na ekranie. W przykładzie pierwsza wartość to 1.
Jaką początkową wartość należy wybrać do wyświetlenia ciągu liczb „100, 101, 102, 103, 104, 105”?
W tym ciągu pierwsza liczba to 100.
Po każdej komendzie wyjścia należy zwiększyć wartość tej zmiennej o 1. Ta jedna to krok zmiany.
Jaki krok będzie w ciągu liczb „100, 102, 104, 106”?
W tym ciągu krok wynosi 2.
Po zastąpieniu różniącego się fragmentu zmienną, kod będzie wyglądał tak:
Console.WriteLine("Wprowadzenie");
int i;
i = 0;
Console.WriteLine("Rozdział " + i);
i = i + 1;
Console.WriteLine("Rozdział " + i);
i = i + 1;
Console.WriteLine("Rozdział " + i);
i = i + 1;
Console.WriteLine("Rozdział " + i);
i = i + 1;
Console.WriteLine("Rozdział " + i);
i = i + 1;
Console.WriteLine("Rozdział " + i);
i = i + 1;
Console.WriteLine("Rozdział " + i);
i = i + 1;
Console.WriteLine("Podsumowanie");
Po zastosowaniu metody „wyrazić wzór w zmiennej” w kodzie powstaje kilka grup takich samych działań, które są wykonywane sekwencyjnie. Teraz powtarzające się działania można zastąpić pętlą.
Sekwencja rozwiązywania zadania, w którym należy użyć pętli, składa się z etapów:
- Rozwiązać „na sztywno” za pomocą wielu pojedynczych komend
- Znaleźć wzór
- Wyrazić wzór w zmiennej
- Oformować w postaci pętli
Następnie wprowadza się nowe terminy, aby student nie znalazł się w sytuacji „wszystko rozumiem, ale nie mogę powiedzieć”:
— licznik — zawsze zmienna, która jest potrzebna do śledzenia liczby kroków pętli. Zwykle jest to liczba całkowita, która jest porównywana z ograniczeniem.
— krok licznika — opis wzoru zmiany licznika.
— ograniczenie — liczba lub zmienna, z którą porównywany jest licznik, aby algorytm był skończony. Wartość licznika zmienia się w taki sposób, aby zbliżać się do ograniczenia.
— ciało pętli — zestaw komend, które będą powtarzane. Kiedy mówi się „komenda napisana wewnątrz pętli”, ma się na myśli właśnie ciało.
— iteracja pętli — jednokrotne wykonanie ciała pętli.
— warunek pętli — wyrażenie logiczne, od którego zależy, czy będzie wykonywana kolejna iteracja. (Może to wprowadzić w błąd w kontekście struktur warunkowych)
Trzeba być przygotowanym na to, że na początku studenci będą używać terminów niezgodnie z ich przeznaczeniem. Dotyczy to zarówno silnych, jak i słabych studentów. Nawiązanie wspólnego języka to całkowita sztuka. Teraz krótką wiadomość: należy postawić zadanie „wyodrębnij fragment kodu z <terminem>” i samemu poprawnie używać tych terminów w rozmowie.
Po przekształceniu z pętlą otrzymujemy fragment:
Console.WriteLine("Wprowadzenie");
int i = 0;
while (i < 7) {
Console.WriteLine("Rozdział " + i);
i = i + 1;
}
Console.WriteLine("Zakończenie");Główne nieporozumienie
Jednym z popularnych przekonań studentów jest to, że umieszczają w konstrukcji pętli takie działania, które należy wykonać tylko raz. Na przykład tak:
;
int i = 0;
while (i < 7) {
Console.WriteLine("Wprowadzenie");
Console.WriteLine("Rozdział " + i);
i = i + 1;
Console.WriteLine("Zakończenie");
}
Uczniowie natrafiają na ten problem zarówno na początku, jak i w bardziej złożonych zadaniach.
Królowa wskazówka w tym przypadku:
Ile razy należy powtórzyć pisanie komendy: raz czy wiele?
Komendy wyjścia słów „Wprowadzenie” i „Zakończenie”, a także deklaracja i inicjalizacja zmiennej i nie są podobne do innych powtarzalnych działań. Wykonywane są tylko raz, więc należy je napisać poza ciałem pętli.
W kodzie powinny pozostać wszystkie trzy etapy rozwiązania, aby można było później się do nich odwołać w razie trudności. Pierwsze dwa warianty wystarczy skomentować, aby nie przeszkadzały.
Należy zwrócić uwagę studenta na następujące fakty:
— W warunku pętli zwykle porównuje się licznik i ograniczenie. Licznik może się zmieniać w ciele pętli, a ograniczenie — nie. Aby złamać tę zasadę, należy mieć przekonujące powody.
— Komendy do wyjścia słów „Wprowadzenie” i „Zakończenie” są poza ciałem pętli. Musimy je wykonać 1 raz. „Wprowadzenie” — przed powtórzeniem działań, „Zakończenie” — po.
W procesie utrwalania tego tematu, opanowywania następnych, a także radzenia sobie z trudnościami, nawet silnym studentom przydatne jest zadawanie pytania: „A ile razy należy wykonać tę czynność? Raz czy wiele?”.
Rozwój dodatkowych umiejętności
W trakcie nauki o cyklach studenci praktykują umiejętności diagnostyczne i rozwiązywania problemów. Aby przeprowadzić diagnostykę, student musi wyobrazić sobie pożądany rezultat i porównać go z rezultatem rzeczywistym. Działania naprawcze zależą od różnicy między nimi.
Ponieważ na tym etapie studenci nie mają jeszcze wyraźnego wyobrażenia o «pożądanym» rezultacie, mogą opierać się na danych testowych. Zazwyczaj nikt na tym etapie nie rozumie jeszcze, co może pójść nie tak i jak z tym walczyć. Dlatego podaję do zapisania w zeszycie opisy typowych problemów i kilka sposobów ich rozwiązania. Wybór najodpowiedniejszego z nich to zadanie samego studenta.
Notatki są potrzebne, aby pytać: «czy udało się to, co oczekiwano?», «która z tych sytuacji miała miejsce?», «czy zastosowane rozwiązanie pomogło?».
- Liczba działań jest o 1 mniejsza lub większa niż oczekiwano. Sposoby rozwiązania:
— zwiększyć początkową wartość licznika o 1.
— zmienić ścisły operator porównania () na niescisły (=).
— zmienić wartość ograniczenia o 1. - Działania w pętli są wykonywane bez zatrzymania, nieskończoność. Sposoby rozwiązania:
— dodać komendę zmieniającą licznik, jeśli jej brakuje.
— poprawić komendę zmieniającą licznik tak, aby jego wartość zbliżała się do ograniczenia.
— usunąć komendę zmieniającą ograniczenie, jeśli znajduje się w ciele pętli. - Liczba działań w pętli jest o więcej niż 1 mniejsza lub większa niż oczekiwano. Działanie w pętli nie zostało wykonane ani razu. Najpierw należy ustalić rzeczywiste wartości zmiennych bezpośrednio przed rozpoczęciem pętli. Sposoby rozwiązania:
— zmienić początkową wartość ograniczenia
— zmienić początkową wartość licznika
Zazwyczaj problem 3 występuje, gdy używana jest niewłaściwa zmienna lub licznik nie jest zerowany.
Po tym wyjaśnieniu, student może wciąż mieć różne złudzenia dotyczące działania cykli.
Aby rozwiać najczęstsze, podaję zadania:
- W której ograniczenie, początkowa wartość licznika lub krok licznika wprowadza użytkownik.
- W której wartość licznika należy wykorzystać w jakimś wyrażeniu arytmetycznym. Najlepiej, aby licznik znajdował się w wyrażeniu podpierającym lub w mianowniku, aby różnica była nieliniowa.
- W którym wartość licznika nie jest wyświetlana na ekranie podczas działania pętli. Na przykład wyświetlenie potrzebnej liczby identycznych fragmentów tekstu lub narysowanie figury grafiką żółwiową.
- W którym najpierw należy wykonać jedne powtarzające się działania, a potem inne.
- W którym należy wykonać inne działania przed i po powtarzających się.
Dla każdego zadania należy przygotować dane testowe oraz oczekiwany wynik.
Aby zrozumieć, jak szybko można się poruszać, należy dać przeczytać warunki tych zadań i zapytać: „czym różnią się od przykładu?”, „Co należy zmienić w przykładzie, aby je rozwiązać?”. Jeśli student odpowiada sensownie, niech rozwiąże przynajmniej jedno podczas zajęć, a pozostałe — w domu samodzielnie. Jeśli rozwiązanie będzie udane, można rozpocząć wyjaśnienie dotyczące warunków wewnątrz pętli.
Jeśli pojawiają się trudności z samodzielnym rozwiązaniem, należy wszystko przepracować na zajęciach. Aby rozwiązanie zadania nie przypominało rysowania sowy, zalecam najpierw rozwiązanie zadania w sposób nieogólny. To znaczy tak, aby rozwiązanie przechodziło pierwszy test i nie używało konstrukcji pętli. A potem zastosować przekształcenia, aby uzyskać ogólność rozwiązania.
Pętle i rozgałęzienia
Moim zdaniem, warto oddzielnie poruszyć temat „pętle wewnątrz rozgałęzień”. Tak, aby później było widać różnicę między wielokrotnym sprawdzaniem warunku a jednokrotnym.
Zadania do utrwalenia będą dotyczyły wyświetlania liczb od A do B, które wprowadza użytkownik:
— zawsze w porządku rosnącym.
— w porządku rosnącym lub malejącym w zależności od wartości A i B.
Do tematu „rozgałęzienia wewnątrz pętli” należy przejść dopiero po tym, jak student opanuje techniki: „zamiana wzoru na zmienną” oraz „zamiana powtarzających się działań na pętlę”.
Główny powód stosowania rozgałęzień wewnątrz pętli — anomalie w wzorze. W środku jest zakłócana w zależności od danych wejściowych.
Uczniom, którzy potrafią szukać rozwiązania poprzez łączenie prostych technik, wystarczy powiedzieć: „rozgałęzienia można pisać wewnątrz pętli” i dać zadanie „na przykład” całkowicie do samodzielnego rozwiązania.
Zadanie na przykład:
Użytkownik wprowadza liczbę X. Wyświetlić w kolumnie liczby od 0 do 9 i postawić znak ‘+’ przy tej liczbie, która równa się X.
Jeśli wprowadzono 00+
1
2
3
4
5
6
7
8
9
Jeśli wprowadzono 60
1
2
3
4
5
6+
7
8
9
Jeśli wprowadzono 90
1
2
3
4
5
6
7
8
9+
Jeśli wprowadzono 7770
1
2
3
4
5
6
7
8
9
Jeśli brakuje krótkiego wyjaśnienia, aby napisać z użyciem pętli, należy dążyć do uniwersalnego rozwiązania tego samego zadania bez pętli.
Będzie to jedna z dwóch opcji:
Pożądany
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);
}
Możliwe
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+");
}
Podobne zadanie daję z wyprzedzeniem, podczas studiowania tematu dotyczącego rozgałęzień.
Jeśli student uzyska opcję „możliwą”, należy powiedzieć, że tego samego zadania może być wiele rozwiązań. Jednak różnią się one odpornością na zmiany wymagań. Zadaj pytanie: „Ile miejsc w kodzie trzeba będzie poprawić, jeśli trzeba będzie dodać jeszcze jedną liczbę?” W „możliwej” opcji będzie trzeba dodać jeszcze jedną gałąź i dopisać zupełnie nowe liczby w 10 innych miejscach. W „pożądanej” wystarczy dodać tylko jedną gałąź.
Postaw zadanie odtworzenia „pożądanego” wariantu, następnie znajdź w kodzie regularność, wykonaj zamianę zmiennej i napisz pętlę.
Jeśli masz pomysł, jak rozwiązać to zadanie bez pętli w inny sposób, proszę napisz to w komentarzach.
Pętle wewnątrz pętli
W tym temacie trzeba zwrócić uwagę na to, że:
— liczniki dla zewnętrznej i wewnętrznej pętli muszą być różnymi zmiennymi.
— licznik dla wewnętrznej pętli należy zerować wiele razy (tj. w ciele pętli zewnętrznej).
W zadaniach związanych z wyświetlaniem tekstu nie można najpierw wypisać jednej litery w kilku wierszach, a potem drugiej. Należy najpierw wypisać wszystkie litery pierwszego wiersza, potem wszystkie litery drugiego i tak dalej.
Wyjaśnienie tematu dotyczącego pętli wewnętrznych najlepiej rozpocząć od omówienia znaczenia zerowania licznika.
Zadanie na przykład:
Użytkownik wprowadza dwie liczby: R i T. Wyświetl dwie linie znaków "#". W pierwszej linii powinno znajdować się R sztuk znaków. W drugiej T sztuk. Jeśli którakolwiek liczba będzie ujemna, wyświetl komunikat o błędzie.
R=5, T=11#####
###########
R=20, T=3####################
###
R=-1, T=6Wartość R musi być nieujemna.
R=6, T=-2Wartość T musi być nieujemna.
Oczywiście, że to zadanie ma co najmniej dwa możliwe rozwiązania.
Pożądany
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;
}
Możliwość nr 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óżnica polega na tym, że w 'możliwości' do wypisania drugiej linii użyto drugiej zmiennej. Należy nalegać na zastosowanie tej samej zmiennej dla obu pętli. Można to uzasadnić tym, że rozwiązanie z jednym licznikiem dla dwóch pętli będzie ilustracją terminu 'zerowanie licznika'. Zrozumienie tego terminu jest kluczowe przy rozwiązywaniu kolejnych zadań. Jako kompromis można zachować oba rozwiązania tego zadania.
Typowy problem z zastosowaniem jednej zmiennej-licznika dla dwóch pętli objawia się w ten sposób:
R=5, T=11#####
######
Liczba znaków w drugiej linii nie odpowiada wartości T. Jeśli potrzebna jest pomoc w związku z tym problemem, należy 'wskazać palcem' na notatki dotyczące typowych problemów z pętli. To symptom nr 3. Diagnozuje się to, jeśli doda się wypisanie wartości licznika bezpośrednio przed drugą pętlą. Naprawia się przez zerowanie. Ale lepiej od razu tego nie mówić. Student powinien spróbować sformułować przynajmniej jedną hipotezę.
Istnieje oczywiście inna wariant rozwiązania. Ale nie widziałem go u studentów ani razu. Na etapie nauki pętli, opowiadanie o nim rozpraszałoby uwagę. Można do niego wrócić później, podczas nauki funkcji do pracy z ciągami.
Możliwość nr 2
string 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));
Następne obowiązkowe zadanie:
Wyświetl na ekranie cyfry od 0 do 9. Każda cyfra powinna być w osobnej linii. Liczba cyfr w linii (W) jest wprowadzana z klawiatury.
W=10
1
2
3
4
5
6
7
8
9
W=100000000000
1111111111
2222222222
3333333333
4444444444
5555555555
6666666666
7777777777
8888888888
9999999999
Jeśli student opanował metodę z zamianą zmiennej, poradzi sobie dość szybko. Możliwy problem znów będzie związany z zerowaniem zmiennej. Jeśli nie radzi sobie z konwersją, oznacza to, że się spieszyłeś i trzeba rozwiązać łatwiejsze zadania.
Dziękuję za uwagę. Lajkujcie, subskrybujcie kanał.
P.S. Jeśli znalazłeś literówki lub błędy w tekście, proszę daj mi znać. Możesz to zrobić, zaznaczając część tekstu i naciskając na Macu „⌘ + Enter”, a na klasycznych klawiaturach „Ctrl / Enter”, lub poprzez wiadomości prywatne. Jeśli te opcje są niedostępne, napisz o błędach w komentarzach. Dziękuję!
Tylko zarejestrowani użytkownicy mogą brać udział w ankiecie. , proszę.
Ankieta dla czytelników bez karmy
20,0%Uczę zawodowo, +12
10,0%Uczę zawodowo, -11
70,0%Nie uczę, +17
0,0%Nie uczę, -10
0,0%Inne0
Zagłosowało 10 użytkowników. Wstrzymało się 5 użytkowników.
Źródło: habr.com
