Teórica 01 (24/set/2018)
Computação. Algoritmo. Programas e Linguagens de Programação.
Computadores eletrónicos.
Code::Blocks - Um ambiente integrado de desenvolvimento de programas.
A Linguagem de Programação C.
Primeiros programas em C usando: funções com um argumento, instrução condicional if, tipos int e double, instruções de input e output.
Descrição de IP-B
Docentes & Horários
Convém fazer a disciplina por avaliação contínua e considerar o exame final é para usar só se alguma coisa correr mal (ou então para subir a nota).
Nesta disciplina não se chumba por faltas. No entanto, espera-se que os alunos vão à maioria das aulas. Em cada aula prática vai circular uma folha de presenças que os alunos presentes devem rubricar. A folha fornece dados estatísticos e também dá aos professores informação positiva relativamente aos alunos presentes.
Para estimular a resolução de exercícios, estará disponível na página da cadeira um serviço de avaliação automática de exercícios de programação chamado Mooshak. Espera-se que os alunos resolvam a maioria dos exercícios instalados no Mooshak, apesar disso não ser obrigatório. A resolução dos exercícios do Mooshak não contribui de forma direta para a nota final, apesar de fornecer aos professores informação positiva sobre os alunos. A aula prática 02 vai ser dedicada ao Mooshak.
Faz parte dos objetivos formais da disciplina desenvolver algumas capacidades de trabalho em equipa. Nas aulas práticas os alunos trabalham aos pares, dois alunos em cada computador, embora isso não seja estritamente obrigatório. Mas o projeto final já será obrigatoriamente feito por grupos de 2 alunos. Só em raros casos, muito especiais, serão autorizados grupos com um único aluno, por exemplo no caso de certos trabalhadores-estudantes.
Documentação oferecida
Folhas das aulas teóricas
Enunciados de testes antigos
Exemplo de programa escrito na linguagem C
Nesta cadeira vamos aprender a programar usando a linguagem C!
O objetivo principal é aprender a escrever programas de pequena dimensão. Mas também existe o objetivo secundário de conhecer parte da própria linguagem C, a ferramenta que usaremos para escrever os programas.
O seguinte programa, escrito em C, quando executado num computador, determina qual é máximo divisor comum entre dois números inteiros positivos que são pedidos ao utilizador:
int euclides(int m, int n) /* Implementação do algoritmo de Euclides */
printf("Introduza dois inteiros: ");
printf("Resposta: mdc(%d,%d) = %d\n", a, b, euclides(a, b));
Eis um exemplo de execução do programa:
Introduza dois inteiros: 123 456
Resposta: mdc(123,456) = 3
Razões pelas quais esta cadeira é importante!
Os aluno deste curso não vão ser programadores profissionais. Será que esta cadeira é assim tão importante?
A resposta é SIM! Por diversas razões:
Na vida profissional é uma enorme vantagem saber escrever pequenos programas para, por exemplo, processar uma coleção de dados guardados em ficheiros. É verdade que alguns dos problemas mais simples podem ser resolvidos carregando os dados numa folha de cálculo, fazendo umas ordenações e escrevendo uma fórmulas. Mas muitos problemas requerem mesmo a escrita dum pequeno programa.
Por vezes precisamos de resolver um programa e até descobrimos na Net um programa que faz mais ou menos aquilo que queremos, mas não o faz completamente. É importante ter a capacidade de olhar para um programa já escrito, entender as partes do código que nos interessam, e conseguir alterar alguns pormenores para o programa passar a fazer o que precisamos.
Saber escrever alguns pequenos programas de processamento de dados e de cálculo de estatísticas poderá ser importante para a tese de final de curso. Também poderá ser uma vantagem para o aluno nos trabalhos de outras cadeiras.
Programar é uma atividade que consiste em instruir uma máquina a realizar uma tarefa! Usa-se a máquina para resolver problemas que nos interessam!
Exemplos de tarefas complicadas realizáveis por computador: gerir os stocks dum grande supermercado; jogar xadrez; compreender e falar português.
A programação é uma tarefa atividade interessante, criativa e trabalhosa que exige que se pense duma forma muito especial. Só se adquire essa forma de pensar com a prática.
Aprender a programar requer persistência e que se pratique muito.
Conclusão: Aprender a programar exige tempo e dedicação.
A programação pode ser efetuada usando diversas estratégias, umas mais inteligentes do que outras. A técnica menos inteligente de todas chama-se força bruta. Aproveita-se a velocidade do computador para resolver o problema. Por exemplo, se quisermos saber quantas vezes o número 7 cabe no número 50, podemos fazer assim, i.e. subtrair o 7 sucessivamente até se chegar a um valor inferior a 7:
// forca bruta
while( number >= 7 ) {
how_many = how_many + 1;
Mas a estratégia anterior é um pouco pateta, não é? A solução inteligente usa diretamente a divisão inteira:
// uma solucao inteligente
int how_many = 50 / 7;
Programar com confiança!
Como em tudo na vida, para desempenhar uma tarefa com confiança é preciso ganhar experiência, ou seja praticar bastante.
Ao contrário de outras disciplinas, como a Álgebra ou a Análise Matemática, a maioria dos alunos não tem qualquer experiência prévia de programação. Ou seja, o grau de novidade é muito grande. Depois, para complicar, o semestre é curto e há apenas 10 aulas teóricas efetivas em IP-B.
Por isso, não surpreende que muitos alunos não sintam o nível de confiança que gostariam de ter no final do semestre. Só se consegue combater este problema praticando muito ao longo do semestre e resolvendo todos os exercícios, se possível.
Em 1975, Fred Brooks identificou 5 razões pelas quais programar é divertido. Foi no seu livro "The Mythical Man-Month: Essays on Software Engineering", concretamente no capítulo 7, chamado "Joys of the Craft". O que se segue é uma adaptação livre:
É divertido programar pelo prazer de construir coisas. Tal como as crianças gostam de criar objetos com plasticina e alguns adultos de pintar quadros ou reconstruir automóveis antigos.
É divertido programar pelo prazer de construir coisas que são úteis para as outras pessoas. Tal como as crianças gostam de desenhar uns bonecos horríveis para o pai ou a mãe dependurarem na parede do gabinete de trabalho.
É divertido programar pelo fascínio de criar sistemas complexos, com diversas partes que se ligam de forma sofisticada. Faz também parte do fascínio observar os detalhes funcionamento do sistema, entendendo a sua arquitetura interna.
É divertido programar pelo prazer de estar sempre a aprender, o que advém do facto de programar nunca ser uma atividade repetitiva. Todos os problemas contém algo de novo e o programador aprende sempre algo de novo com cada problema.
É divertido programar pela maravilha que é trabalhar com uma "matéria prima" infinitamente flexível, próxima do pensamento puro. O programador desenvolve nos seus programas estruturas de ideias que refletem diretamente a sua imaginação, quase como um poeta.
Nota: Evidentemente os programadores não têm o monopólio da criatividade; a maioria destas 5 razões também se aplicam a outras atividades humanas. No entanto são poucas as atividades que usam uma "matéria prima" tão flexível - conceitos do pensamento.
Fred Brooks também escreveu no seu livro um capítulo chamado "The Woes of the Craft" ("As Desventuras da Programação"). Alguns dos problemas: os programas têm de ser perfeitos e de confiança; descobrir e corrigir erros de pormenor nos programas pode ser demorado, maçador e trabalhoso; por vezes aproveitamos código existente, mas por vezes esse código é confuso, difícil de perceber.
Conceitos iniciais: Computação, Algoritmos, Programas
Nesta cadeira vamos aprender a escrever programas que se destinam a ser executados num computador.
Para perceber o que é um programa, temos de compreender que se trata da concretização dum algoritmo que descreve computações.
Programar envolve a invenção de algoritmos que depois têm de ser convertidos em programas que correm no computador.
Tentemos clarificar estes conceitos:
O objetivo da Informática é estudar a computação e estudar formas úteis de tirar partido dela para resolver problemas importantes.
Um algoritmo é uma maneira de resolver um problema. Corresponde a um conjunto de regras que determinam completamente como uma computação vai decorrer. É precisa imaginação para inventar algoritmos.
Um algoritmo é uma "receita" para resolver um problema.
Em geral um mesmo problema pode ser resolvido usando diversos algoritmos, ou seja, de diversas maneiras. Realmente, depende da imaginação de quem o inventa.
Um algoritmo é independente de qualquer linguagem de programação particular. Um dado algoritmo pode ser implementado em C, em Java, etc.
A palavra "algoritmo" deriva da palavra Algoritmi que por sua vez corresponde à latinização do nome do matemático Persa Muhammad ibn Musa al-Khwarizmi, nascido por volta de 780 DC. Este cientista, que trabalhou quase toda a sua vida em Bagdad, deu importantes contribuições para a Álgebra, Trigonometria e Aritmética. Veja aqui um vídeo de 5 minutos sobre esta génio da antiguidade.
Eis o algoritmo de Euclides (300 BC), que serve para achar o máximo divisor comum entre dois números - MDC(m,n).
Usar dois contadores x e y.
Inicializar x com m e inicializar y com n.
Se x > y então o valor de x muda para x - y
Se x < y então o lavor de y muda para y - x
Repetir os dois passos anteriores até os valores de x e y ficarem iguais. Quando isso acontecer, esse é o resultado final.
Euclides demonstrou que este algoritmo calcula efetivamente o valor MDC(m,n) e não qualquer outro valor.
Exemplo - Cálculo de MDC(252, 105):
Inicialização 252 105
Passo 1 147 105
Passo 2 42 105
Passo 3 42 63
Passo 4 42 21
Passo 5 21 21
Algoritmos, logo desde a escola primária
Logo a partir da escola primária (1º ciclo) aprendem-se diversos algoritmos: somar, subtrair, multiplicar e dividir.
Os algoritmos mais antigos que se conhecem foram inventados pelos Babilónios (3000AC-1500AC). Eles criaram algoritmos para fatorizar números, achar raízes quadradas, e muito mais. Os seus livros de Matemática eram acima de tudo receitas sobre como efetuar os cálculos para resolver determinados problemas. Esses algoritmos eram para executar "à mão".
Antigamente, "computador" era o nome duma profissão humana (bastante monótona, diga-se). Quando apareceram os primeiros computadores eletrónicos, eles receberam esse nome porque faziam trabalho que previamente era feito por computadores humanos.
A principal motivação para executar algoritmos em máquinas é a grande velocidade de execução.
Um programa é a expressão concreta dum algoritmo. Trata-se dum texto que descreve o algoritmo usando regras de escrita bem definidas.
Diz-se que: um programa implementa um algoritmo numa linguagem de programação concreta.
Um programa é usado para controlar as operações e cálculos que o computador executa.
Cada linguagem de programação é caraterizada por conjunto de regras sintáticas e por conjunto semânticas, descritas no documento de referência da linguagem.
As regras sintáticas definem a estrutura das construções de texto que podem ser usadas nos programas.
As regras semânticas definem o efeito da execução dessas construções.
Implementação em C do algoritmo de Euclides
Trata-se do programa apresentado logo no início desta aula.
Computadores eletrónicos
A imagem abaixo mostra a arquitetura dum computador eletrónico moderno. Repare nos dispositivos de entrada e saída, na memória onde residem os dados e o programa, e no processador (CPU) que serve para executar o programa.
O C é uma linguagem de alto nível, concebida para ser usada por humanos, mas não pelo processador da máquina. De facto, os circuitos eletrónicos do processador só "entendem" uma linguagem de baixo nível a que se costuma chamar linguagem máquina.
Assim, para um programa em C poder correr no computador, o programa terá primeiro de ser traduzido para linguagem máquina.
Code::Blocks - Um ambiente integrado de desenvolvimento de programas
Normalmente os programas são desenvolvidos dentro dum ambiente integrado de desenvolvimento, dentro do qual podemos escrever e executar os nossos programas. Um bom sistema de desenvolvimento aumenta a produtividade dos programadores e contribui indiretamente para aumentar a qualidade dos programas. Se não tivéssemos um ambiente integrado, restar-nos-ia usar um editor de texto normal para escrever os programas (o que também não seria o fim do mundo...)
Na nossa a disciplina usaremos o ambiente Code::Blocks que funciona igualmente bem em Windows, Macintosh e Linux. Aproveita o gcc, que é o compilador de C dos GNU Tools do Linux. O Code::Blocks é um sistema gratuito mas de muito boa qualidade e muito rápido.
Veja na aula prática 1 um pequeno guia sobre a utilização do Code::Blocks.
Programando usando o Code::Blocks...
Para escrever um programa em C, usamos o editor de texto do Code::Blocks.
Antes de ser executado, o nosso programa fonte tem de ser compilado, ou seja, traduzido para a linguagem máquina que o processador sabe executar.
Durante a compilação, o compilador deteta possíveis erros de escrita, ou seja, possíveis violações das regras sintáticas da linguagem. Os erros são assinalados, e para cada um deles aparecerá uma explicação, mais ou menos clara.
Um programa sem erros sintáticos é sempre compilado com sucesso. Depois de adicionado o código das funções de biblioteca, é gerado o chamado programa executável que fica guardado num ficheiro com extensão ".exe".
Mas um programa sem erros sintáticos pode, ainda assim, ter erros de lógica. Os erros de lógica podem ser muito graves, pois os resultados podem estar errados e ninguém dar por isso.
Os erros de lógica são da responsabilidade do programador e são causados por incompreensão, distração, descuido, pressa ou excesso de confiança.
Uma forma de tentar detetar os perigosos erros de lógica, é correr o programa várias vezes com diferentes valores de entrada e observar os resultados. Chama-se a isso testar o programa.
Mas não é possível testar um programa para todas as entradas possíveis. Por isso, o melhor mesmo é escrever os programas usando uma lógica impecável, que previna o aparecimento de erros logo na origem.
Dennis Ritchie Brian Kernighan
https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Standards.html#C-Language
Concebida e implementada por Dennis Ritchie entre 1969 e 1973 nos Bell Labs da AT&T. A segunda versão do sistema operativo Unix foi escrita em C, em 1973.
Uma das linguagens atualmente mais populares, tem sido utilizada para escrever todo o tipo de aplicações tais como compiladores, bases de dados, sistemas operativos (Unix, por exemplo), editores gráficos e de texto, jogos 3D, etc.
É uma linguagem normalizada, com standards ANSI (American National Standards Institute) e ISO (International Standards Organization). A versões mais recentes da norma pode ser designada tanto como ISO C11 ou como ANSI C11. O compilador de C do Code::Blocks, o gcc, respeita esta norma de forma bastante satisfatória. (Sobre os padrões da linguagem C: aqui.)
Linguagem de alto nível, imperativa, procedimental e estruturada.
Permite ao programador escrever código muito eficiente e permitindo a manipulação direta da memória.
Encoraja independência da máquina. Este aspeto é extremamente importante pois cumpre um dos objetivos de qualquer linguagem de programação: a possibilidade de escrever programas independentes de cada máquina particular.
É necessária uma boa disciplina na programação para se produzirem programas legíveis.
Tipos de dados básicos: carateres, inteiros, reais, booleanos, enumerados.
Tipos de dados derivados: arrays, registos, uniões, apontadores.
Tipificação fraca: por exemplo, os carateres e os valores enumerados são tratados como inteiros.
Estruturas de controlo: condicionais, iterativas, seletivas.
Funções. Recursividade é suportada. Não suporta a definições de funções dentro de outras funções.
A linguagem C influenciou fortemente outras linguagens, como o C++, C#, Objective-C e Java.
O C é uma linguagem antiga e sempre foi bastante popular. Aliás nos últimos 30 anos esteve quase sempre em 1º lugar nas listas de popularidade, trocando raramente de posição com a linguagem Java nos últimos 15 anos.
Primeiros programas em C usando: funções, instrução condicional if, tipos int e double, instruções de input e output
Na aula teórica de hoje vamos examinar alguns pequenos programas, já completamente escritos, e vamos tentar percebê-los.
Note que, nas primeiras aulas práticas, você irá programar imitando estes exemplos, mesmo antes de dominar os detalhes da linguagem C. As aulas práticas disponíveis têm de ser bem aproveitadas logo desde o início, mesmo com as aulas teóricas apenas a começar.
1º programa em C
Desenvolva um programa que escreva simplesmente Bem-vindos!.
printf("Bem-vindos!\n");
Um programa em C é constituído principalmente por funções. Neste caso, o programa contém apenas uma função.
É obrigado existir uma função chamada main, que se designa como função principal. É na função principal que o programa começa a correr.
A palavra função tem em C um sentido técnico específico, com algumas semelhanças, mas não é completamente igual ao sentido usado da Matemática. Esta questão será discutida em aulas posteriores.
Olhando para o cabeçalho da função, vê-se que ela não tem argumentos (escreve-se void, para indicar isso) e que produz um valor inteiro.
No corpo da função, ocorrem duas instruções, em duas linhas diferentes. Cada instrução é obrigatoriamente terminada por um ponto e vírgula.
A primeira instrução consiste numa chamada da função printf para escrever uma string (um pedaço de texto), onde \n indica uma mudança de linha. Na maior parte dos casos, devemos colocar esse \n no final da string, para que seja escrita uma linha de texto devidamente terminada.
A segunda instrução, um return, faz a função terminar imediatamente, produzindo (retornando) o valor zero, neste caso.
No caso particular da função main, o valor retornado é recebido pelo sistema operativo e o valor 0 indica que o programa terminou normalmente; outros valores podem ser usados para indicar situações de erro.
A diretiva include, na primeira linha, permite que este programa tenha acesso a informação sobre a biblioteca de input/output do C, uma biblioteca chamada stdio (standard input output). A função printf, usada no programa, faz parte da biblioteca stdio.
Um programa com duas funções
Desenvolva um programa que calcule o cubo de valores inteiros.
Quem escreve um programa tem a responsabilidade de escrever código claro, fácil de entender por outras pessoas.
Um bom programa em C é sempre constituído por várias funções. Cada função deve desempenhar uma tarefa bem definida e deve ter um nome bem escolhido que sugira essa tarefa.
A função cube tem um argumento inteiro, e produz um resultado inteiro. Para uma função desempenhar a sua tarefa, tem de ser chamada. Neste caso, ela é chamada a partir da função main.
Este é um caso relativamente raro em que o printf não escreve um \n no final, para permitir que a leitura do valor introduzido pelo utilizador seja feita na mesma linha, e não na linha seguinte. Isto é motivado por uma simples questão de estética.
Uma novidade! Dentro da função main define-se uma variável inteira, chamada i neste caso, que é usada para recolher o valor introduzido pelo utilizador.
A função de biblioteca scanf serve para ler valores da consola. Os valores lidos são guardados em variáveis. Na string de formatação deste scanf, o designador de formato %d indica que se pretende ler um valor inteiro em formato decimal (ou seja, em base 10 - o C também suporta os formatos octal e hexadecimal). Num scanf, cada variável tem de ser precedida pelo símbolo "&". Note que, ao contrário do caso printf, num scanf nunca se mete um \n na string de formatação.
Nesta chamada de printf, com três argumentos, a string de formatação inclui duas ocorrências do designador de formato %d que indicam que devem ser escritos dois valores inteiros em decimal (base 10). Repare que esses valores são obtidos nos argumentos que aparecem a seguir à string de formatação.
Um programa que usa números reais e a instrução condicional if
Desenvolva um programa que calcule o módulo (valor absoluto) de valores reais.
double module(double x)
printf("Introduza um valor real: ");
printf("O modulo de %lf tem o valor %lf.\n", r, module(r));
A função module tem um argumento real e produz um resultado real. Em C, o nome double serve para designar valores reais. Tal como na Matemática, na linguagem C existe distinção entre números inteiros e números reais. Em cada problema, devemos escolher o tipo de números mais adequado, ou então usar o tipo de números indicado no enunciado do problema.
Num programa, deve ser possível poder tomar decisões em função do estado corrente do programa. Para isso usa-se a instrução condicional if. Uma instrução if envolve: uma condição e dois ramos alternativos. Só um dos ramos é executado, consoante a condição seja verdadeira ou falsa.
Há uma terceira novidade neste programa: o uso do designador de formato %lf nas chamadas das funções de input e output. Esse designador de formato representa valores de tipo double.