Como ensinar a superar dificuldades e ao mesmo tempo escrever ciclos

Apesar de falarmos sobre um dos temas básicos, este artigo foi escrito para profissionais experientes. O objetivo é mostrar quais são os equívocos que os iniciantes têm em programação. Para desenvolvedores praticantes, esses problemas foram resolvidos há muito tempo, esquecidos ou nem percebidos. O artigo pode ser útil se de repente você precisar ajudar alguém com este tópico. O artigo traça paralelos com materiais de vários livros sobre programação de Schildt, Stroustrup, Okulov.

O tema ciclos foi escolhido porque muitas pessoas ficam excluídas dele quando dominam a programação.

Esta técnica é projetada para alunos fracos. Via de regra, pessoas fortes não ficam presas nesse assunto e não há necessidade de inventar técnicas especiais para elas. O objetivo secundário do artigo é mover esta técnica da classe “funciona para todos os alunos, mas apenas um professor” para a classe “funciona para todos os alunos, todos os professores”. Não reivindico originalidade absoluta. Se você já estiver usando uma metodologia semelhante para ensinar este tópico, escreva como sua versão difere. Se você decidir usá-lo, conte-nos como foi. Se uma técnica semelhante for descrita em um livro, escreva o nome.


Trabalhei nessa técnica por 4 anos, estudando individualmente com alunos de diferentes níveis de formação. No total são cerca de cinquenta alunos e duas mil horas de aula. No início, os alunos sempre ficavam presos nesse assunto e iam embora. Após cada aluno, a metodologia e os materiais foram ajustados. No ano passado, os alunos não ficaram mais presos a esse tópico, então decidi compartilhar minhas descobertas.

Por que tantas cartas? Os ciclos são tão elementares!

Como escrevi acima, para desenvolvedores praticantes e para estudantes experientes, a complexidade do conceito de loops pode ser subestimada. Por exemplo, você pode dar uma longa palestra, ver cabeças balançando e olhos inteligentes. Mas ao tentar resolver qualquer problema, começam o estupor e os problemas inexplicáveis. Após a palestra, os alunos provavelmente tiveram apenas uma compreensão parcial. A situação é agravada pelo fato de os próprios alunos não conseguirem expressar exatamente qual é o seu delírio.
Um dia percebi que os alunos viam meus exemplos como hieróglifos. Ou seja, como pedaços de texto indivisíveis nos quais você precisa adicionar alguma letra “mágica” e tudo funcionará.
Às vezes percebi que os alunos pensam que para resolver um problema específico é preciso algo mais um design que ainda não abordei. Embora a solução exigisse apenas uma ligeira modificação do exemplo.

Então tive a ideia de que o foco não deveria estar na sintaxe das expressões, mas sim na ideia de refatorar código repetitivo usando loops. Depois que os alunos dominarem essa ideia, qualquer sintaxe poderá ser melhorada com pouca prática.

Quem e por que eu ensino?

Como não há vestibular, as aulas podem incluir alunos fortes e muito fracos. Você pode ler mais sobre meus alunos no artigo Retrato de alunos do curso noturno
Eu me esforcei para garantir que todos que desejam aprender programação possam aprender.
Minhas aulas são ministradas individualmente e o aluno paga seu próprio dinheiro por cada uma. Parece que os alunos otimizarão custos e exigirão o mínimo. Porém, as pessoas vão para aulas presenciais com professor presencial não pelo conhecimento em si, mas pela confiança no que aprenderam, pela sensação de progresso e pela aprovação do especialista (professor). Se os alunos não sentirem progresso em seu aprendizado, eles irão embora. Em geral, as aulas podem ser estruturadas de forma que os alunos sintam progresso no aumento do número de estruturas familiares. Ou seja, primeiro estudamos detalhadamente, depois estudamos, depois fazemos enquanto, e agora temos um curso de mil e uma noites pronto, em que só se estudam ciclos durante dois meses, e no final - um aluno que escreveu uma biblioteca padrão sob ditado. Porém, para resolver problemas práticos, é necessário não apenas conhecimento do material, mas também independência na sua aplicação e na busca de novas informações. Portanto, para cursos presenciais, acho que o princípio correto é ensinar o mínimo e incentivar o estudo independente de nuances e temas relacionados. No tópico de loops, considero a construção while o mínimo. Você pode entender o princípio disso. Conhecendo o princípio, você pode dominar tanto o fazer quanto o fazer sozinho.

