Baixe o app para aproveitar ainda mais
Prévia do material em texto
Algoritmos e a Lógica de Programação Origem do termo Algoritmo Palavra algoritmos vem do latim • dos termos algorismos ou algorithmos que estão associados à ideia de algarismos ou algorithmos, • que estão associados à ideia de algarismos por influência do idioma grego a partir do termo arithmós associado à ideia de números Origem do termo Algoritmo Segundo o dicionário, a palavra algoritmo é aplicada em: • Matemática • Está associada a um processo de cálculo, ou de resolução de um grupo de problemas semelhantes, em que se estipulam, com generalidade e sem restrições, regras formais para obtenção do resultado, ou da solução do problema • Computação • Está associada a um conjunto de regras e operações bem definidas e ordenadas, destinadas à solução de um problema, ou de uma classe de problemas, em um número finito de passos Origem do termo Algoritmo Em um sentido mais amplo, algoritmo é um processo sistemático para a resolução de um problema, ou de uma sequência ordenada de passos a ser observada para a realização de uma tarefa Regras formais, sequenciais e bem definidas a partir do entendimento lógico de um problema a ser resolvido por um programador com o objetivo de transformá-lo em um programa que seja possível de ser tratado e executado por um computador Do ponto de vista computacional, o termo algoritmo pode ser entendido como: Cozinha x Computador Ingredientes • são definidos os dados a serem usados e as quantidades que devem estar preparadas e separadas para a elaboração da receita Modo de preparo • são descritos o programa de ações e a sequência de atividades Receita Culinária Bloco de ingredientes + Bloco do modo de preparo Estabelecem o roteiro de trabalho a ser seguido (o programa de atividades) Se uma das etapas definidas em toda a receita deixar de ser seguida, ter- se-á no final um resultado diferente do preestabelecido na receita Cozinha x Computador Cozinheiro pessoa que, se seguir os passos da receita, consegue preparar a refeição indicada sem grandes dificuldades Mestre-cuca cria e inventa receitas Usuário prova a refeição que foi preparada pelo cozinheiro, que não é necessariamente um mestre-cuca, mas alguém que, ao longo de um determinado tempo, pode se tornar um Cozinha x Computador Na atividade de programação de computadores há etapas semelhantes às de uma cozinha Programador de computador • Mestre-cuca prepara o programa a ser utilizado por uma pessoa denominada usuário • Cozinheiro montam programas a partir de algoritmos já escritos Usuário quer consumir, usar um programa como alguém que entra em um restaurante e deseja comer um alimento • Ele não está preocupado com a maneira como o alimento foi preparado (ou como um programa de computador foi escrito), simplesmente quer usá-lo Raciocínio Lógico Conjunto de estudos que visa determinar os processos intelectuais que são as condições gerais do conhecimento verdadeiro Sequência coerente, regular e necessária de acontecimentos, de coisas ou fatos, ou até mesmo a maneira do raciocínio particular que cabe a um indivíduo ou a um grupo Esquema sistemático que define as interações de sinais no equipamento automático do processamento de dados, ou o computador científico com o critério e princípios formais de raciocínio e pensamento Na área da computação Raciocínio Lógico Pode-se dizer que lógica é a ciência que estuda as leis e os critérios de validade que regem o pensamento e a demonstração, ou seja, ciência dos princípios formais do raciocínio Aprender a pensar o “computador”, ou seja, é necessário modelar o pensar e o raciocínio ao formato operacional preestabelecido e funcional de um computador eletrônico Raciocínio Lógico As bases que norteiam o processo da programação de computadores vêm das mesmas ideias estudadas e apresentadas por Charles Babbage com a máquina analítica e da programação idealizada por sua assistente, Ada Augusta Byron King, condessa de Lovelace, que desenvolveu os algoritmos que permitiriam à máquina analítica computar os valores de funções matemáticas Algoritmos Os computadores ou sistemas computacionais são as ferramentas que vão nos permitir automatizar grande parte das tarefas do nosso dia-a-dia, seja no contexto profissional ou pessoal. Não existe “mágica” alguma por trás deste processo de automatização, mas é necessário que o usuário seja capaz de “convencer” o computador a executar estas tarefas de forma automática. Isto é feito através dos programas computacionais, construídos a partir do uso de linguagens de programação, cujo objetivo é oferecer ao usuário (ou programador) um meio de comunicação com a máquina. Algoritmos A construção de um programa computacional é motivada geralmente a partir de uma necessidade de solução de um problema particular: geração automática de documentos, controle de um equipamento eletrodoméstico, transmissão de informações em longas distâncias, agilização de cálculos científicos, e outras motivações mais. A solução dos nossos problemas através de um sistema computacional só é obtida no momento em que é definido um conjunto coerente de instruções de um programa que permita estabelecer que ações deverão ser executadas e em que ordem. A descrição formal do processo de obtenção de uma solução computacional é definida como sendo um algoritmo. Algoritmos Desde o início da Computação, diversos autores preocuparam-se em apresentar uma definição adequada para o termo algoritmo. Definição dada por Kronsjö: “Algoritmo é um procedimento consistindo de um conjunto finito de regras não ambíguas que especificam uma seqüência finita de operações necessárias à solução de um problema ou para especificar uma classe de problemas” Os algoritmos são uma ferramenta importante para a especificação formal das ações a serem realizadas por um computador para automatizar a solução de um problema. Algoritmos O objetivo na construção dos algoritmos é evitar qualquer ambigüidade que possa surgir na definição de um problema e que pode resultar em erros (muitas vezes catastróficos) uma vez que a solução venha a ser executada pelo computador. Em sua rotina diária, o ser humano, mesmo sem se dar conta, executa algoritmos bastante básicos, como por exemplo, uma receita de bolo, instruções de montagem de um aparelho, etc. Outra definição: Algoritmo é uma seqüência ordenada, e sem ambigüidade, de passos que levam à solução de um dado problema! Algoritmos Procedimento passo a passo para resolver um problema Pessoas tem inteligência e habilidade racional => fazem perguntas para se esclarecer. Computador não tem senso próprio => deve receber instruções explícitas (algoritmos) Os Computadores, infelizmente só fazem aquilo que mandamos e não necessariamente o que desejamos que eles façam! Não deve haver ambigüidade nas instruções do programa Algoritmos A tarefa de programação dos computadores não é simples À medida que a complexidade dos problemas foi aumentando, constatou-se que a construção de um programa deveria ser, na realidade, resultado de um trabalho de engenharia, como o são tantos outros produtos. Da mesma forma como, no caso de um edifício ou o motor de um automóvel, não se passa diretamente da idéia à construção, o desenvolvimento de um programa deverá ser caracterizado pela execução de uma fase (a mais exaustiva possível) de reflexão ondeo objetivo é analisar o problema a resolver e encontrar uma solução (se possível, a melhor) que possa ser realizada por um sistema computacional. O resultado deste trabalho de reflexão pode ser, então, registrado na forma de um algoritmo, a partir do qual o programa será finalmente construído. Algoritmos A construção de um programa pode tornar-se uma tarefa de extrema dificuldade, cujos resultados podem ser totalmente catastróficos. Os fatores podem ser os mais diversos, mas poderíamos organizá-los basicamente em duas categorias: A dificuldade intrínseca do problema, uma vez que existem casos onde a implementação computacional é de difícil solução A má definição do problema, provocada por um processo ineficiente de análise e busca da solução Algoritmos Etapas da Construção de Programas DEFINIÇÃO (o que) DESENVOLVIMENTO (como) • Projetar a Solução (ALGORITMO) • Codificar a Solução (Programar em Linguagem de Computador) • Testar o Programa Definição do Problema Algoritmos Etapas da Construção de Programas Problema Solução em Forma de Algoritmo Solução como um Programa de Computador Fase de resolução do Problema Fase da Implemen- tação Passo Difícil Algoritmos Etapas da Construção de Programas É preciso separar a Fase de Resolução do Problema da Fase de Implementação Um algoritmo correto deve possuir 4 qualidades: 1- O algoritmo deve ter um início 2- Cada passo do algoritmo deve ser uma instrução que possa ser realizada 3- A ordem dos passos deve ser precisamente determinada 4- O algoritmo deve ter um fim Algoritmos A linguagem natural é a forma mais imediata de representação de algoritmos. Um cuidado que deve ser tomado quando da adoção da linguagem natural como forma de representação de algoritmos é o uso de um alfabeto de símbolos (palavras) relativamente limitado, de modo a facilitar, numa etapa posterior, a tradução deste para uma linguagem de programação. O uso da linguagem natural pode provocar alguns problemas de interpretação do funcionamento do algoritmo se este tiver um grau de complexidade relativamente elevado. O grande número de linhas utilizado para descrever a solução de um problema, se apresentado de forma linear, pode representar um grande obstáculo ao entendimento do problema. A Linguagem Natural e o Texto Estruturado Algoritmos Observemos novamente o exemplo de algoritmo que explica a uma pessoa como trocar o pneu de um carro. pegar o macaco e o estepe no porta-malas do carro se o estepe estiver cheio levantar o carro usando o macaco retirar o pneu furado colocar o estepe em seu lugar abaixar o carro guardar o macaco e o pneu furado senão aguardar socorro A Linguagem Natural e o Texto Estruturado Algoritmos O exemplo apresentado é ainda relativamente curto para ilustrar a dificuldade de compreensão que a apresentação neste formato pode representar. Utilizando as facilidades de indentação (tabulação) pode-se torná-lo mais compreensível. A forma de representação denominada de texto estruturado, é largamente utilizada na descrição do comportamento de programas de computador, de um lado, pela sua “informalidade” e, por outro, pela sua proximidade com a forma de escrever programas em um número bastante grande de linguagens de programação. A Linguagem Natural e o Texto Estruturado Algoritmos pegar o macaco e o estepe no porta-malas do carro se o estepe estiver cheio levantar o carro usando o macaco retirar o pneu furado colocar o estepe em seu lugar abaixar o carro guardar o macaco e o pneu furado senão aguardar socorro A Linguagem Natural e o Texto Estruturado ALGORITMO PARA TROCAR PNEU DE UM CARRO ALGORITMO PARA TROCAR PNEU DE UM CARRO ALGORITMO PARA TROCAR PNEU DE UM CARRO ALGORITMO PARA TROCAR PNEU DE UM CARRO ALGORITMO PARA TROCAR PNEU DE UM CARRO Início Trocar Pneu Fim E se o estepe estiver vazio? Isto traz necessidade de uma decisão entre duas possibilidades ALGORITMO PARA TROCAR PNEU DE UM CARRO Início se <o estepe está vazio> então chamar borracheiro senão mudar o pneu fim se Fim Estrutura Condicional ALGORITMO PARA TROCAR PNEU DE UM CARRO Início se <o estepe está vazio> então chamar borracheiro senão mudar o pneu fim se Fim Estrutura Condicional A atividade de mudar o pneu pode ser mais detalhada ALGORITMO PARA TROCAR PNEU DE UM CARRO Início se <o estepe está vazio> então chamar borracheiro senão levantar o carro desparafusar a roda remover a roda colocar o estepe parafusar a roda abaixar o carro fim se Fim Estrutura Sequencial ALGORITMO PARA TROCAR PNEU DE UM CARRO Início se <o estepe está vazio> então chamar borracheiro senão levantar o carro desparafusar a roda remover a roda colocar o estepe parafusar a roda abaixar o carro fim se Fim Estrutura Sequencial A atividade de desparafusar a roda pode ser mais detalhada A atividade de parafusar a roda pode ser mais detalhada ALGORITMO PARA TROCAR PNEU DE UM CARRO Início se <o estepe está vazio> então chamar borracheiro senão levantar o carro desparafusar o 1o parafuso desparafusar o 2o parafuso desparafusar o 3o parafuso desparafusar o 4o parafuso remover a roda colocar o estepe parafusar o 1o parafuso parafusar o 2o parafuso parafusar o 3o parafuso parafusar o 4o parafuso abaixar o carro fim se Fim Estrutura Sequencial ALGORITMO PARA TROCAR PNEU DE UM CARRO Início se <o estepe está vazio> então chamar borracheiro senão levantar o carro desparafusar o 1o parafuso desparafusar o 2o parafuso desparafusar o 3o parafuso desparafusar o 4o parafuso remover a roda colocar o estepe parafusar o 1o parafuso parafusar o 2o parafuso parafusar o 3o parafuso parafusar o 4o parafuso abaixar o carro fim se Fim Estrutura Sequencial A repetição é inconveniente A repetição é inconveniente ALGORITMO PARA TROCAR PNEU DE UM CARRO Início se <o estepe está vazio> então chamar borracheiro senão levantar o carro enquanto <houver parafuso para desapertar> faça desparafusar a roda fim enquanto remover a roda colocar o estepe enquanto <houver parafuso para apertar> faça parafusar a roda fim do enquanto abaixar o carro fim se Fim Estrutura de Repetição ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início remova a lâmpada queimada coloque a nova lâmpada Fim ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início remova a lâmpada queimada coloque a nova lâmpada Fim O que é necessário para remover a lâmpada queimada? ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO • posicione a escada debaixo da lâmpada queimada • suba na escada até que a lâmpada possa ser alcançada • gire a lâmpada queimada no sentidoanti-horário até que se solte ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início remova a lâmpada queimada coloque a nova lâmpada Fim O que é necessário para colocar a lâmpada nova? ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO • escolha uma lâmpada da mesma potência da queimada • posicione a nova lâmpada no soquete • gire a lâmpada no sentido horário até que ela se firme • desça da escada ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim Diversos passos deste algoritmo implicam operações mais elaboradas que devem ser expressas explicitamente ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim enquanto <não alcançar a lâmpada> faça suba um degrau da escada fim enquanto ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim enquanto <a lâmpada não soltar> faça gire a lâmpada no sentido anti-horário fim enquanto ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim se <tiver lâmpada da mesma potência> então selecione a lâmpada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que se firme desça da escada senão desça da escada fim se ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim se <tiver lâmpada da mesma potência> então selecione a lâmpada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que se firme desça da escada senão desça da escada fim se ALGORITMO PARA TROCAR UMA LÂMPADA NO TETO Início posicione a escada debaixo da lâmpada queimada suba na escada até que a lâmpada possa ser alcançada gire a lâmpada queimada no sentido anti-horário até que se solte remova a lâmpada queimada escolha uma lâmpada da mesma potência da queimada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que ela se firme desça da escada Fim se <tiver lâmpada da mesma potência> então selecione a lâmpada posicione a nova lâmpada no soquete gire a lâmpada no sentido horário até que se firme desça da escada senão desça da escada fim se enquanto <a lâmpada não prender> faça gire a lâmpada no sentido horário fim enquanto A L G O R IT M O P A R A T R O C A R U M A L Â M P A D A N O T E T O Início posicione a escada debaixo da lâmpada queimada enquanto <não alcançar a lâmpada> faça suba um degrau da escada fim enquanto enquanto <a lâmpada não soltar> faça gire a lâmpada no sentido anti-horário fim enquanto remova a lâmpada queimada se <tiver lâmpada da mesma potência> então selecione a lâmpada posicione a nova lâmpada no soquete enquanto <a lâmpada não prender> faça gire a lâmpada no sentido horário fim enquanto desça da escada senão desça da escada fim se Fim Inicio Se <lâmpada não acender> Então Se <existir lâmpada nova> Então Desligar a chave geral Pegar uma escada Posicionar a escada embaixo da lâmpada queimada Pegar lâmpada nova Enquanto <não alcançar a lâmpada> faça Subir um degrau com a lâmpada nova Fim_Enquanto Segurar a lâmpada queimada Enquanto <lâmpada não sair do soquete> faça Rosquear a lâmpada para a esquerda Fim_Enquanto Tirar a lâmpada queimada Botar a lâmpada nova no soquete Enquanto<lâmpada não fixar> faça Rosquear para a direita Fim_Enquanto Descer a escada com a lâmpada queimada Ligar a chave geral Ligar o interruptor Se <não acender> Então chamar o eletricista Fim_Se Senão Comprar lâmpada nova Fim_Se Fim Algoritmos - Estruturas Sequencial Condicional Repetição condicionais (a repetição ocorre condicionada a uma condição lógica) incondicionais (têm um número pré-definido de repetições) Algoritmos - Estruturas Repetição Condicional – Condição testada no início da repetição Sintaxe Geral: Enquanto condição faça bloco de comandos Fim enquanto Características: • Testa a condição antes da execução do bloco. • Enquanto a condição for verdadeira, o bloco de comandos é executado. Assim, o bloco de comandos pode ser executado 0 ou mais vezes. • Pára a execução do bloco quando a condição se tornar falsa. Algoritmos - Estruturas Repetição Condicional – Condição testada no início da repetição Exemplo: Elabore um algoritmo para determinar o menor número fornecido de um conjunto de valores inteiros positivos dados. Considere que o número zero indica o encerramento do conjunto de dados de entrada. Algoritmos - Estruturas Repetição Condicional – Condição testada no final da repetição Sintaxe Geral: Repita bloco de comandos Até condição Características: • Testa a condição após da execução do bloco. • Enquanto a condição for verdadeira, o bloco de comandos é executado. Assim, o bloco de comandos é executado pelo menos uma vez. • Pára a execução do bloco quando a condição se tornar verdadeira (denominada de Condição de Parada). Algoritmos - Estruturas Repetição Condicional – Condição testada no final da repetição Exemplo: Repetir exemplo para condição testada no início. É possível? Elabore um algoritmo para determinar o menor número fornecido de um conjunto de valores inteiros positivos dados. Considere que o número zero indica o encerramento do conjunto de dados de entrada. Algoritmos - Estruturas Repetição Incondicional - N.º pré-definido de repetições Sintaxe Geral: Para variável de controle = valor inicial até valor final Faça bloco de comandos Fim para • Repete o bloco de comandos (valor final - valor-inicial + 1) vezes • Incrementa automaticamente a variável de controle cada vez que o bloco é executado (incremento “default” de 1 até alcançar o valor final) • Se o valor final definido for menor que o valor inicial, o laço de repetição não é executado nenhuma vez. • A variável de controle deve ser do tipo primitivo inteiro. • A variável usada como controle da estrutura não pode ser modificada dentro do bloco! Algoritmos - Estruturas Repetição Incondicional - N.º pré-definido de repetições Exemplo: Elabore um algoritmo para calcular o fatorial de N, onde N é um número inteiro (maior ou igual a zero). Considere que: Se N > 0 então N! = 1x 2 x 3 x .... x N N= 0 então N! = 1 Linguagem de Programação Conjunto de Instruções Fonte: http://wwwusers.rdc.puc-rio.br/rmano/ri1finst.html Exemplo de uma máquina hipotética Instrução Significado Operação Código Load Carrega no acumulador ACC op 0000 Store Salvar na memória op ACC 0001 Add Somar ACC ACC + op 0010 Sub Subtrair ACC ACC - op 0011 Mult Mutiplicar ACC ACC * op 0100 Div Dividir ACC ACC / op 0101 Jmp Desviar CI op 0110 Jz Desviar, se CC igual a 0 CI op, se ACC = 0 0111 Jnz Desviar se ACC não 0 CI op, se ACC != 0 1000 Read Ler entrada op entrada 1001 Print Imprimir saida op 1010 Stop Terminar 1100 Conjunto de Instruções Fonte: http://wwwusers.rdc.puc-rio.br/rmano/ri1finst.html Formato das Intruções Código de operação (OPCODE) Operando 1 (OP1) OP2 OP3... Código de Operação ou OPCODE • identifica a operação a ser realizada pelo processador • valor binário (código binário) identifica a operação a ser realizada. • código entrada no decodificador de instruções na unidade de controle • cada instrução deverá ter um código único que a identifique Operando(s) • fornecem os dados da instrução • valor binário sinaliza a localização do dado (ou é o próprio dado) que será manipulado (processado) pela instrução durante a operação • em geral, um operando identifica: • endereço de memória onde está contido o dado que será manipulado ou • endereço onde o resultado da operação será armazenado ou • um registrador (que conterá o dado propriamente dito ou um endereço de memória onde está armazenado o dado) • obs: existem instruções que não tem operando. Ex.: Instrução HALT (PARE) Conjunto de Instruções Exemplos ADD OP1 OP2 (OP1) (OP1) + (OP2) soma conteúdo de OP1 e OP2 e armazena o resultado em OP1 ADD OP1 OP2 OP3 (OP3) (OP1) + (OP2) soma conteúdo de OP1 e OP2 e armazena o resultado em OP3 ADD OP1 (ACC) (ACC) + (OP1) soma o conteúdo de OP1 e ACC e armazena em ACC Linguagem de Programação Processo de: • Edição • Pré-processamento • Tradução • Ligação • Carregamento • Execução Linguagem de Programação C Histórico Deduzida da linguagem B Dennis Ritchie no AT&T Bell Lab Estruturada, imperativa, procedural Originalmente implementada em um computador DEC PDP-11 em 1972 Tornou-se conhecida como a linguagem de desenvolvimento do SO UNIX Quase todos os SOs são escritos em C e/ou C++ Está disponível para a maioria dos computadores É independente de hardware Possível escrever programas portáveis para a maioria dos computadores Linguagem de Programação C Evolução No final dos anos 1970 evoluiu para o “C tradicional” Rápida expansão para vários tipos de computadores Levou a muitas variações da linguagem que, embora semelhantes, eram frequentemente incompatíveis Problema sério para escrita de programas portáveis Era necessária uma versão padrão de C!!! 1983 criado comitê técnico para produzir uma definição que não fosse ambígua, mas que fosse independente de máquina 1989 o padrão foi aprovado 1999 o padrão foi atualizado (chamado C99) Nem todos os compiladores C populares admitem C99 Linguagem de Programação C Programas em C módulos ou peças chamadas funções É possível programar todas as funções para formar um programa em C A maioria dos programadores de C aproveita as coleções de funções existentes na biblioteca-padrão de C Duas fases para aprender a programar em C Aprender a linguagem propriamente dita Aprender a utilizar as funções da biblioteca-padrão de C Ao programar em C, utiliza-se os seguintes blocos de montagem: Funções da biblioteca-padrão de C Funções que você mesmo criar Funções que outras pessoas criaram e tornaram disponíveis para você Linguagem de Programação C Usar funções da biblioteca-padrão de C em vez de escrever suas próprias versões equivalentes Melhora o desempenho dos programas Essas funções foram cuidadosamente escritas para serem executadas de modo eficaz Melhora a portabilidade do programa Essas funções estão incluídas em praticamente todas as implementações-padrão de C Linguagem de Programação C Boa prática de programação Importante clareza do programa Escreva seus programas em C de uma maneira simples e direta Não “force” a linguagem tentando usos estranhos Programadores experientes em C às vezes se orgulham de poder criar algum uso misterioso, contorcido e “enrolado” da linguagem Essa é uma prática ruim de programação Torna os programas: Mais difíceis de serem lidos Mais propensos a apresentar comportamentos estranhos Mais difíceis de testar e depurar Mais difíceis de serem adaptados a mudanças de requisitos Linguagem de Programação C /* Primeiro programa em C */ #include <stdio.h> /* função main inicia execução do programa */ int main( void ) { printf( “Bem-vindo a linguagem C!\n" ); return 0; /* indica que o programa terminou com sucesso */ } /* fim da função main */ Um programa simples: imprimindo uma linha de texto Bem-vindo a linguagem C! Linguagem de Programação C Sequências comuns de escape Sequência de escape Descrição \n Nova linha. Posiciona o cursor da tela no início da próxima linha. \t Tabulação horizontal. Move o cursor da tela para a próxima posição de tabulação \a Alerta. Faz soar o alarme do sistema. \\ Barra invertida. Insere um caractere de barra invertida em uma string. \” Aspas. Insere um caractere de aspas em uma string. Linguagem de Programação C Um programa simples: somando dois inteiros /* Programa de adição */ #include <stdio.h> /* função main inicia execução do programa */ int main( void ) { int inteiro1; /* primeiro número a ser informado pelo usuário */ int inteiro2; /* segundo número a ser informado pelo usuário */ int soma; /* variável em que a soma será armazenada */ printf( “Digite o primeiro inteiro\n" ); /* prompt */ scanf( "%d", &integer1 ); /* lê um inteiro */ printf( “Digite o segundo inteiro\n" ); /* prompt */ scanf( "%d", &integer2 ); /* lê um inteiro */ sum = integer1 + integer2; /* atribui o total à soma */ printf( “A soma eh %d\n", sum ); /* print soma */ return 0; /* indica que o programa foi concluído com sucesso */ } /* fim da função main */ Digite o primeiro inteiro 45 Digite o segundo inteiro 72 A soma eh 117 Linguagem de Programação C Tamanhos e valores dos tipos inteiros Tipo inteiro Tamanho Valor mínimo Valor máximo Signed char 8 -128 127 Short int 16 -32.768 32.767 Int 32 -2.147.483.648 2.147.483.647 Long int 32 -2.147.483.648 2.147.483.647 Long long int 64 -9.223.372.036.854.775.808 9.223.372.036.854.775.807 Unsigned char 8 0 255 Unsigned short int 16 0 65535 Unsigned int 32 0 4.294.967.295 Unsigned long int 32 0 4.294.967.295 Unsigned long long int 64 0 18.446.744.073.709.551.615 Valores adotados pelo compilador gcc para uma arquitetura de 32 bits e complemento-2 para representação de negativos. Quando a arquitetura-alvo é de 64 bits, o tamanho 64 é adotado para os tipos long int e unsigned long int Linguagem de Programação C Tamanhos e valores dos tipos ponto flutuante Valores usuais para uma arquitetura de 32 bits Tipo Sinal Expoente Mantissa Float 1 8 23 Double 1 11 52 Long double 1 64 63 Tipo Tamanho Menor valor Maior valor Float 32 1,17549 x 10-38 3,40282 x 10+38 Double 64 2,22507 x 10-308 1,79769 x 10+308 Long double 128 3,3621 x 10-4932 1,18973 x 10+4932 Linguagem de Programação C Operadores Aritméticos Operação em C Operador aritmético Expressão algébrica Expressão em C Adição + f + 7 f + 7 Subtração – p – c p – c Multiplicação * bm b * m Divisão / x/y ou xy x / y Módulo ou resto da divisão entre 2 inteiros % r mod s r % s Linguagem de Programação C Precedência de operadores aritméticos Operador(es) Operação(ões) Ordem de avaliação (precedência) ( ) Parênteses Avaliados em primeiro lugar. Se os parênteses forem aninhados, a expressão no par mais interno é a primeira a ser avaliada. Se houver vários pares de parênteses „no mesmo nível‟ (ou seja, não aninhados), eles serão avaliados da esquerda para a direita. * / % Multiplicação Divisão Módulo Avaliados em segundo lugar. Se houver vários, serão avaliados da esquerda para a direita. + – Adição Subtração Avaliados por último. Se houver vários, serão avaliados da esquerda para a direita. Linguagem de Programação C Operadores de igualdade e relacionais Operador de igualdade ou relacional na álgebra Operador de igualdade ou relacional em C Exemplo de condição em C Significado da condição em C Operadores de igualdade = == x == y x é igual a y != x != y x não é igual a y Operadores relacionais > > x > y x é maior que y < < x < y x é menor que y >= x >= y x é maior ou igual a y <= x <= y x é menor ou igual a y Linguagem de Programação C Precedência e associatividade Operadores Associatividade ( ) esquerda para direita * / % esquerda para direita + – esquerda para direita < <= > >= esquerda para direita == != esquerda para direita = direita para esquerda Linguagem de Programação C Se Então Senão if (nota >= 60) { printf(“Aprovado\n”); } /* fim do if */ else { printf(“Reprovado\n”); } /* fim do else */ if (nota >= 90) printf(“A\n”); else if (nota >= 80) printf(“B\n”); else if (nota >= 70) printf(“C\n”); else if (nota >= 60) printf(“D\n”); else printf(“E\n”); if (nota >= 90) printf(“A\n”); else if (nota >= 80) printf(“B\n”); else if (nota >= 70) printf(“C\n”); else if (nota >= 60) printf(“D\n”); else printf(“E\n”); if (nota >= 60) { printf(“Aprovado\n”); } /* fim do if */ else { printf(“Reprovado\n”); printf(“Voce precisa fazer esse curso novamente. \n”); } /* fim do else */ Linguagem de Programação C Switch if (opcao==1) printf (“A opcao escolhida foi 1!”); else if (opcao==2) printf (“A opcao escolhida foi 2!”); else if (opcao==3) printf (“A opcaoescolhida foi 3!”); else printf (“A opcao escolhida nao foi 1, nem 2, nem 3!”); switch (opcao) { case 1: printf (“A opcao escolhida foi 1!”); case 2: printf (“A opcao escolhida foi 2!”); case 3: printf (“A opcao escolhida foi 3!”); default: printf (“A opcao escolhida nao foi 1, nem 2, nem 3!”); } Linguagem de Programação C Enquanto produto = 3; while (produto <= 100) { produto = 3 * produto; } /* fim do while */ /* Programa de média da turma com repetição controlada por contador */ #include <stdio.h> /* função main inicia execução do programa */ int main( void ) { int contados; /* número da nota a digitar em seguida */ int nota; /* valor da nota */ int total; /* soma das notas inseridas pelo usuário */ int media; /* média das notas */ /* fase de inicialização */ total = 0; /* inicializa total */ counter = 1; /* inicializa contador do loop (laço) */ /* fase de processamento */ while ( contador <= 10 ) { /* loop 10 vezes */ printf( “Digite a nota: " ); /* prompt para inserção */ scanf( "%d", ¬a ); /* lê a nota do usuário */ total = total + nota; /* soma nota ao total */ contador = contador + 1; /* incrementa contador*/ } /* fim do while */ /* fase de término */ media = total/10; /* divisão de inteiros */ printf( “Media da turma eh %d\n", media ); /* exibe resultado */ return 0; /* indica que o programa foi concluído com sucesso */ } /* fim da função main */ Digite a nota: 98 Digite a nota: 76 Digite a nota: 71 Digite a nota: 87 Digite a nota: 83 Digite a nota: 90 Digite a nota: 57 Digite a nota: 79 Digite a nota: 82 Digite a nota: 94 Media da turma eh 81 Enquanto Enquanto /* Programa de média da turma com repetição controlada por sentinela */ #include <stdio.h> int main( void ) { int contador; /* número de notas digitadas */ int nota; /* valor da nota */ int total; /* soma das notas */ float media; /* númeo em ponto flutuante para a média */ /* fase de inicialização */ total = 0; /* inicializa total */ contador = 0; /* inicializa contador do loop */ /* fase de processamento */ /* recebe primeira nota do usuário */ printf( “Digite a nota, -1 no fim: " ); /* prompt para entrada */ scanf( "%d", &grade ); /* lê nota do usuário */ /* loop enquanto valor da sentinela não foi lido */ while ( nota != -1 ) { total = total + nota; /* soma nota ao total */ contador = contador + 1; /* incrementa contador */ /* recebe próxima nota do usuário */ printf( “Digite a nota, -1 para finalizar: " ); /* prompt para entrada */ scanf("%d", ¬a); /* lê próxima nota */ } /* fim do while */ /* fase de finalização */ /* se o usuário digitou pelo menos uma nota */ if ( contador != 0 ) { /* calcula média de todas as notas lidas */ media = ( float ) total / contador; /* evita truncar */ /* exibir média com dígitos de precisão */ printf( “Media da turma eh %.2f\n", media ); } /* fim do if */ else { /* se nenhuma nota foi informada, envia mensagem */ printf( “Nenhuma nota foi informada\n" ); } /* fim do else */ return 0; /* indica que o programa foi concluído com sucesso */ } /* fim da função main */ Digite a nota, -1 para finalizar: 75 Digite a nota, -1 para finalizar: 94 Digite a nota, -1 para finalizar: 97 Digite a nota, -1 para finalizar: 88 Digite a nota, -1 para finalizar: 70 Digite a nota, -1 para finalizar: 64 Digite a nota, -1 para finalizar: 83 Digite a nota, -1 para finalizar: 89 Digite a nota, -1 para finalizar: -1 Media da turma eh 82,50 Digite a nota, -1 para finalizar: -1 Nenhuma nota foi informada E se tirar o { ??? /* Análise de resultados de exame */ #include <stdio.h> /* função main inicia execução do programa */ int main( void ) { /* inicializa variáveis nas declarações */ int aprovados = 0; /* número de aprovações */ int reprovados = 0; /* número de reprovações */ int aluno = 1; /* contador de alunos */ int resultado; /* um resultado de exame */ /* processa 10 alunos usando loop controlado por contador */ while ( aluno <= 10 ) { /* pede entrada do usuário e l~e o valor digitado */ printf( “Forneca resultado ( 1=aprovado,2=reprovado ): " ); scanf( "%d", &resultado ); /* se resultado 1, incrementa aprovados */ if ( resultado == 1 ) { aprovados = aprovados + 1; } /* fim do if */ else { /* senão, incrementa reprovados */ reprovados = reprovados + 1; } /* fim do else */ aluno = aluno + 1; /* incrementa contador de alunos */ } /* fim do while */ /* fase de finalização; exibe número de aprovados e reprovados */ printf( “Aprovados %d\n", aprovados ); printf( “Reprovados %d\n", reprovados ); /* se mais de oito aprovados, imprime "Bônus ao instrutor!" */ if ( aprovados > 8 ) { printf( "Bonus ao instrutor!\n" ); } /* fim do if */ return 0; /* indica que o programa foi concluído com sucesso */ } /* fim da função main */ Enquanto Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 2 Forneca resultado (1=aprovado, 2=reprovado): 2 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 2 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 2 Aprovados 6 Reprovados 4 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 2 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Forneca resultado (1=aprovado, 2=reprovado): 1 Aprovados 9 Reprovados 1 Bonus ao instrutor! Para /* Repetição controlada por contador com a estrutura for */ #include <stdio.h> /* função main inicia a execução do programa */ int main( void ) { int contador; /* declara o contador */ /* inicialização, condição de repetição e incremento são todos incluídos no cabeçalho da estrutura for. */ for ( contador = 1; contador <= 10; contador++ ) { printf( "%d\n", contador ); } /* fim do for */ return 0; /* indica que o programa terminou com sucesso */ } /* fim da função main */ 1 2 3 4 5 6 7 8 9 10 Para /* Somatorio com for */ #include <stdio.h> /* função main inicia a execução do programa */ int main( void ) { int soma = 0; /* inicializa soma */ int numero; /* número a ser acrescido à soma */ for ( numero = 2; numero <= 100; numero += 2 ) { soma += numero; /* adiciona numero a soma */ } /* fim do for */ printf( "Soma eh %d\n", soma ); /* exibe soma */ return 0; /* indica que o programa terminou com sucesso */ } /* fim da função main */ A soma eh 2550 Repita... Até /* Usando a estrutura de repetição do/while */ #include <stdio.h> /* função main inicia a execução do programa */ int main( void ) { int contador = 1; /* inicializa contador */ do { printf( "%d ", contador ); /* exibe contador */ } while ( ++contador <= 10 ); /* fim de do...while */ return 0; /* indica que o programa terminou com sucesso */ } /* fim da função main */ 1 2 3 4 5 6 7 8 9 10 Break / Continue /* Usando o comando break em uma estrutura for */ #include <stdio.h> /* função main inicia a execução do programa */ int main( void ) { int x; /* contador */ /* loop por 10 vezes */ for ( x = 1; x <= 10; x++ ) { /* se x é 5, encerra loop */ if ( x == 5 ) { break; /* sai do loop somente se x eh 5 */ } /* fim do if */ printf( "%d ", x ); /* exibe valor de x */ } /* fim do for */ printf( "\nSaiu do loop em x == %d\n", x ); return 0; /* indica que o programa terminou com sucesso */ } /* fim da função main */ 1 2 3 4 Saiu do loop em x == 5 Break / Continue /* Usando o comando continue em uma estrutura for */ #include <stdio.h> /* função main inicia a execução doprograma */ int main( void ) { int x; /* contador */ /* loop por 10 vezes */ for ( x = 1; x <= 10; x++ ) { /* se x é 5, continua com a próxima iteração do loop */ if ( x == 5 ) { continue; /* salta código restante no corpo do loop */ } /* fim do if */ printf( "%d ", x ); /* exibe valor de x */ } /* fim do for */ printf( "\nUsou continue para pular a exeibicao do valor 5\n" ); return 0; /* indica que o programa terminou com sucesso */ } /* fim da função main */ 1 2 3 4 6 7 8 9 10 Usou continue para pular a exibição do valor 5 Operadores Lógicos • AND lógico && • OR lógico || • NOT lógico ! if (sexo == 1 && idade >= 65 ++idosoFeminino; if (mediaSemestre >= 90 || exameFinal >= 90) Printf (“Nota do aluno eh A\n”); if (!(nota == valorSentinela)) printf(“A proxima nota eh %f\n”, nota); if (nota != valorSentinela) printf(“A proxima nota eh %f\n”, nota); equivalente a: Linguagem de Programação C Operadores aritméticos de atribuição Operador de atribuição Exemplo de expressão Explicação Atribui Considere: int c = 3, d = 5, e = 4, f = 6, g = 12; += c += 7 c = c + 7 10 a c –= d –= 4 d = d – 4 1 a d *= e *= 5 e = e * 5 20 a e /= f /= 3 f = f / 3 2 a f %= g %= 9 g = g % 9 3 a g Linguagem de Programação C Operadores de incremento e decremento Operador Exemplo de expressão Explicação ++ ++a Incrementa a em 1, e então usa o novo valor de a na expressão em que a estiver. ++ a++ Usa o valor corrente de a na expressão em que a estiver, e então incrementa a em 1. – – – –b Decrementa b em 1, e então usa o novo valor de b na expressão em que b estiver. – – b– – Usa o valor corrente de b na expressão em que b estiver, e então incrementa b em 1. Linguagem de Programação C Operadores de incremento e decremento /* Pré-incrementando e pós-incrementando */ #include <stdio.h> /* função main inicia a execução do programa */ int main( void ) { int c; /* define variável */ /* demonstra pós-incremento */ c = 5; /* atribui 5 a c */ printf( "%d\n", c ); /* imprime 5 */ printf( "%d\n", c++ ); /* imprime 5 e depois pós-incrementa */ printf( "%d\n\n", c ); /* imprime 6 */ /* demonstra pré-incremento */ c = 5; /* atribui 5 a c */ printf( "%d\n", c ); /* imprime 5 */ printf( "%d\n", ++c ); /* pré-incrementa e depois imprime 6 */ printf( "%d\n", c ); /* imprime 6 */ return 0; /* indica que o programa foi concluído com sucesso */ } /* fim da função main */ 5 5 6 5 6 6 Linguagem de Programação C Precedência e associatividade dos operadores Operadores Associatividade Tipo ++ (pós-fixo) – – (pós-fixo) direita para esquerda Pós-fixo + – (tipo) ++ (prefixo) – – (prefixo) direita para esquerda Unário * / % esquerda para direita Multiplicativo + – esquerda para direita Aditivo < <= > >= esquerda para direita Relacional == != esquerda para direita Igualdade && esquerda para direita AND lógico || esquerda para direita OR lógico ?: direita para esquerda Condicional = += –= *= /= %= direita para esquerda Atribuição Funções Modularização Um problema complexo é melhor abordado se for dividido primeiramente em vários subproblemas Modularização Modularização Funções A implementação desses Módulos é feita através de SUBPROGRAMAS Procedimentos Funções As linguagens de programação têm à sua disposição várias funções pré-definidas: Exemplos em C: sqrt (X): raiz quadrada de X pow(X,Y): X elevado à potência Y (XY) sin (X): seno de X Identificador da Função Funções As Funções Pré Definidas podem ser usadas diretamente em expressões: Exemplo: H:= sqrt (A + sqr (Y) + 2 * sin (Y)) Funções Se houver necessidade o programador pode definir suas próprias FUNÇÕES Funções função NOME-DA-FUNÇÃO (parâmetro : declaração do tipo do parâmetro1, parâmetro 2: declaração do tipo do parâmetro2, parâmetro n: declaração do tipo do parâmetro n): declaração do tipo da saída da função declaração das variáveis utilizadas no corpo da função início da função corpo da função fim da função Linguagem Algoritmica Funções Características Retorna um único valor Na definição da função devem ser declarados: o tipo de todos os parâmetros o tipo do valor que a função retorna todas as variáveis utilizadas internamente no subprograma (variáveis locais) Para utilizar a função no programa principal basta colocar seu nome (identificador) e os parâmetros de entrada Funções Exemplo A Função fat deve ser criada Dados dois números N e K, calcular a Combinação CN,K = Se existisse uma função fat (X) que calculasse o fatorial de um dado X, o cálculo da Combinação ficaria: CNK fat (N) / (fat (K) * fat (N-K)) )!(! ! KNK N função FAT(X: tipo do parâmetro): tipo da função declaração das variáveis utilizadas na função início da função P 1 para I de 1 até X faça P P * I fim para FAT P fim da função Função Fatorial função FAT(X: tipo do parâmetro): tipo da função declaração das variáveis utilizadas na função início da função P 1 para I de 1 até X faça P P * I fim para FAT P fim da função Função Fatorial Declarações relativas às Variáveis da Função (LOCAIS) função FAT(X: tipo do parâmetro): tipo da função declaração das variáveis utilizadas na função início da função P 1 para I de 1 até X faça P P * I fim para FAT P fim da função Função Fatorial O número para o qual é calculado o fatorial entra como parâmetro NÃO PRECISA SER LIDO DENTRO DA FUNÇÃO função FAT(X: tipo do parâmetro): tipo da função declaração das variáveis utilizadas na função início da função P 1 para I de 1 até X faça P P * I fim para FAT P fim da função • O resultado do cálculo do fatorial deve ser atribuído ao NOME da função • O NOME da função só pode aparecer uma vez dentro do corpo da função (exceto para o caso de recursão) Função Fatorial Dados dois números N e K, calcular a Combinação: Função Fatorial CN,K = )!(! ! KNK N programa COMBINACAO declarações do programa definição da função FAT(X) inicio do programa principal ler (N) ler (K) C FAT(N) / (FAT(K) * FAT(N - K)) escrever C fim do programa principal função FAT(X: tipo do parâmetro): tipo da função declaração das variáveis utilizadas no subprograma início da função P 1 para I de 1 até X faça P P * I fim para FAT P fim da função Função Fatorialprograma COMBINACAO declarações do programa inicio do programa principal ler (N) ler (K) C FAT(N) / (FAT(K) * FAT(N - K)) escrever C fim do programa principal função FAT(X: tipo do parâmetro): tipo da função declaração das variáveis utilizadas no subprograma início da função P 1 para I de 1 até X faça P P * I fim para FAT P fim da função Função Fatorial Exemplo função FAT nome da função Funções Exemplo função FAT (X: inteiro) parâmetros da função tipos dos parâmetros Funções Exemplo função FAT(X: inteiro): inteiro valor de retorno da função Funções Exemplo função FAT(X: inteiro): inteiro declaração das variáveis utilizadas no subprograma Funções Exemplo função FAT(X: inteiro): inteiro declaração das variáveis utilizadas no subprograma início da função P 1 para I de 1 até X faça P P * I fim para FAT P fim da função Funções programa COMBINACAO declarações inicio do programa principal ler (N) ler (K) C FAT(N) / (FAT(K) * FAT(N - K)) escrever C fim do programa principal função FAT(X: declaração do tipo do parâmetro): declaração do tipo da função declaração das variáveis utilizadas no subprograma início da função P 1 para I de 1 até X faça P P * I fim para FAT P fim da função Função Fatorial FUNÇÃO PROGRAMA PRINCIPAL declaração da função chamada da função Funções em C Funções da Biblioteca Matemática printf(“%.2f”, sqrt(900.0)); printf(“%.2f”, sqrt(c1 + d * f)); c1 = 13.0; d = 3.0; f = 4.0; Os argumento (parâmetro) de função podem ser constantes, variáveis ou expressões #include <math.h> Funções da Biblioteca Matemática Função Descrição Exemplo sqrt(x) raiz quadrada de x sqrt(900.0) é 30,0 exp(x) função exponencial ex exp(1) é 2,718282 log(x) logaritmo natural de x (base e) log(2,718282) é 1,0 log10(x) logaritmo de x (base 10) log10(1,0) é 0,0 log10(100,0) é 2,0 fabs(x) valor absoluto de x fabs(-13,5) é 13,5 ceil(x) arredonda x ao menor inteiro não menor que x ceil(9,2) é 10,0 ceil(-9,8) é 9,0 floor(x) arredonda x ao maior inteiro não maior que x floor(9,2) é 9,0 floor(-9,8) é -10,0 pow(x,y) x elevado à potência y (xy) pow(2,7) é 128,0 pow(9,0.5) é 3,0 fmod(x,y) módulo (resto) de x/y como um número em ponto flutuante fmod(13,657, 2,333) é 1,992 sin(x) seno trigonométrico de x (x em radianos) sin(0,0) é 0,0 cos(x) cosseno trigonométrico de x (x em radianos) cos(0,0) é 1,0 tan(x) tangente trigonométrica de x (x em radianos) tan(0,0) é 0,0 #include <math.h> Observações Nos programas que contêm muitas funções, main normalmente é implementada como um grupo de chamadas para funções que realizam a maior parte do trabalho no programa Cada função deve ser limitada a realizar uma única tarefa bem-definida, e o nome dela deve expressar essa tarefa Facilita a abstração e promove a reutilização do software Se não puder escolher um nome curto que expresse o que a função faz, é possível que sua função esteja tentando realizar muitas tarefas diversas Normalmente, é melhor quebrar essa função em várias funções menores /* Criando e usando uma função definida pelo programador */ #include <stdio.h> int square( int y ); /* protótipo da função */ /* função main inicia a execução do programa */ int main( void ) { int x; /* contador */ /* loop 10 vezes e calcula e exibe quadrado de x a cada vez*/ for ( x = 1; x <= 10; x++ ) { printf( "%d ", square( x ) ); /* chamada da função */ } /* fim do for */ printf( "\n" ); return 0; /* indica conclusão bem-sucedida */ } /* fim do main */ /* definição de função square retorna quadrado do parâmetro */ int square( int y ) /* y é uma cópia do argumento à função */ { return y * y; /* returna o quadrado de y como um int */ } /* fim da função square */ 1 4 9 16 25 36 49 64 81 100 Definição de funções O protótipo da função, o cabeçalho da função e as chamadas de função devem combinar em número, tipo e ordem de argumentos e de parâmetros, e também no tipo do valor de retorno Definição de funções /* Achando o máximo de três inteiros */ #include <stdio.h> int maximum( int x, int y, int z ); /* protótipo da função */ /* função main inicia a execução do programa */ int main( void ) { int number1; /* primeiro inteiro */ int number2; /* segundo inteiro */ int number3; /* terceiro inteiro */ printf( “Digite tres inteiros: " ); scanf( "%d%d%d", &number1, &number2, &number3 ); /* number1, number2 and number3 são argumentos da chamada da função maximum */ printf( "Maximum is: %d\n", maximum( number1, number2, number3 ) ); return 0; /* indica conclusão bem-sucedida */ } /* fim do main */ /* Definição da função maximum */ /* x, y e z são parâmetros */ int maximum( int x, int y, int z ) { int max = x; /* assume que x é o maior */ if ( y > max ) { /* se y é maior que max, atribui y a max */ max = y; } /* fim do if */ if ( z > max ) { /* if z é maior que max, atribui z a max */ max = z; } /* fim do if */ return max; /* max é o maior valor */ } /* fim da função maximum */ Digite tres inteiros: 22 85 17 Maximo eh: 85 Digite tres inteiros: 85 22 17 Maximo eh: 85 Digite tres inteiros: 22 17 85 Maximo eh: 85 Pilha da chamada de funções e registros de ativação Pilha (estrutura de dados do tipo last-in, first-out – LIFO) Empilhar Desempilhar Quando um programa chama uma função, a função chamada precisa saber como retornar ao chamador o endereço de retorno da função chamadora é colocado na pilha de execução do programa (ou pilha de chamada de função) Várias chamadas de função os endereços de retorno sucessivos são empilhados na ordem “último a entrar, primeiro a sair” Cada função pode retornar à sua chamadora Pilha de execução do programa também contém: Endereço de retorno da função chamadora Memória para as variáveis locais usadas em cada chamada de função durante a execução do programa (registros de ativação ou quadros de pilha da chamada de função) Função é chamada seu registro de ativação é colocado na pilha de execução do programa Função retorna ao seu chamador seu registro de ativação é retirado da pilha, e suas variáveis locais não são mais conhecidas do programa Quantidade de memória em um computador é finita Se houver mais chamadas de função do que é possível armazenar nos registros de ativação da pilha de execução do programa ocorrerá o erro estouro de pilha (stack overflow) Pilha da chamada de funções e registros de ativação Cabeçalho Explicação <assert.h> Contém macros e informações que acrescentam diagnósticos que auxiliam a depuração do programa <ctype.h> Contém protótipos de função para funções que testam certas propriedades dos caracteres, e protótipos de função para funções que podem ser usadas para converter letras minúsculas em maiúsculas, e vice-versa <errno.h> Define macros que são úteis na comunicaçãode condições de erro <math.h> Contém protótipos de função para funções da biblioteca matemática <stdio.h> Contém protótipos de função para as funções da biblioteca-padrão de entrada/saída, e informações usadas por eles <stdlib.h> Contém protótipos de funções para conversões de números em texto e de texto em números, alocação de memória, números aleatórios e outras funções utilitárias <string.h> Contém protótipos de função de processamento de strings <time.h> Contém protótipos de função e tipos para manipulação de hora e data Cabeçalhos Contêm os protótipos de função para todas as funções em uma biblioteca, e defiñições de vários tipos de dados e constantes necessárias a essas funções Chamando funções por valor e por referência Duas maneiras de chamar funções Por valor É feita uma cópia do valor do argumento e passada para a função chamada Mudanças na cópia não afetam o valor original da variável na chamadora Evita efeitos colaterais (modificações de variável) acidentais Por refrência Chamador permite que a função chamada modifique o valor da variável original Em C, todas as chamadas são feitas por valor É possível simular a chamada por referência usando operadores de endereço e operadores de indireção Classe de armazenamento Identificadores são usados para nomes de variáveis Atributos das variáveis: Nome Tipo Tamanho Valor Identificadores também são usados para nomes de funções para nomes de funções definidas pelo usuário Em um programa, os identificadores têm outros atributos: Classe de armazenamento Duração do armazenamento Escopo Vinculação Classe de armazenamento Classe de armazenamento Determina duração de armazenamento (período durante o qual o identificador existe na memória) Alguns existem por pouco tempo, alguns são criados e destruídos repetidamente e outros existem por toda a execução de um programa Escopo Local em que um identificador pode ser referenciado em um programa Alguns podem ser referenciados por um programa; outros, apenas por partes de um programa Vinculação de um identificador Determinante em um programa de múltiplos arquivos-fonte Classe de armazenamento C oferece 4 classes de armazenamento: duração de armazenamento automático duração de armazenamento estático Criadas quando é iniciado o bloco em que estão definidas; elas existirão enquanto o bloco estiver ativo, e serão destruídas quando o bloco terminar a sua execução auto register extern static Existem a partir do momento em que um programa inicia sua execução Classe de armazenamento auto Declara explicitamente variáveis de duração de armazenamento automático auto double x, y; Variáveis locais automáticas (existem apenas no corpo da função em que foram declaradas) * As variáveis locais possuem duração de armazenamento automático como padrão (a palavra-chave auto raramente é usada) Meio de economizar memória! Armazenamento Automático Classe de armazenamento register Dados na versão da linguagem de máquina de um programa normalmente são carregados em registradores para cálculos e outros tipos de processamento register int contador = 1; É possível que o compilador ignore essa declaração (p.ex: pode não haver um número suficiente de registradores disponíveis para o compilador utilizar) Sugere que a variável inteira contador seja colocada em um dos registradores do computador e inicializada em 1 * Só pode ser usado com variáveis de duração de armazenamento automática Normalmente, declarações register são desnecessárias. Os compiladores otimizados de hoje são capazes de reconhecer as variáveis usadas com frequência, e podem decidir colocá-las nos registradores sem que uma declaração register seja necessária Armazenamento Automático Classe de armazenamento extern Armazenamento Estático static e Usadas nas declarações de identificadores para variáveis e funções de duração de armazenamento estático: Para variáveis estáticas, o armazenamento é alocado e inicializado uma vez, quando o programa é iniciado Para funções, o nome da função existe quando o programa inicia sua execução Classe de armazenamento extern Armazenamento Estático Dois tipos de identificadores com duração de armazenamento estático: Identificadores externos (variáveis globais e nomes de funções) São da classe de armazenamento extern, como padrão Variáveis globais são criadas a partir da colocação das declarações de variável fora de qualquer definição de função – Retêm seus valores durante toda a execução do programa As variáveis globais e funções podem ser referenciadas por qualquer função que siga suas declarações ou definições no arquivo – Motivo para que se use protótipos de função o protótipo de função é colocado no início do arquivo para tornar os nomes de suas funções conhecidos no restante do arquivo) Variáveis locais declaradas com o especificador de classe de armazenamento static static e Classe de armazenamento extern Armazenamento Estático static e Variáveis locais declaradas com a palavra-chave static são conhecidas também apenas na função em que são definidas No entanto, diferentemente das variáveis automáticas, variáveis locais static retêm seu valor quando a função termina Da próxima vez em que a função for chamada, a variável local static conterá o valor que ela tinha quando a função foi executada pela última vez * Todas as variáveis numéricas de duração de armazenamento estático são inicializadas em zero se não forem inicializadas explicitamente * Variáveis globais: • O uso deve ser evitado • Possibilidade de efeitos colaterais involuntários quando uma função que não precisa de acesso à variável, acidentalmente, ou intencionalmente, a modifica Regras de escopo Escopo de um identificador Parte do programa em que o identificador pode ser referenciado Ex: ao definir uma variável local em um bloco, ela só poderá ser referenciada após sua definição nesse bloco, ou em blocos aninhados dentro desse bloco Quatro escopos de identificador: Escopo de função Escopo de arquivo Escopo de bloco Escopo de protótipo de função Regras de escopo Escopo de Função Os labels (identificadores seguidos por um sinal de dois pontos, como start:) são os únicos – Podem ser usados em qualquer lugar na função em que aparecem, mas não podem ser referenciados fora do corpo da função – São usados na estrutura switch (como nos labels de case) e em comandos goto – São detalhes de implementação que as funções ocultam uma da outra Escopo de Arquivo Identificador declarado fora de qualquer função “Conhecido” (ou seja, acessível) em todas as funções, a partir do ponto em que é declarado até o final do arquivo Exemplos: – Todas as variáveis globais – Definições de função e protótipos de função colocados fora de uma função Regras de escopo Escopo de Bloco Identificadores definidos dentro de um bloco Termina na chave direita ( } ) do bloco Exemplos: Variáveis locais definidas no início de uma função Parâmetros de função, que são considerados variáveis locais pela função Variáveis locais declaradas static ainda possuem escopo de bloco, embora existam desde o momento em que o programa iniciou sua execução a duração do armazenamento não afeta o escopo de um identificador Escopo de Protótipo de Função Identificadores usados nalista de parâmetros de um protótipo de função Os protótipos de função não exigem nomes na lista de parâmetros – apenas os tipos são obrigatórios Se um nome for utilizado na lista de parâmetros de um prótótipo de função, o compilador desprezará esse nome Os identificadores usados em um protótipo de função podem ser reutilizados em qualquer lugar no programa sem causar ambiguidades /* Um exemplo de escopo */ #include <stdio.h> void useLocal( void ); /* protótipo de função */ void useStaticLocal( void ); /* protótipo de função */ void useGlobal( void ); /* protótipo de função */ int x = 1; /* variável global */ /* função main inicia a execução do programa */ int main( void ) { int x = 5; /* variável local para main */ printf("x local no escopo externo de main eh %d\n", x ); { /* inicia novo escopo */ int x = 7; /* variável local para novo escopo */ printf(“x local no escopo interno de main eh %d\n", x ); } /* fim do novo escopo */ printf( "x local no escopo externo de main eh %d\n", x ); (continua a funcao main ...) useLocal(); /* useLocal tem x local automática */ useStaticLocal(); /* useStaticLocal tem x local estática */ useGlobal(); /* useGlobal usa x global */ useLocal(); /* useLocal reinicializa x local automática */ useStaticLocal(); /* x local estática retém seu valor anterior */ useGlobal(); /* x global também retém seu valor */ printf( "\nx local em main eh %d\n", x ); return 0; /* indica conclusão bem-sucedida */ } /* fim do main */ /* useLocal reinicializa variável local x durante cada chamada */ void useLocal( void ) { int x = 25; /* inicializada cada vez que useLocal é chamada */ printf( "\nx local em useLocal eh %d após entrar em useLocal\n", x ); x++; printf( “x local em useLocal eh %d antes de sair de useLocal\n", x ); } /* fim da funcao useLocal */ (continua as funções...) /* useStaticLocal inicializa variável local estática x somente na primeira vez em que essa função é chamada; o valor de x é salvo entre as chamadas a essa função */ void useStaticLocal( void ) { /* inicializada apenas na primeira vez em que useStaticLocal é chamada */ static int x = 50; printf( "\nx estatica local eh %d na entrada de useStaticLocal\n", x ); x++; printf( “x estatica local eh %d na saida de useStaticLocal\n", x ); } /* fim da função useStaticLocal */ /* função useGlobal modifica variável global x durante cada chamada */ void useGlobal( void ) { printf( "\nx global eh %d na entrada de useGlobal\n", x ); x *= 10; printf( “x global eh %d na saida de useGlobal\n", x ); } /* fim da função useGlobal */ x local no escopo externo de main eh 5 x local no escopo interno de main eh 7 x local no escopo externo de main eh 5 x local em useLocal eh 25 após entrar em useLocal x local em useLocal eh 26 antes de sair de useLocal x local estatica eh 50 na entrada de useStaticLocal x local estatica eh 51 na saida de useStaticLocal x global eh 1 na entrada de useGlobal x global eh 10 na saida de useGlobal x local em useLocal eh 25 após entrar em useLocal x local em useLocal eh 26 antes de sair de useLocal x local estatica eh 51 na entrada de useStaticLocal x local estatica eh 52 na saida de useStaticLocal x global eh 10 na entrada de useGlobal x global eh 100 na saida de useGlobal x local em main eh 5 Recursão Funções recursivas Funções que chamam a si mesmas 5! 5 * 4! 4 * 3! 3 * 2! 2 * 1! 1 5! 5 * 4! 4 * 3! 3 * 2! 2 * 1! 1 1 é retornado 2! = 2 * 1 = 2 é retornado 3! = 3 * 2 = 6 é retornado 4! = 4 * 6 = 24 é retornado 5! = 5 * 24 = 120 é retornado Valor final = 120 Sequência de chamadas recursivas Valores retornados a partir de cada chamada recursiva Recursão Funções recursivas Funções que chamam a si mesmas Erros comuns Esquecer de retornar um valor de uma função recursiva quando isso é necessário Omitir o caso básico, ou escrever a etapa de recursão incorretamente, de modo que ela não convirja no caso básico, causará recursão infinita, o que, eventualmente, esgotará toda a memória – Problema semelhante ao de um loop infinito em uma solução iterativa (não recursiva) – A recursão infinita também pode ser causada por uma entrada não esperada Dica de desempenho Evite programas recursivos que resultam em uma “explosão” exponencial de chamadas! /* Fuñção fatorial recursiva */ #include <stdio.h> long factorial( long number ); /* protótipo de função */ /* função main inicia a execução do programa */ int main( void ) { int i; /* contador */ /* loop 11 vezes; durante cada iteração, calcula factorial( i ) e mostra o resultado */ for ( i = 0; i <= 10; i++ ) { printf( "%2d! = %ld\n", i, factorial( i ) ); } /* fim do for */ return 0; /* indica conclusão bem-sucedida */ } /* fim do main */ /* definição recursiva da função fatorial */ long factorial( long number ) { /* caso base */ if ( number <= 1 ) { return 1; } /* fim do if */ else { /* passo recursivo */ return ( number * factorial( number - 1 ) ); } /* fim do else */ } /* fim da função fatorial */ 0! = 1 1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720 7! = 5040 8! = 40320 9! = 362880 10! = 3628800 /* função recursiva de fibonacci */ #include <stdio.h> long fibonacci( long n ); /* protótipo de função */ /* função main inicia a execução do programa */ int main( void ) { long result; /* valor de fibonacci */ long number; /* número fornecido pelo usuário */ /* obtém inteiro do usuário */ printf( “Digite um inteiro: " ); scanf( "%ld", &number ); /* calcula valor de fibonacci para número informado pelo usuário */ result = fibonacci( number ); /* mostra resultado */ printf( "Fibonacci( %ld ) = %ld\n", number, result ); return 0; /* indica conclusão bem-sucedida */ } /* fim do main */ /* Definição recursiva da função fibonacci */ long fibonacci( long n ) { /* caso básico */ if ( n == 0 || n == 1 ) { return n; } /* fim do if */ else { /* etapa recursiva */ return fibonacci( n - 1 ) + fibonacci( n - 2 ); } /* fim do else */ } /* fim da função fibonacci */ Digite um inteiro: 0 Fibonacci(0) = 0 Digite um inteiro: 1 Fibonacci(1) = 1 Digite um inteiro: 2 Fibonacci(2) = 1 Digite um inteiro: 6 Fibonacci(6) = 8 Digite um inteiro: 10 Fibonacci(10) = 55 Gerando números de Fibonacci por meio de recursão Conjunto de chamadas recursivas para Fibonacci fibonacci (3) fibonacci (2) fibonacci (1) return + fibonacci (1) fibonacci (0) return + return 1 return 1 return 0 Recursão x Iteração Iteração Recursão Tanto a iteração quanto a recursão se baseiam em uma estrutura de controle Usa uma estrutura de repetição Usa uma estrutura de seleção Ambas envolvem repetição Usa explicitamente uma estrutura de repetição Consegue a repetição por meio das chamadas de função repetitivas Ambas envolvem teste de término Termina quando a condição de continuação do loop falha Termina quando um caso básico é reconhecido Podem ocorrer infinitamente Um
Compartilhar