Cu toate că vom discuta despre unul dintre subiectele de bază, acest articol este destinat profesioniștilor experimentați. Scopul este de a arăta ce încurcături există printre începătorii în programare. Pentru dezvoltatorii practicanți, aceste probleme au fost rezolvate de mult, uitate sau chiar nesobservate. Articolul poate fi util dacă va trebui să ajutați pe cineva cu acest subiect. Se fac paralele cu materialul din diverse cărți de programare scrise de Shields, Stroustrup, Okulov.
Tema despre bucle a fost aleasă deoarece aceasta filtrează destul de multe persoane în procesul de învățare a programării.
Această metodă este destinată studenților mai slabi. De obicei, cei puternici nu se fixează pe acest subiect și nu este necesar să inventăm metode speciale pentru ei. Un alt obiectiv al articolului este de a transforma această metodă din clasa „funcționează pentru toți studenții, dar doar pentru un singur profesor” în clasa „funcționează pentru toți studenții, toți profesorii”. Nu pretind la originalitate absolută. Dacă deja aplicați o metodă similară pentru a preda acest subiect, vă rog să-mi spuneți în ce diferă versiunea dumneavoastră. Dacă decideți să aplicați, povestiți-mi despre rezultate, cum a decurs totul. Dacă o metodă similară este descrisă într-o carte, vă rog să-mi spuneți titlul.
Am lucrat la această metodă timp de 4 ani, lucrând individual cu studenți de diferite niveluri de pregătire. În total, aproximativ cincizeci de studenți și două mii de ore de cursuri. La început, studenții se blocau pe acest subiect și plecau. După fiecare student, metoda și materialele au fost corectate. În ultimul an, studenții nu mai rămân blocați pe acest subiect, așa că am decis să împărtășesc rezultatele.
De ce atât de multe cuvinte? Bucla este elementară!
Așa cum am menționat mai sus, pentru dezvoltatorii practicanți și pentru studenții puternici, complexitatea conceptului de bucle poate fi subestimată. De exemplu, se poate susține o lecție lungă, observa capete care dau din cap și priviri inteligente. Dar, în momentul în care încearcă să rezolve o problemă, apare o blocaj și probleme inexplicabile. După lecție, studenții au la sigur doar o înțelegere parțială. Situația este agravată de faptul că studenții nu pot exprima singuri în ce constă confuzia lor.
Odată am realizat că studenții percep exemplele mele ca pe niște hieroglife. Adică, ca pe niște bucăți indivizibile de text, în care trebuie să completezi o literă „magică” și va funcționa.
Uneori observam că studenții cred că pentru a rezolva o problemă specifică este nevoie de o altă structură, pe care eu încă nu am prezentat-o. Deși pentru a rezolva era suficient să modific puțin exemplul.
De aceea am ajuns la ideea că trebuie să ne concentrăm nu pe sintaxa expresiilor, ci pe conceptul de refactorizare a codului repetitiv prin intermediul buclelor. Odată ce elevii stăpânesc această idee, orice sintaxă va fi învățată prin exerciții mici.
Cui și de ce predau
Deoarece nu există examene de admitere, la cursuri pot fi atât studenți buni, cât și foarte slabi. Mai multe detalii despre studenții mei pot fi găsite în articolul
Am urmărit ca programarea să fie învățată de toți cei care își doresc acest lucru.
Cursurile mele sunt individuale, iar studentul plătește pentru fiecare sesiune. Pare că studenții ar trebui să optimizeze costurile și să ceară minimul. Cu toate acestea, oamenii vin la cursuri față în față cu un profesor nu doar pentru cunoștințe, ci pentru siguranța că au reușit să asimileze, pentru sentimentul de progres și pentru aprobarea expertului (profesorului). Dacă studenții nu simt progresul în învățare, ei vor pleca. În general, se pot structura cursurile astfel încât studenții să simtă progresul în creșterea numărului de construcții cunoscute. Adică, mai întâi studiem detaliat while, apoi descoperim for, apoi do while, și astfel avem un curs pentru o mie și una de nopți, în care timp de două luni studiem doar bucle, iar la final — un student care a scris, la dictare, biblioteca standard. Totuși, pentru a rezolva probleme practice, este nevoie nu doar de cunoștințe, ci și de autonomie în aplicarea acestora și în căutarea de informații noi. De aceea, pentru cursurile față în față, consider corect principiul — a învăța minimul și a încuraja studiul independent al detaliilor și al subiectelor înrudite. În ceea ce privește buclele, eu consider că minimul este structura while. Cu aceasta se poate înțelege principiul. Cunoscând principiul, se pot stăpâni și for, și do-while în mod independent.
Pentru a asigura învățarea materialului de către studenții mai puțin pregătiți, nu este suficient să descrii sintaxa. Este necesar să oferi mai multe sarcini simple, dar diverse, și să explici exemplele mai detaliat. În cele din urmă, viteza de învățare este limitată de capacitatea studentului de a transforma expresiile și de a căuta modele. Pentru studenții mai isteți, majoritatea sarcinilor vor fi plictisitoare. Atunci când lucrezi cu ei, nu este nevoie să insiști asupra soluționării 100% din sarcini. Materialul meu poate fi vizualizat pe . Totuși, depozitul arată mai mult ca un grimuar al unui vrăjitor — nimeni, în afară de mine, nu va înțelege unde se află fiecare lucru, iar dacă se va considera că este un eșec, s-ar putea să îți pierzi mințile
Metodologia este orientată spre practică
Teoria este explicată prin intermediul soluționării unei probleme. La cursurile fundamentale de programare, unde se studiază ramificațiile și buclele, pur și simplu nu este posibil să organizezi o lecție utilă pe un singur subiect timp de o oră întreagă. 15-20 de minute sunt suficiente pentru a explica conceptul. Principalele dificultăți apar în timpul realizării sarcinilor practice.
Profesorii începători pot arunca operatori, ramificații, bucle și matrice într-o singură lecție. Cu toate acestea, studenții se vor confrunta cu problema asimilării acestei informații.
Trebuie să nu doar să povestești materialul, ci și să te asiguri că ascultătorii l-au înțeles.
Faptul că un student a asimilat subiectul este determinat de modul în care se descurcă cu munca independentă.
Dacă studentului i-a reușit să rezolve problema pe subiect fără ajutorul profesorului, înseamnă că subiectul a fost asimilat. Pentru a asigura autoevaluarea, fiecare problemă este însoțită de o tabelă cu scenarii de testare. Problemele au un ordonare clară. Este nerecomandat să sari peste probleme. Dacă problema curentă este prea dificilă, este inutil să treci la următoarea. Aceasta este chiar mai dificilă. Pentru ca studentul să poată depăși problema curentă complexă, îi sunt explicate câteva tehnici pe exemplul primei probleme. De fapt, tot conținutul subiectului se reduce la tehnici de depășire a dificultăților. Bucles sunt, mai degrabă, un efect secundar.
Prima problemă este întotdeauna un exemplu. A doua diferă ușor și se execută „independent” imediat după prima sub supravegherea profesorului. Toate problemele următoare sunt menite să atragă atenția asupra diferitelor detalii care pot genera confuzii.
Explicația exemplului este un dialog în care studentul trebuie să activeze back propagation și cross-validation pentru a se asigura că a înțeles o porțiune de material.
Voi fi banal și voi afirma că primul exemplu pe tema este foarte important. Dacă există material pentru o muncă autonomă extinsă, lipsa primului exemplu poate fi compensată. Dacă nu mai există nimic în afară de exemplu, atunci studentul cel mai probabil nu va învăța tema.
While sau for?
Una dintre întrebările controversate este alegerea construcției pentru exemplu: while sau for. Odată, un cunoscut programator practicant fără experiență în predare m-a convins timp de o oră că ciclul for este cel mai simplu de înțeles. Argumentele au fost că «în el totul este clar și bine structurat». Însă cauza reală a dificultăților întâmpinate de începători este ideea ciclului, nu scrierea acestuia. Dacă o persoană nu înțelege această idee, va avea dificultăți cu sintaxa. Odată ce ideea este înțeleasă, problemele de formatare a codului dispar de la sine.
În materialele mele, tema ciclilor urmează teme despre ramificări. Asemănarea externă între if și while permite realizarea unei analogii directe: «când condiția din antet este adevărată, se execută corpul». Particularitatea ciclului constă în faptul că corpul se execută de mai multe ori.
Al doilea argument al meu este că while necesită mai puțin cod decât for. Cu cât este mai puțin cod, cu atât sunt mai puține erori stupide cu virgule și paranteze omise. Începătorii nu au încă suficiente abilități de atenție și meticulozitate pentru a evita automat erorile de sintaxă.
Al treilea argument este că în multe cărți bune while este explicat primul.
Dacă studentul reușește să transforme ușor expresiile, atunci se poate vorbi despre for în treacăt. Studentul își va alege singur ce îi place mai mult. Dacă însă transformările creează dificultăți, este mai bine să nu distragă atenția. Să rezolve mai întâi totul cu while. Când tema ciclurilor este stăpânită, se pot rescrie soluțiile pentru a exersa transformarea de la while la for.
Ciclurile cu post-condiție sunt destul de rare. Nu-mi pierd timpul cu ele deloc. Dacă studentul a stăpânit ideile de identificare a regularităților și transformarea expresiilor, atunci se va descurca fără ajutorul meu.
At the demonstration of the first example to strong students, I emphasize that in the first example it is important to capture not only the solution but also the entire sequence of actions that led to the result. Lazy students may neglect the writing and only transfer the final algorithm to themselves. They need to be convinced that one day they will come across a complex task. To solve it, they will need to follow steps just like in this example. That is why it is important to document all stages. In subsequent tasks, only the final solution can be left.
The main idea of automation is that we delegate routine work to computers. One of the basic techniques is writing loops. This is used when the program repeatedly performs several identical actions in succession.
Explicit is better than implicit
It might seem like a good idea in the first task on loops to print the same phrase several times. For example:
Hooray, it works!
Hooray, it works!
Hooray, it works!
Hooray, it works!
Hooray, it works!
Hooray, it works!
Hooray, it works!
Hooray, it works!
This option is poor because the value of the counter is not visible in the output. This is a problem for beginners. One should not underestimate it. Initially, this task was the first, while the task of printing a series of numbers in ascending order was the second. It was necessary to introduce additional terms like 'loop N times' and 'loop from A to B', which are essentially the same. To avoid creating unnecessary entities, I decided to show only the example with printing a series of numbers. Few manage to learn how to keep the counter in mind and model the program's behavior in their heads without preparation. Some students encounter the modeling 'in their mind' for the first time precisely on the topic of loops.
After some practice, I assign the task of repeating identical text for independent solving. If a visible counter is provided first, and then an invisible one, students encounter fewer problems. Sometimes it's enough to hint, 'don't print the counter on the screen.'
How is it explained by others?
În majoritatea materialelor didactice disponibile online, sintaxa ciclului este prezentată în cadrul unei «lecții». De exemplu, pe developer.mozilla.org (la momentul actual), împreună cu ciclul while sunt descrise și alte câteva construcții. În acest caz, sunt prezentate doar construcțiile în formă de șabloane. Rezultatul execuției acestora este descris în cuvinte, iar ilustrarea lipsește. Din punctul meu de vedere, o astfel de prezentare a subiectului reduce la zero utilitatea acestor materiale. Elevul poate rescrie codul și să-l execute singur, dar tot trebuie să existe un etalon pentru comparație. Cum să înțelegi dacă exemplul a fost rescris corect dacă nu ai cu ce să compari rezultatul?
Când este oferit doar un șablon, fără un exemplu, studentului îi este și mai greu. Cum să înțeleagă că fragmentele de cod sunt aranjate corect în șablon? Poate încerca să scrie într-un fel, apoi să-l execute. Dar dacă nu există un etalon pentru a compara rezultatul, nici executarea nu va ajuta.
În cursul de C++ pe Intuit, sintaxa ciclului este ascunsă pe pagina a treia din lecția 4 pe tema «operatori». În explicarea sintaxei ciclurilor se pune un accent special pe termenul «operator». Termenul este prezentat sub formă de set de fapte precum «simbol; acesta este un operator», "{} este un operator compus", «corpul ciclului trebuie să fie un operator». Mie nu-mi place acest mod de abordare, deoarece ascunde legăturile importante sub un singur termen. Analiza codului sursă al unui program la acest nivel este necesară dezvoltatorilor de compilatoare pentru implementarea specificației limbajului, dar nu și studenților la prima vedere. Novicii în programare rareori dispun de suficientă perspicacitate pentru a ține cont atât de atent de termeni. Rareori o persoană memorează și înțelege cuvinte noi din prima. Practic nimeni nu poate aplica corect un termen pe care l-a învățat cu puțin timp înainte. Din acest motiv, studenților le apar o mulțime de greșeli precum «am scris while(a<7);{, iar programul nu funcționează».
Din punctul meu de vedere, la început ar fi mai bine să se ofere sintaxa construcției imediat cu paranteze. Varianta fără paranteze ar trebui explicată doar dacă elevul pune o întrebare concretă «de ce aici fără paranteze și funcționează».
În cartea lui Okulov „Fundamentele programării” din 2012, introducerea la cicluri începe cu modelul for, urmat de recomandări privind utilizarea acestuia, iar apoi urmează imediat o secțiune experimentală a lecției. Înțeleg că această carte a fost scrisă pentru acel mic procent de elevi foarte capabili, care rareori vin la orele mele.
În cărțile populare este întotdeauna prezentat rezultatul fragmentelor de cod. De exemplu, în cartea lui Schildt „Java 8. Ghid complet” din 2015. Mai întâi se oferă modelul, apoi un exemplu de program și imediat după, rezultatul execuției.
Ca exemplu, să considerăm ciclul while, în care se face un numărător descrescător,
începând de la 10, și se afișează exact 10 linii de „tact”://Продемонстрировать применение оператора цикла while class While { public static void main(String args []) { int n = 10; while (n > 0) { System.out.println("такт " + n); n--; } } }După ce este lansat, acest program afișează zece „tacte” în următorul mod:
tact 10
tact 9
tact 8
tact 7
tact 6
tact 5
tact 4
tact 3
tact 2
tact 1
Abordarea cu descrierea modelului, exemplul de program și rezultatul execuției acestuia este folosită și în cartea „Javascript pentru copii” și în cursul js de pe w3schools.com. Formatul paginii web permite chiar realizarea acestui exemplu interactiv.
În cartea lui Stroustrup „Principii și practică folosind C++” din 2016, autorul a mers și mai departe. În primul rând, se explică ce rezultat ar trebui să obțină, iar abia apoi se arată textul programului. De asemenea, ca exemplu, nu se ia o programă oarecare, ci se face o excursie în istorie. Acest lucru ajută să-i atragă atenția asupra ei: „Uite, acesta nu este doar un text inutil. Vezi ceva semnificativ”.
Ca exemplu de iterație, să luăm prima programă realizată pe o mașină cu program stocat (EDSAC). Aceasta a fost scrisă de David Wheeler în laboratorul de calculatoare al Universității din Cambridge, Anglia, pe 6 mai 1949. Această programă calculează și tipărește o simplă listă de pătrate.
0 0
1 1
2 4
3 9
4 16
...
98 9604
99 9801
Aici, în fiecare linie se află un număr, urmat de un semn de tabulare (‘t’) și pătratul acestui număr. Versiunea acestei programe în C++ arată astfel://Вычисляем и распечатываем таблицу квадратов чисел 0-99 int main() { int i = 0; // Начинаем с нуля while(i < 100){ cout << i << 't' << square(i) << 'n'; ++i; } }
Este curios că modelul sintactic din această carte nu este descris. Stroustrup în manualul instructorului () subliniază că respectă inteligența studenților săi. Poate că abilitatea de a identifica un model în mai multe exemple este considerată o manifestare a acelei inteligențe.
Așa cum explic eu însumi
Abordarea lui Stroustrup: descrierea rezultatului, apoi soluția problemei și, în final, analiza independentă a studentului — pare a fi cea mai bine gândită. De aceea, am decis să iau ca bază exact această abordare, dar voi povesti folosind un exemplu mai puțin istoric — problema generării „cuprinsului”. Aceasta formează un punct de referință recognoscibil, astfel încât, mai târziu, să putem spune „amintește-ți problema cu cuprinsul” și studenții să își amintească exact de ea. În exemplul meu, am încercat să prevenim încă două dintre cele mai frecvente concepții greșite. Îmi voi scrie despre ele în detaliu.
În această problemă, ne familiarizăm cu tehnicile de rezolvare a problemelor complexe. Soluția inițială trebuie să fie primitivă și simplă. Apoi, putem să ne gândim cum să îmbunătățim această soluție.
Introducere
Capitolul 1
Capitolul 2
Capitolul 3
Capitolul 4
Capitolul 5
Capitolul 6
Capitolul 7
Concluzie
Din observațiile mele, abordarea „șablon-exemplu-rezultatul” în diferite combinații duce totuși la faptul că studenții percep ciclul ca un hieroglif. Acest lucru s-a manifestat prin faptul că ei nu înțelegeau de ce trebuie să scrie condiția, cum să aleagă între i++ și i— și alte lucruri care păreau evidente. Pentru a evita aceste concepții greșite, abordarea de a explica ciclurile ar trebui să sublinieze sensul repetării acțiunilor identice și abia apoi — formatarea acestora printr-o construcție. De aceea, înainte de a oferi sintaxa ciclului, trebuie să rezolvăm problema „în mod direct”. Soluția primitivă a problemei cu cuprinsul arată astfel:
Console.WriteLine("Introducere");
Console.WriteLine("Capitolul 1");
Console.WriteLine("Capitolul 2");
Console.WriteLine("Capitolul 3");
Console.WriteLine("Capitolul 4");
Console.WriteLine("Capitolul 5");
Console.WriteLine("Capitolul 6");
Console.WriteLine("Capitolul 7");
Console.WriteLine("Concluzie");
Cum poate fi îmbunătățit?
Înlocuirea acțiunilor repetitive cu un ciclu.
Ce acțiuni se repetă aici fără modificări?
În acest fragment, nu există astfel de acțiuni. Totuși, comenzile de a afișa cuvântul „Capitol” cu numărul sunt foarte asemănătoare între ele.
De aceea, următorul pas este căutarea diferenței între fragmente. Doar în această problemă este totul evident, apoi se vor repeta nu comenzi unice, ci blocuri de cod de 5 linii sau mai mult. Va trebui să căutăm nu doar în lista de comenzi, ci și în construcții de ramificație sau ciclu.
În exemplu, diferența între comenzi constă în numărul de după cuvântul „Capitol”.
Odată ce diferența este găsită, trebuie să înțelegem pattern-ul schimbării. Fragmentele distincte sunt numere? Acestea cresc sau scad constant? Cum variază valoarea numărului între cele două comenzi adiacente?
În exemplu, numărul după cuvântul „Capitol” crește cu câte 1. Diferența a fost găsită, iar regularitatea identificată. Acum putem înlocui fragmentul difernțiat cu o variabilă.
Trebuie să declarăm o astfel de variabilă înainte de primul dintre fragmentele repetitive. Această variabilă este de obicei numită I sau j sau într-un mod mai detaliat. Valoarea inițială a acesteia trebuie să fie egală cu prima valoare afișată pe ecran. În exemplu, prima valoare este 1.
Ce valoare inițială ar trebui să luăm pentru a afișa seria de numere „100, 101, 102, 103, 104, 105”?
În această serie, primul număr este 100.
După fiecare comandă de afișare, trebuie să creștem valoarea acestei variabile cu 1. Această unitate este pasul de schimbare.
Care va fi pasul în seria de numere „100, 102, 104, 106”?
În această serie, pasul este 2.
După înlocuirea fragmentului diferit cu o variabilă, codul va arăta astfel:
Console.WriteLine("Introducere");
int i;
i = 0;
Console.WriteLine("Capitol " + i);
i = i + 1;
Console.WriteLine("Capitol " + i);
i = i + 1;
Console.WriteLine("Capitol " + i);
i = i + 1;
Console.WriteLine("Capitol " + i);
i = i + 1;
Console.WriteLine("Capitol " + i);
i = i + 1;
Console.WriteLine("Capitol " + i);
i = i + 1;
Console.WriteLine("Capitol " + i);
i = i + 1;
Console.WriteLine("Concluzie");
După aplicarea tehnicii „exprimați regularitatea cu o variabilă”, codul conține câteva grupuri de acțiuni identice care se desfășoară în succesiune. Acum acțiunile repetitive pot fi înlocuite cu un ciclu.
Secvența de soluționare a problemei, unde trebuie să folosim cicluri, constă în etape:
- Soluționați „direct” cu un număr de comenzi separate
- Găsiți regularitatea
- Exprimați regularitatea cu o variabilă
- Formați-o sub formă de ciclu
Apoi sunt introduse noi termeni, pentru ca studentul să nu se afle în situația „înțeleg tot, dar nu pot să spun”:
— contor — întotdeauna variabilă care este necesară pentru a urmări numărul de pași ai ciclului. De obicei, un număr întreg care este comparat cu o limită.
— pasul contorului — descrierea regularității de schimbare a contorului.
— limită — un număr sau o variabilă cu care este comparat contorul, astfel încât algoritmul să fie finit. Valoarea contorului se schimbă astfel încât să se apropie de limită.
— corpul ciclului — un set de comenzi care vor fi repetate. Când se spune „comandă scrisă în interiorul ciclului”, se referă exact la corp.
— iterația ciclului — executarea o dată a corpului ciclului.
— condiția de ciclu — o expresie logică de care depinde dacă se va executa o altă iterație. (Aici poate apărea confuzie cu structurile de ramificare)
Trebuie să fim pregătiți că, la început, studenții vor utiliza termeni în mod misconceptual. Aceasta se aplică atât celor puternici, cât și celor slabi. Stabilirea unui limbaj comun este o adevărată artă. Acum voi scrie pe scurt: trebuie să formulăm sarcina „subliniază fragmentul de cod cu ” și să folosim corect acești termeni în discuție.
După transformarea cu un ciclu, obținem fragmentul:
Console.WriteLine("Introducere");
int i = 0;
while (i < 7) {
Console.WriteLine("Capitolul " + i);
i = i + 1;
}
Console.WriteLine("Concluzie");Principala confuzie
O confuzie populară printre studenți este că ei includ în structura ciclului astfel de acțiuni care trebuie executate o singură dată. De exemplu, așa:
;
int i = 0;
while (i < 7) {
Console.WriteLine("Introducere")
Console.WriteLine("Capitolul " + i);
i = i + 1;
Console.WriteLine("Concluzie");
}
Elevii se confruntă constant cu această problemă, atât la început, cât și în sarcini mai complexe.
Sugestia principală în acest caz:
De câte ori trebuie să repetăm scrierea comenzii: o dată sau de mai multe ori?
Comenzile de ieșire a cuvintelor „Introducere” și „Concluzie”, precum și declarația și inițializarea variabilei i nu sunt similare cu alte acțiuni repetitive. Acestea se execută o singură dată, deci trebuie scrise în afara corpului ciclului.
În cod trebuie să rămână toate cele trei etape ale soluției, astfel încât ulterior să ne putem referi la ele în caz de dificultăți. Primele două variante pot fi doar comentate pentru a nu deranja.
Atenția studentului trebuie să fie îndreptată spre următoarele fapte:
— În condiția ciclului, de obicei, se compară un contor și o limită. Contorul poate varia în corpul ciclului, dar limita nu. Pentru a încălca această regulă, este necesar să avem motive temeinice.
— Comenzile de ieșire a cuvintelor „Introducere” și „Concluzie” se află în afara corpului ciclului. Trebuie să le executăm o singură dată. „Introducere” — înainte de a repeta acțiunile, „Concluzie” — după.
În procesul de consolidare a acestei teme, stăpânirea următoarelor, precum și clarificarea dificultăților, chiar și studenților puternici le este util să pună întrebarea: „Iar această acțiune trebuie să fie executată de câte ori? O dată sau de mai multe ori?”.
Dezvoltarea abilităților suplimentare
În timpul studiului ciclurilor, studenții își dezvoltă abilitatea de diagnosticare și rezolvare a problemelor. Pentru a efectua diagnosticul, studentul trebuie să-și imagineze rezultatul dorit și să-l compare cu rezultatul efectiv. Acțiunile pentru corectare depind de diferența dintre acestea.
Dat fiind că studenții în această etapă nu au o claritate suficientă asupra rezultatelor „dorințe”, ei își pot orienta către datele de test. De obicei, nimeni la acest stadiu nu înțelege ce poate merge prost și cum să facă față. Prin urmare, le ofer o descriere a problemelor tipice și câteva modalități de rezolvare, iar alegerea celei mai potrivite revine studentului.
Notația este necesară pentru a întreba „a ieșit ceea ce se aștepta?”, „Care dintre aceste situații s-a întâmplat acum?”, „A ajutat soluția aplicată?”.
- Numărul de acțiuni este cu 1 mai mic sau mai mare decât se aștepta. Modalitățile de rezolvare sunt:
— crește valoarea inițială a contorului cu 1.
— înlocuiește operatorul strict de comparare (< sau >) cu unul ne-dur (<= sau >=).
— schimbă valoarea limitată cu 1. - Acțiunile din ciclu se execută fără oprire, infinit. Modalitățile de rezolvare sunt:
— adaugă comanda de modificare a contorului, dacă lipseste.
— corectează comanda de modificare a contorului astfel încât valoarea să se apropie de limită.
— elimină comanda de modificare a limitei, dacă se află în corpul ciclului. - Numărul de acțiuni din ciclu este cu 1 mai mic sau mai mare decât se aștepta. Acțiunea din ciclu nu s-a executat deloc. Este necesar să aflăm valorile efective ale variabilelor chiar înainte de începerea ciclului. Modalitățile de rezolvare sunt:
— modifică valoarea inițială a limitei
— modifică valoarea inițială a contorului
De obicei, problema 3 este legată de utilizarea unei variabile greșite sau de ne-resetarea contorului.
După această explicație, studentul poate încă avea diverse concepții greșite despre funcționarea ciclurilor.
Pentru a dizolva cele mai comune, le ofer sarcini:
- În care limita, valoarea inițială a contorului sau pasul contorului sunt introduse de utilizator.
- În care valoarea contorului trebuie utilizată într-o expresie aritmetică. Este de preferat ca aceasta să fie într-o expresie subrădăcină sau în numitor, astfel încât diferența să fie neliniară.
- În care valoarea contorului nu este afișată pe ecran în timpul execuției buclei. De exemplu, afișarea unui număr necesar de fragmente de text identice sau desenarea unei figuri folosind grafică de tip broască țestoasă.
- În care trebuie să efectuezi mai întâi unele acțiuni repetitive și apoi altele.
- În care trebuie să efectuezi alte acțiuni înainte și după cele repetitive.
Pentru fiecare sarcină trebuie oferite date de testare și rezultatul așteptat.
Pentru a înțelege cât de repede se poate lucra, trebuie să le oferi elevilor să citească condițiile acestor sarcini și să întrebi: „ce le diferențiază de exemplu?”, „ce trebuie să schimbi în exemplu pentru a le rezolva?”. Dacă elevul răspunde rațional, atunci să rezolve măcar una în clasă, iar restul acasă. Dacă soluția este reușită, atunci putem începe explicația despre condițiile din interiorul buclelor.
Dacă există dificultăți în rezolvarea pe cont propriu, atunci trebuie să se exerseze totul în clasă. Pentru a nu face rezolvarea unei sarcini similară cu desenatul unei bufnițe, recomand să rezolvi mai întâi sarcina nu în mod universal. Adică, așa încât soluția să treacă primul test și să nu folosească construcția buclei. Apoi se pot aplica transformări pentru a obține universalitatea soluției.
Buclele și ramificările
Din perspectiva mea, este util să oferim tema „buclele în interiorul ramificărilor” separat. Așa, încât să fie ulterior vizibilă diferența între verificarea repetată a condiției și verificarea unică.
Sarcinile de consolidare vor fi despre afișarea numerelor de la A la B, care sunt introduse de utilizator:
— mereu în ordine crescătoare.
— în ordine crescătoare sau descrescătoare în funcție de valorile A și B.
La tema „ramificările în interiorul buclelor” trebuie să se treacă doar după ce elevul a stăpânit tehnicile: „înlocuirea regularității cu o variabilă” și „înlocuirea acțiunilor repetitive cu o buclă”.
Principala cauză a aplicării ramificărilor în interiorul buclelor sunt anomaliile în regularitate. În mijloc aceasta este perturbată în funcție de datele inițiale.
Pentru acei elevi care sunt capabili să caute soluții prin combinarea unor tehnici simple, este suficient să spunem „ramificările pot fi scrise în interiorul buclelor” și să oferim sarcina „pentru exemplu” complet pentru auto-rezolvare.
Sarcina pentru exemplu:
Utilizatorul introduce numărul X. Afișați într-o coloană numerele de la 0 la 9 și puneți semnul '+' lângă numărul care este egal cu X.
Dacă a fost introdus 00+
1
2
3
4
5
6
7
8
9
Dacă s-a introdus 60
1
2
3
4
5
6+
7
8
9
Dacă s-a introdus 90
1
2
3
4
5
6
7
8
9+
Dacă s-a introdus 7770
1
2
3
4
5
6
7
8
9
Dacă explicația scurtă nu este suficientă pentru a scrie cu un ciclu, atunci trebuie să găsiți o soluție universală a aceleași probleme fără ciclu.
Se va obține una dintre cele două variante:
Dezirabil
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);
}
Posibil
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+");
}
O problemă similară o dau dinainte, în timpul studiului subiectului despre ramificații.
Dacă studentul a obținut o variantă „posibilă”, atunci trebuie să se explice că soluțiile pentru aceeași problemă pot fi multiple. Totuși, ele diferă prin stabilitatea față de modificările cerințelor. Puneți întrebarea: „Câte locuri din cod trebuie corectate dacă trebuie să adăugați un alt număr?” În varianta „posibilă” va trebui să adăugați o altă ramificație și să scrieți în alte 10 locuri noul număr. În variantă „dezirabilă” este suficient să adăugați doar o singură ramificație.
Formulați sarcina de a reproduce varianta „dezirabilă”, apoi găsiți în cod o regulă, realizați înlocuirea variabilei și scrieți un ciclu.
Dacă aveți o idee despre cum să rezolvați această problemă fără ciclu în alt mod, vă rog să scrieți în comentarii.
Cicluri în interiorul ciclurilor
În acest subiect trebuie să acordați atenție la:
— contoarele pentru ciclul interior și cel exterior trebuie să fie variabile diferite.
— contorul pentru ciclul interior trebuie resetat de multe ori (adică în corpul ciclului exterior).
În sarcinile de ieșire a textului, nu poți scrie mai întâi o literă pe mai multe rânduri și apoi pe a doua. Trebuie mai întâi să ieși toate literele primului rând, apoi toate literele celui de-al doilea și așa mai departe.
Explicarea subiectului despre cicluri în interiorul ciclumilor este cel mai bine să înceapă cu explicarea importanței resetării contorului.
Sarcina pentru exemplu:
Utilizatorul introduce două numere: R și T. Afișați două rânduri de caractere "#". În primul rând, trebuie să fie R simboluri. În al doilea, T simboluri. Dacă orice număr este negativ, afișați un mesaj de eroare.
R=5, T=11#####
###########
R=20, T=3####################
###
R=-1, T=6Valoarea lui R trebuie să fie non-negativă
R=6, T=-2Valoarea lui T trebuie să fie non-negativă
Este evident că această problemă are cel puțin două soluții posibile.
Dezirabil
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;
}
Soluție posibilă №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;
}
Diferența este că în soluția «posibilă» pentru ieșirea celui de-al doilea rând a fost utilizată a doua variabilă. Este necesar să se insiste asupra utilizării aceleași variabile pentru ambele cicluri. Poate fi argumentat că soluția cu un singur contor pentru două cicluri va ilustra termenul «resetarea contorului». Înțelegerea acestui termen este necesară pentru trecerea la următoarele probleme. Ca un compromis, ambele soluții ale problemei pot fi păstrate.
O problemă tipică cu utilizarea unei singure variabile contor pentru două cicluri se manifestă astfel:
R=5, T=11#####
######
Numărul de caractere din al doilea rând nu se potrivește cu valoarea T. Dacă ai nevoie de ajutor cu această problemă, trebuie să «îi arăți» notițele despre problemele tipice cu ciclurile. Acesta este simptom №3. Este diagnosticabil dacă adaugi ieșirea valorii contorului chiar înainte de al doilea ciclu. Se corectează prin resetare. Dar este mai bine să nu povestești asta imediat. Studentul ar trebui să încerce să formuleze cel puțin o ipoteză.
Există, desigur, și această variantă de soluție. Dar nu am văzut-o la studenți. În etapa de învățare a ciclurilor, a vorbi despre ea va distrage atenția. O putem relua mai târziu, în cadrul studiului funcțiilor de lucru cu șiruri.
Soluție posibilă №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));
Următoarea sarcină obligatorie:
Afișați pe ecran cifrele de la 0 la 9. Fiecare cifră trebuie să fie pe o linie separată. Numărul de cifre pe linie (W) este introdus de la tastatură.
W=10
1
2
3
4
5
6
7
8
9
W=100000000000
1111111111
2222222222
3333333333
4444444444
5555555555
6666666666
7777777777
8888888888
9999999999
Dacă studentul a învățat să înlocuiască variabila, va reuși destul de repede. Problema posibilă va fi din nou resetezarea variabilei. Dacă nu reușește să facă conversia, înseamnă că ai grăbit lucrurile și ar trebui să rezolvi probleme mai simple.
Mulțumesc pentru atenție. Dați like, abonați-vă la canal.
P.S. Dacă ați găsit greșeli sau tipuri în text, vă rog să-mi spuneți. Puteți face acest lucru selectând o parte din text și apăsând pe Mac „⌘ + Enter”, iar pe tastaturile clasice „Ctrl / Enter”, sau prin mesaje private. Dacă aceste variante nu sunt disponibile, scrieți despre greșeli în comentarii. Mulțumesc!
Numai utilizatorii înregistrați pot participa la sondaj. , vă rugăm.
Sondaj pentru cititori fără karma
20,0%Predau profesional, +12
10,0%Predau profesional, -11
70,0%Nu predau, +17
0,0%Nu predau, -10
0,0%Altceva0
10 utilizatori au votat. 5 utilizatori s-au abținut.
Sursa: habr.com