Para conseguir o domínio do material por alunos fracos, descrever a sintaxe não é suficiente. É necessário fornecer tarefas mais simples, mas variadas, e descrever exemplos com mais detalhes. Em última análise, a velocidade de desenvolvimento é limitada pela capacidade do aluno de transformar expressões e procurar padrões. Para alunos inteligentes, a maioria das tarefas será enfadonha. Ao estudar com eles, você não precisa insistir em resolver 100% dos problemas. Meu material pode ser visualizado em meu github. É verdade que o repositório é mais parecido com o grimório de um bruxo - ninguém além de mim entenderá o que está onde, e se você falhar na verificação, poderá enlouquecer

A metodologia é orientada para a prática

A teoria é explicada usando o exemplo de resolução de um problema. Em uma aula de fundamentos de programação onde são ensinados ramos e loops, simplesmente não é possível dar uma palestra útil sobre um tópico durante uma hora inteira. 15-20 minutos são suficientes para explicar o conceito. As principais dificuldades surgem na execução de tarefas práticas.
Professores iniciantes podem recitar operadores, ramificações, loops e matrizes em uma aula. Mas seus alunos enfrentarão o problema de assimilar essas informações.
É necessário não apenas contar o material, mas também garantir que os ouvintes o compreendam.

O fato de dominar um tema é determinado pela forma como o aluno lida com o trabalho independente.
Se um aluno conseguiu resolver um problema sobre um tema sem a ajuda de um professor, então o tema foi dominado. Para garantir o autoteste, cada tarefa é descrita em uma tabela com cenários de teste. As tarefas têm uma ordem clara. Ignorar tarefas não é recomendado. Se a tarefa atual for muito difícil, passar para a próxima será inútil. É ainda mais complicado. Para que o aluno possa dominar a complexa tarefa atual, diversas técnicas são explicadas a ele a partir do exemplo do primeiro problema. Na verdade, todo o conteúdo do tema se resume a técnicas de superação de dificuldades. Os ciclos são mais um efeito colateral.

A primeira tarefa é sempre um exemplo. A segunda difere um pouco e é realizada “de forma independente” imediatamente após a primeira, sob a supervisão de um professor. Todas as tarefas subsequentes visam prestar atenção a várias pequenas coisas que podem causar conceitos errados.

A explicação do exemplo é um diálogo em que o aluno precisa chamar de volta a propagação e a validação cruzada para ter certeza de que dominou uma parte do material.

Serei banal e direi que o primeiro exemplo sobre o tema é muito importante. Se você tiver material para um extenso trabalho independente, as omissões do primeiro exemplo podem ser corrigidas. Se não houver mais nada além do exemplo, o aluno provavelmente não dominará o tópico.

Enquanto ou para?

Uma das questões polêmicas é a escolha da construção por exemplo: enquanto ou para. Certa vez, um desenvolvedor amigo meu, sem experiência de ensino, passou uma hora me convencendo de que o loop for era o mais fácil de entender. Os argumentos resumiam-se a “tudo nele é claro e colocado em seu devido lugar”. No entanto, a causa raiz das dificuldades para verdadeiros iniciantes é a ideia do ciclo em si, e não a sua escrita. Se uma pessoa não entender essa ideia, terá dificuldades com a sintaxe. Assim que a ideia é concretizada, os problemas de design de código desaparecem por conta própria.

Nos meus materiais, o tema dos loops segue o tema da ramificação. A semelhança externa de if e while nos permite traçar uma analogia direta: “quando a condição no cabeçalho é verdadeira, então o corpo é executado”. A única peculiaridade do ciclo é que o corpo é executado diversas vezes.

Meu segundo argumento é que while requer menos formatação que for. Menos formatação significa menos erros estúpidos com falta de vírgulas e parênteses. Os iniciantes ainda não desenvolveram atenção e meticulosidade suficientes para evitar automaticamente erros de sintaxe.
O terceiro argumento é explicado em muitos bons livros como o primeiro argumento.

Se o aluno consegue transformar expressões facilmente, então você pode falar sobre isso de passagem. O aluno então escolherá o que mais lhe agrada. Se as transformações causam dificuldades, é melhor não desviar a atenção. Deixe o aluno primeiro resolver tudo usando while. Depois de dominar o tópico dos loops, você pode reescrever as soluções para praticar a conversão de while em for.
Loops de pós-condição são uma fera bastante rara. Eu não perco tempo com isso. Se um aluno tiver dominado as ideias de identificação de padrões e transformação de expressões, ele poderá descobrir isso sem minha ajuda.

Ao demonstrar o primeiro exemplo para alunos fortes, chamo a atenção para o fato de que no primeiro exemplo é importante registrar não só a solução, mas também toda a cadeia de ações que levaram ao resultado. Alunos preguiçosos podem negligenciar a redação e copiar apenas o algoritmo final. Eles precisam estar convencidos de que um dia uma tarefa difícil surgirá em seu caminho. Para resolvê-lo, você precisará seguir os passos deste exemplo. Por isso é importante registrar todas as etapas. Nos problemas seguintes será possível deixar apenas a versão final da solução.

A ideia principal da automação é confiar a um computador o trabalho rotineiro de uma pessoa. Uma das técnicas básicas é escrever loops. É usado quando várias ações repetidas idênticas são escritas consecutivamente em um programa.

Explícito é melhor que implícito

Pode parecer uma boa ideia exibir a mesma frase várias vezes na primeira tarefa de loop. Por exemplo:

Viva, funciona!
Viva, funciona!
Viva, funciona!
Viva, funciona!
Viva, funciona!
Viva, funciona!
Viva, funciona!
Viva, funciona!

Esta opção é ruim porque o valor do contador não é visível na saída. Este é um problema para iniciantes. Não a subestime. A princípio, esta tarefa foi a primeira, e a tarefa de derivar uma série de números em ordem crescente foi a segunda. Foi necessário introduzir termos adicionais “ciclo N vezes” e “ciclo de A a B”, que são essencialmente a mesma coisa. Para não criar entidades desnecessárias, resolvi mostrar apenas um exemplo com a saída de uma série de números. Poucas pessoas conseguem aprender como manter um contador na cabeça e modelar o comportamento de um programa na cabeça sem preparação. Alguns alunos encontram pela primeira vez a modelagem mental sobre o tema dos ciclos.
Depois de alguma prática, dou a tarefa de repetir o mesmo texto para ser resolvido de forma independente. Se você fornecer primeiro um contador visível e depois um invisível, os alunos terão menos problemas. Às vezes a dica “não escreva o contador na tela” é suficiente.

Como os outros explicam isso?

Na maioria dos materiais educativos na Internet, a sintaxe do ciclo é dada como parte de uma “aula”. Por exemplo, em developer.mozilla.org (atualmente), várias outras construções são descritas junto com o loop while. Neste caso, apenas os próprios designs são fornecidos na forma de modelos. O resultado do seu lançamento é descrito em palavras, mas não há ilustração. Na minha opinião, tal apresentação do tema multiplica por zero a utilidade de tais materiais. O aluno pode reescrever o código e executá-lo sozinho, mas ainda precisa de um padrão para comparação. Como você pode entender que um exemplo foi reescrito corretamente se não há nada com que comparar o resultado?
Quando é fornecido apenas um modelo, sem exemplo, fica ainda mais difícil para o aluno. Como entender que os fragmentos de código estão colocados corretamente no template? Você pode tentar escrever de alguma formae execute. Mas se não houver um padrão para comparar o resultado, o lançamento também não ajudará.

No curso C++ sobre Intuitivo, a sintaxe do loop está enterrada na terceira página da Aula 4 sobre o tópico “operadores”. Ao explicar a sintaxe dos loops, é dada ênfase especial ao termo “operador”. O termo é apresentado como um conjunto de fatos como “símbolo; isto é uma instrução", "{} é uma instrução composta", "o corpo do loop deve ser uma instrução". Não gosto desta abordagem porque parece esconder relações importantes por trás de um termo. A análise do código-fonte de um programa em termos neste nível é necessária aos desenvolvedores de compiladores para implementar a especificação da linguagem, mas não aos alunos como uma primeira aproximação. Os recém-chegados à programação raramente são meticulosos o suficiente para prestar tanta atenção aos termos. É raro uma pessoa lembrar e compreender palavras novas pela primeira vez. Quase ninguém consegue aplicar corretamente um termo que acabou de aprender. Portanto, os alunos recebem muitos erros como “Escrevi while(a<7);{, mas o programa não funciona”.
Na minha opinião, no início é melhor dar a sintaxe da construção imediatamente entre parênteses. A opção sem parênteses só deve ser explicada caso o aluno tenha uma dúvida específica: “por que não tem parênteses e funciona”.

No livro “Fundamentals of Programming” de Okulov de 2012, uma introdução aos loops começa com o padrão for, depois fornece recomendações para seu uso e, em seguida, vai imediatamente para a seção experimental da lição. Entendo que o livro foi escrito para aquela minoria de estudantes muito capazes que raramente vêm às minhas aulas.

Nos livros populares, o resultado dos fragmentos de código é sempre escrito. Por exemplo, a edição “Java 8. The Complete Guide” de 2015 de Shildt. Primeiro é fornecido um modelo, depois um programa de exemplo e imediatamente após - o resultado da execução.

Como exemplo, considere um loop while que faz o inverso
contagem regressiva começando em 10 e exatamente 10 linhas de “medidas” são exibidas:

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

Uma vez executado, este programa gera dez "ciclos" da seguinte forma:
такт 10
такт 9
такт 8
такт 7
такт 6
такт 5
такт 4
такт 3
такт 2
такт 1

A abordagem de descrição de um template, um programa de exemplo e o resultado do programa também é utilizada no livro “Javascript for Kids” e no curso js em w3schools.com. O formato da página web permite até que este exemplo seja interativo.

O livro de Stroustrup de 2016, Princípios e Prática Usando C++, foi ainda mais longe. O primeiro passo é explicar qual resultado deve ser obtido, e em seguida é mostrado o texto do programa. Além disso, eles não tomam apenas um programa aleatório como exemplo, mas fazem uma excursão pela história. Isso ajuda a chamar a atenção: “Olha, isso não é só um texto inútil. Você vê algo significativo."

Como exemplo de iteração, considere o primeiro programa executado em uma máquina de programa armazenado (EDSAC). Foi escrito por David Wheeler no Laboratório de Computação da Universidade de Cambridge, Inglaterra, em 6 de maio de 1949. Este programa calcula e imprime uma lista simples de quadrados.
0 0
1 1
2 4
3 9
4 16
...
98 9604
99 9801

Aqui, cada linha contém um número seguido por um caractere de tabulação ('t') e o quadrado desse número. A versão C++ deste programa se parece com isto:

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

Curiosamente, o padrão de sintaxe não é descrito neste livro. Stroustrup no manual do instrutor (tradução) ressalta que respeita a inteligência de seus alunos. Talvez a capacidade de identificar um padrão em vários exemplos seja considerada uma manifestação dessa inteligência.

Enquanto eu me explico

A abordagem de Stroustrup: descrever o resultado, depois resolver o problema e, em seguida, uma análise independente pelo aluno - parece a mais ponderada. Portanto, decidi tomá-lo como base, mas contá-lo usando um exemplo menos histórico - a tarefa de derivar um “índice”. Ele forma uma âncora reconhecível para que você possa dizer “lembre-se da tarefa sobre o índice” e para que os alunos se lembrem exatamente disso. No meu exemplo, tentei evitar mais dois dos equívocos mais comuns. A seguir escreverei sobre eles com mais detalhes.

Nesta tarefa, somos apresentados a técnicas para resolver problemas complexos. A decisão inicial precisa ser feita de forma primitiva e simples. Bem, então você pode pensar em como melhorar esta solução.
Введение
Глава 1
Глава 2
Глава 3
Глава 4
Глава 5
Глава 6
Глава 7
Заключение

De acordo com minhas observações, a abordagem “modelo-exemplo-resultado” em várias combinações ainda leva ao fato de os alunos perceberem o ciclo como um hieróglifo. Isso se manifestou no fato de que eles não entendiam por que havia uma condição para escrever ali, como escolher entre i++ e i – e outras coisas aparentemente óbvias. Para evitar estes equívocos, a abordagem ao falar sobre ciclos deve enfatizar o significado de repetir ações idênticas e só então formalizá-las através de uma estrutura. Portanto, antes de fornecer a sintaxe do loop, você precisa resolver o problema de frente. Uma solução primitiva para o problema do índice é semelhante a esta:

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("Заключение");

Como pode ser melhorado?
Substitua ações monótonas por um ciclo.
Quais ações são repetidas consecutivamente sem alterações?
Não há nenhum neste fragmento. Porém, os comandos para exibir a palavra “Capítulo” com um número são muito semelhantes entre si.
Portanto, a próxima etapa é encontrar a diferença entre os fragmentos. É somente nesta tarefa que tudo fica óbvio, então não serão repetidos comandos únicos, mas blocos de código de 5 linhas ou mais. Você terá que pesquisar não apenas na lista de comandos, mas em construções de ramificação ou loop.
No exemplo, a diferença entre os comandos está no número após a palavra “Capítulo”.
Uma vez encontrada a diferença, você precisa entender o padrão de mudança. O fragmento diferente é o número? Está aumentando ou diminuindo constantemente? Como o valor de um número muda entre duas equipes lado a lado?
No exemplo, o número após a palavra “Capítulo” aumenta em incrementos de 1. A diferença é encontrada, o padrão é revelado. Agora você pode substituir o fragmento diferente por uma variável.
Você precisa declarar tal variável antes do primeiro dos fragmentos repetidos. Tal variável é geralmente chamada de I ou j ou algo mais detalhado. Seu valor inicial deve ser igual ao primeiro valor exibido na tela. No exemplo, o primeiro valor é 1.
Qual valor inicial deve ser assumido para exibir a série de números “100, 101, 102, 103, 104, 105”?
O primeiro número desta série é 100.
Após cada comando de saída, você precisa aumentar o valor desta variável em 1. Esta unidade é a etapa de mudança.
Qual será a etapa da série de números “100, 102, 104, 106”?
Etapa 2 nesta linha.
Depois de substituir o fragmento diferente por uma variável, o código ficará assim:

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("Заключение");

Depois de aplicar a técnica “expressar o padrão de uma variável” no código, você obtém vários grupos de ações idênticas seguidas. Agora, as ações repetidas podem ser substituídas por um ciclo.

A sequência de resolução de um problema onde é necessário usar loops consiste nas seguintes etapas:

  1. Resolva “de frente” com muitos comandos separados
  2. Encontre um padrão
  3. Expresse o padrão de uma variável
  4. Design como um ciclo

A seguir, são introduzidos novos termos para que o aluno não se encontre na situação de “entendi tudo, mas não consigo falar”:
— um contador é sempre uma variável necessária para rastrear o número de passos em um loop. Normalmente, um número inteiro que é comparado à restrição.
— counter step — descrição do padrão de contra-mudanças.
- restrição - um número ou variável com a qual o contador é comparado para que o algoritmo seja final. O valor do contador muda para se aproximar do limite.
— loop body — um conjunto de comandos que serão repetidos. Quando dizem “o comando está escrito dentro de um loop”, eles se referem ao corpo.
— iteração do loop — execução única do corpo do loop.
— condição de loop — uma expressão lógica que determina se outra iteração será executada. (Pode haver confusão com estruturas ramificadas aqui)
Você precisa estar preparado para o fato de que no início os alunos usarão os termos para outros fins. Isto se aplica tanto aos fortes quanto aos fracos. Estabelecer uma linguagem comum é uma arte. Agora vou escrever brevemente: você precisa definir a tarefa “destacar o fragmento de código com <term>” e usar esses termos corretamente na conversa.
Após a transformação com um loop, o fragmento é obtido:

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

O principal equívoco

Um equívoco popular entre os estudantes é que eles colocam ações dentro de um loop que precisa ser feito apenas uma vez. Por exemplo assim:

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

Os alunos se deparam com esse problema o tempo todo, tanto no início quanto em problemas mais complexos.
Dica importante neste caso:

Quantas vezes você deve repetir o comando: uma vez ou várias vezes?

Os comandos para imprimir as palavras “Introdução” e “Conclusão” e declarar e inicializar a variável i não são como outras ações repetitivas. Eles são executados apenas uma vez, o que significa que precisam ser escritos fora do corpo do loop.

Todas as três etapas da solução devem permanecer no código para que você possa consultá-las posteriormente em caso de dificuldades. Basta comentar as duas primeiras opções para que não interfiram.
Deve-se chamar a atenção do aluno para os seguintes fatos:
— Em uma condição de loop, um contador e um limite são geralmente comparados. O contador pode mudar no corpo do loop, mas o limite não. Para quebrar esta regra, você precisa formular razões convincentes.
— Os comandos para exibir as palavras “Introdução” e “Conclusão” estão localizados fora do corpo do loop. Precisamos realizá-los 1 vez. “Introdução” - antes de repetir as ações, “Conclusão” - depois.
No processo de consolidação deste tópico, de domínio dos próximos, bem como de lidar com as dificuldades, é útil que até mesmo os alunos mais fortes façam a pergunta: “Quantas vezes esta ação precisa ser realizada? Um ou muitos?

Desenvolvimento de habilidades adicionais

No processo de estudo dos ciclos, os alunos também desenvolvem a habilidade de diagnosticar e resolver problemas. Para realizar o diagnóstico, o aluno precisa apresentar o resultado desejado e compará-lo com o resultado real. As ações corretivas dependem da diferença entre elas.
Como os alunos nesta fase ainda têm pouca ideia do resultado “desejado”, eles podem focar nos dados do teste. Via de regra, ninguém nesta fase ainda entende o que pode dar errado e como lidar com isso. Portanto, escrevo em um caderno uma descrição de problemas típicos e diversas maneiras de resolvê-los. A escolha do mais adequado é tarefa do próprio aluno.
É necessário um registro para perguntar “aconteceu o que era esperado?”, “Qual dessas situações aconteceu agora?”, “A solução aplicada ajudou?”

  1. O número de ações é 1 a menos ou mais que o esperado. Soluções:
    — aumente o valor inicial do contador em 1.
    — substitua o operador de comparação estrito (< ou >) por um não estrito (<= ou >=).
    — altere o valor limite para 1.
  2. As ações em loop são executadas sem parar, indefinidamente. Soluções:
    — adicione um comando de alteração de contador se estiver faltando.
    — corrija o comando de alteração do contador para que seu valor fique mais próximo do limite.
    — remova o comando de alteração de restrição se ele estiver no corpo do loop.
  3. O número de ações em um loop é maior que 1 a menos ou mais que o esperado. A ação no loop não foi executada nem uma vez. Primeiro você precisa descobrir os valores reais das variáveis ​​​​antes do início do loop. Soluções:
    — alterar o valor inicial da restrição
    — alterar o valor inicial do contador

O problema 3 geralmente envolve usar a variável errada ou não zerar o contador.

Após esta explicação, o aluno ainda pode ter vários equívocos sobre como funcionam os loops.
Para dissipar os mais comuns, dou-lhe as seguintes tarefas:

  1. Em que o limite, o valor inicial do contador ou o passo do contador são inseridos pelo usuário.
  2. Em que o valor do contador deve ser utilizado em alguma expressão aritmética. É aconselhável utilizar um contador na expressão radical ou no denominador para que a diferença seja não linear.
  3. Em que o valor do contador não é exibido na tela enquanto o loop está em execução. Por exemplo, exibindo o número necessário de fragmentos de texto idênticos ou desenhando uma figura com gráficos de tartaruga.
  4. Em que você precisa realizar primeiro algumas ações repetitivas e depois outras.
  5. Em que você precisa realizar outras ações antes e depois de repetir

Para cada tarefa você precisa fornecer dados de teste e o resultado esperado.

Para entender a rapidez com que você pode avançar, você precisa ler os termos desses problemas e perguntar: “como eles diferem do exemplo?”, “O que precisa ser mudado no exemplo para resolvê-los?” Se o aluno responder de forma significativa, deixe-o resolver pelo menos uma em sala de aula e o restante em casa sozinho. Se a solução for bem-sucedida, podemos começar a explicar as condições dentro dos loops.
Se você tiver problemas para resolver problemas sozinho, precisará resolver tudo em sala de aula. Para evitar que a solução do problema lembre o desenho de uma coruja, recomendo primeiro resolver o problema de uma forma não universal. Ou seja, para que a solução passe no primeiro teste e não utilize a construção do loop. Bem, então aplique transformações para alcançar a universalidade da solução.

Loops e ramificações

Na minha opinião, é útil abordar separadamente o tópico “ciclos dentro dos ramos”. Para que mais tarde você possa ver a diferença entre verificar uma condição várias vezes e verificá-la uma vez.
As tarefas de consolidação serão sobre a saída de números de A para B, que são inseridos pelo usuário:
- sempre em ordem crescente.
- ascendente ou descendente dependendo dos valores de A e B.

O tópico “ramificação dentro de loops” deve ser abordado somente após o aluno ter dominado as técnicas: “substituição de um padrão por uma variável” e “substituição de ações repetitivas por um ciclo”.
A principal razão para usar ramificações dentro de loops são anomalias no padrão. No meio ele quebra dependendo dos dados iniciais.
Para aqueles alunos que conseguem buscar uma solução combinando técnicas simples, basta dizer “a ramificação pode ser escrita dentro de loops” e dar o problema “por exemplo” para resolver completamente de forma independente.
Tarefa de exemplo:

O usuário insere o número X. Exiba os números de 0 a 9 em uma coluna e coloque um sinal '+' oposto ao número que é igual a X.

Se 0 foi inserido0+
1
2
3
4
5
6
7
8
9

Se 6 foi inserido0
1
2
3
4
5
6+
7
8
9

Se 9 foi inserido0
1
2
3
4
5
6
7
8
9+

Se 777 foi inserido0
1
2
3
4
5
6
7
8
9

Se uma breve explicação não for suficiente para escrever com loop, então você precisa encontrar uma solução universal para o mesmo problema sem loop.
Você terá uma de duas opções:
Desejado

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);
}

Possível

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+");
}

Dou uma tarefa semelhante com antecedência, enquanto estudo o tema da ramificação.
Se o aluno apresentar uma opção “possível”, você precisará dizer a ele que pode haver muitas soluções para o mesmo problema. No entanto, eles diferem na sua resistência a mudanças nos requisitos. Faça a pergunta: “Quantos lugares no código precisariam ser corrigidos se eu tivesse que adicionar outro número?” Na versão “possível”, será necessário adicionar mais uma filial e adicionar um novo número em outros 10 locais. No “desejado” basta adicionar apenas um ramo.
Defina a tarefa de reproduzir a opção “desejada”, depois encontre um padrão no código, execute uma substituição de variável e escreva um loop.
Se você tem uma ideia de como resolver esse problema sem loop de alguma outra forma, escreva nos comentários.

Loops dentro de Loops

Neste tópico você precisa prestar atenção ao seguinte:
— os contadores dos loops interno e externo devem ser variáveis ​​diferentes.
— o contador do loop interno deve ser zerado várias vezes (ou seja, no corpo do loop externo).
— em tarefas de saída de texto, você não pode escrever primeiro uma letra em várias linhas e depois a segunda. Você deve primeiro imprimir todas as letras da primeira linha, depois todas as letras da segunda e assim por diante.

É melhor começar a explicar o tópico de loops dentro de loops explicando a importância de zerar o contador.
Tarefa de exemplo:

O usuário insere dois números: R e T. Imprime duas linhas de caracteres “#”. A primeira linha deve conter caracteres R. A segunda linha contém peças T. Se algum número for negativo, exibe uma mensagem de erro.

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

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

R=-1, T=6O valor R deve ser não negativo

R=6, T=-2O valor T deve ser não negativo

Obviamente, este problema também tem pelo menos duas soluções.
Desejado

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;
}

Possível #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;
}

A diferença é que na solução "possível", uma segunda variável foi utilizada para gerar a segunda linha. Você deve insistir em usar a mesma variável para ambos os loops. Esta limitação pode ser justificada pelo facto de uma solução com um contador para dois ciclos ser uma ilustração do termo “reinicialização do contador”. A compreensão deste termo é necessária ao resolver os seguintes problemas. Como compromisso, você pode salvar ambas as soluções para o problema.

Um problema típico com o uso de uma variável de contador para dois loops é assim:
R=5, T=11#####
######

O número de caracteres na segunda linha não corresponde ao valor de T. Se precisar de ajuda com esse problema, você precisará consultar as notas sobre problemas típicos com loops. Este é o sintoma nº 3. É diagnosticado se você adicionar uma saída de valor do contador imediatamente antes do segundo ciclo. Corrigido pela redefinição. Mas é melhor não contar isso imediatamente. O aluno deve tentar formular pelo menos uma hipótese.

Existe, claro, outra solução. Mas nunca vi isso entre os estudantes. Na fase de estudo dos ciclos, a história a respeito distrairá a atenção. Você pode voltar a isso mais tarde, quando aprender sobre funções de string.
Possível #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));

Próxima tarefa necessária:

Exiba os números de 0 a 9. Cada número deve estar em sua própria linha. O número de dígitos em uma linha (W) é inserido no teclado.

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

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

Se um aluno dominar a técnica de substituição de uma variável, ele lidará com isso rapidamente. Um possível problema estará novamente na redefinição da variável. Se você não consegue lidar com a transformação, significa que estava com pressa e precisa resolver problemas mais simples.

Obrigado pela sua atenção. Curta e se inscreva no canal.

PS Se você encontrar erros de digitação ou erros no texto, por favor me avise. Isso pode ser feito selecionando parte do texto e pressionando “⌘ + Enter” no Mac, e “Ctrl/Enter” nos teclados clássicos, ou através de mensagens privadas. Se essas opções não estiverem disponíveis, escreva sobre os erros nos comentários. Obrigado!

Apenas usuários registrados podem participar da pesquisa. Entrarpor favor

Enquete para leitores sem carma

  • 20,0%Eu ensino profissionalmente, +12

  • 10,0%Eu ensino profissionalmente, -11

  • 70,0%Eu não ensino, +17

  • 0,0%Eu não ensino, -10

  • 0,0%Outro0

10 usuários votaram. 5 usuários se abstiveram.

Fonte: habr.com

Adicionar um comentário