Mudanças entre as edições de "PRG1-2014-1-Engenharia Programação 1 - Engenharia"
Linha 1 826: | Linha 1 826: | ||
#Implementar um programa que é uma variação do programa de sorteio e adivinhação dado em sala. O programa deve flexibilizar a variação da faixa 1 a 10, permitindo que o usuário a configure no início do programa (por exemplo, 1-100). Além disto, o programa deve mostrar o número de tentativas realizadas antes de mostrar a mensagem de Congratulations. | #Implementar um programa que é uma variação do programa de sorteio e adivinhação dado em sala. O programa deve flexibilizar a variação da faixa 1 a 10, permitindo que o usuário a configure no início do programa (por exemplo, 1-100). Além disto, o programa deve mostrar o número de tentativas realizadas antes de mostrar a mensagem de Congratulations. | ||
#Implementar uma variação do programa acima, onde o usuário também fornece no início uma margem de erro percentual para o acerto. Exemplo: suponha que a faixa de adivinhação é 1-100 e que o usuário forneça uma margem de erro de 10%. Suponha que o programa sorteie o número 30. Então serão considerados acertos quaisquer entradas entre 20 e 40. | #Implementar uma variação do programa acima, onde o usuário também fornece no início uma margem de erro percentual para o acerto. Exemplo: suponha que a faixa de adivinhação é 1-100 e que o usuário forneça uma margem de erro de 10%. Suponha que o programa sorteie o número 30. Então serão considerados acertos quaisquer entradas entre 20 e 40. | ||
+ | {{collapse bottom}} | ||
+ | |||
+ | == AULA 7 DIA 13/03/2014== | ||
+ | |||
+ | ===Objetivos=== | ||
+ | |||
+ | O aluno deverá ser capaz de: | ||
+ | |||
+ | *dividir problemas em subproblemas e utilizar subrotinas para organizar a solução. | ||
+ | *passar parâmetros em funções e retonar valores. | ||
+ | |||
+ | ===Quebrando um problema em subproblemas: SUBPROGRAMAS=== | ||
+ | |||
+ | PROBLEMA: Aprimorar o exemplo do controle de acesso para que, no caso de 3 tentativas de acesso seguidas, com senha errada, o sistema seja bloqueado. | ||
+ | |||
+ | *DADOS DE ENTRADA: SENHA /* variável que armazena a senha entrada pelo usuário ou administrador */ | ||
+ | *DADOS DE SAÍDA: mensagem de abertura da porta / usuário bloqueado*/ | ||
+ | *VARIÁVEIS INTERMEDIÁRIAS: CONT_ACESSO /* valor inicial zero - incrementada a cada senha inválida */ | ||
+ | |||
+ | [[imagem:FluxogramaControleAcessoComContador.jpg|border|850px]] | ||
+ | |||
+ | Note que a variável CONT_ACESSO é iniciada com zero e | ||
+ | incrementada a cada erro no fornecimento da senha. A | ||
+ | atribuição CONT_ACESSO = CONT_+ACESSO + 1 deve ser | ||
+ | interpretada da forma: acesse o valor de CONT_ACESSO e some 1 | ||
+ | a este valor. Coloque o resultado novamente em CONT_ACESSO | ||
+ | (o conteúdo anterior é sobrescrito!) | ||
+ | |||
+ | Neste procedimento pode ser observado que: | ||
+ | *começa a aparecer uma certa complexidade no fluxograma; | ||
+ | *Além disto, não ficou uma abordagem muito interessante, pois se for o administrador que erra a senha, ele pode bloquear o usuário; | ||
+ | *não existe forma de desbloquear a senha (zerar o contador), a não ser mudando a senha. | ||
+ | |||
+ | Em síntese, existem subproblemas adicionais a serem resolvidos. Como podemos resolvê-los sem deixar um fluxograma complexo? | ||
+ | |||
+ | Usaremos a caixa de processos pré-definidos que usaremos para invocar funções que resolvem determinado subproblema. | ||
+ | |||
+ | Inicialmente, vamos construir três subprogramas: | ||
+ | * Iniciar_Sistema(): inicia variáveis do sistema, colocando o sistema em um estado inicial conhecido; | ||
+ | * Tratar_Admin(): é o código que trata a funcionalidade associada ao administrador; | ||
+ | * Tratar_User(): é a funcionalidade que trata o usuário (procedimento de abrir porta, bloquear etc). | ||
+ | |||
+ | |||
+ | [[imagem:FluxogramaControleAcessoComSubprograma.jpg|850px]] | ||
+ | |||
+ | OBS: Note que foi usada uma variável auxiliar AUX que permite ajustar o valor | ||
+ | de número de acessos a ser mostrado no display. Note também que na caixa DISPLAY foi usado | ||
+ | uma string a ser impressa e a variável AUX cujo conteúdo deve ser impresso. Ambos separados | ||
+ | por vírgula. | ||
+ | |||
+ | ===PARÂMETROS E RETORNO DE VALORES EM SUBPROGRAMAS=== | ||
+ | |||
+ | Para tornar ainda mais interessante o uso de subprogramas, vamos ver o conceito de passagem de parâmetros e retorno de valores. | ||
+ | |||
+ | Quando chamamos (invocamos) um subprograma podemos passar valores (dados de entrada) para este subprograma. | ||
+ | Estes valores são passados através de variáveis especiais que chamamos de parâmetros. | ||
+ | |||
+ | Parâmetros podem ser passados por valor e por referência. Por valor é quando os dados a serem passados na invocação | ||
+ | do subprograma são copiados para uma variável do subprograma. | ||
+ | |||
+ | Os parâmetros são passados por referência quando o que é passado para o subprograma é simplesmente o endereço da variável | ||
+ | repassada na invocação do subprograma. | ||
+ | |||
+ | Não existe uma forma explícita de definir os parâmetros em um fluxograma. Deve-se realizar um comentário antes ou ao lado do mesmo especificando o tipo e como será tratado o parâmetro. | ||
+ | |||
+ | EXEMPLO: Seja elaborar um fluxograma correspondente a uma subprograma que deve calcular o fatorial de um número inteiro passado como parâmetro. O subprograma deve retornar o valor calculado. | ||
+ | |||
+ | A função fatorial é definida por: | ||
+ | |||
+ | :<math>n!=\prod_{k=1}^n k\qquad\forall n\in\mathbb{N}</math> | ||
+ | |||
+ | |||
+ | [[imagem:FluxogramaFatorial.jpg|border|650px]] | ||
+ | |||
+ | Neste fluxograma, o subprograma denominado ''CalcFatorial'' recebe um valor no parâmetro N (implicitamente inteiro) e retorna o valor calculado do fatorial. | ||
+ | |||
+ | O fluxograma principal invoca duas vezes o subrograma. O retorno é armazenado nas variáveis NUM1 e NUm3. | ||
+ | |||
+ | Quando um subprograma retorna um valor, ele é chamado de função. Para manter coerência com o C chamaremos | ||
+ | qualquer subrprograma de função (independente de retornar valor). | ||
+ | |||
+ | |||
+ | ===Exemplo de Função usando pseudo-código=== | ||
+ | |||
+ | Seja uma função que retorna a média de 5 números reais passados como parâmetros: | ||
+ | |||
+ | <code> | ||
+ | real FUNCAO(real num1, real num2, real num3, real num 4, real num5) | ||
+ | VARIAVEIS | ||
+ | media: real | ||
+ | INICIO | ||
+ | media = (num1+num2+num3+num4+num5) /5 | ||
+ | RETORNAR media | ||
+ | FIM | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===EXERCÍCIOS=== | ||
+ | |||
+ | ''EXERCÍCIO 1'': Implementar uma função (subprograma), usando fluxograma, que recebe dois números inteiros como parâmetro. A função retorna 1 se os números forem iguais, 0 se o primeiro número maior que o segundo e -1 se o segundo for maior que o primeiro. | ||
+ | Mostre um exemplo de uso a partir de um fluxograma principal. | ||
+ | |||
+ | ''EXERCÍCIO 2'': Usando a formula de Heron, implemente na forma de pseudo-código uma função que recebe três números reais (lados de um triângulo) e retorne o valor da área do mesmo. | ||
+ | |||
+ | ''EXERCÍCIO 3'': Implementar uma função (subprograma), usando fluxograma, para computar o valor da PG, dados como parâmetros ''s'' e ''q'', onde "s" é o número inicial e "q" a razão da progressão. A função deve retornar um número real que é o valor da PG. | ||
+ | |||
+ | Obs: Para PG tem-se: | ||
+ | |||
+ | :<math> a_1 = s </math> | ||
+ | :<math> a_n = q\times a_{n-1} </math> ou | ||
+ | :<math>a_n=a_1.q^{n-1}\,\!</math> | ||
+ | |||
+ | ''EXERCÍCIO 4:'' Modificar o sistema de controle de acesso para incluir a inserção de nome de usuário (USERID) e senha (SENHA). Prever a existência de dois usuários (USERID_1, USERID_2, SENHA_1, SENHA_2). O admin poderá ser identificado pelo nome ADMIN. Prever bloqueio por usuário (duas variáveis contadores). | ||
+ | Sugestão: criar funcões separadas para tratamento de cada usuário. Em breve veremos como podemos contornar esta duplicação através da parametrização de funções/subprogramas. | ||
+ | |||
+ | ===Funções no C === | ||
+ | |||
+ | ====Chamando funções ==== | ||
+ | |||
+ | Um programa em C basicamente é um conjunto de funções. | ||
+ | Uma função pode ser vista como um subprograma para o qual podemos repassar | ||
+ | dados de entrada através de parâmetros e receber os resultados através | ||
+ | do retorno da função. | ||
+ | |||
+ | Normalmente, um programa bem comportado em C possui pelo menos uma função: a ''função main()''. Esta função | ||
+ | é chamada no início da execução do programa. A primeira instrução da função main() é a primeira instrução | ||
+ | executada pelo programa (pelo menos do ponto de vista do programador). Da mesma forma, a última instrução | ||
+ | desta função é a última instrução a ser chamada. | ||
+ | |||
+ | Um programa normalmente vai apresentar um conjunto de funções. Por exemplo: | ||
+ | <syntaxhighlight lang=c > | ||
+ | #include <stdio.h> | ||
+ | |||
+ | func4() | ||
+ | { | ||
+ | printf("Esta é a função func4()\n"); | ||
+ | } | ||
+ | |||
+ | func3() | ||
+ | { | ||
+ | printf("Esta é a função func3()\n"); | ||
+ | func4(); | ||
+ | } | ||
+ | |||
+ | func2() | ||
+ | { | ||
+ | printf("Esta é a função func2()\n"); | ||
+ | } | ||
+ | |||
+ | func1() | ||
+ | { | ||
+ | printf("Esta é a função func1()\n"); | ||
+ | func2(); | ||
+ | func3(); | ||
+ | } | ||
+ | |||
+ | main() | ||
+ | { | ||
+ | printf("Esta é a primeira instrução da função main()\n"); | ||
+ | func1(); | ||
+ | printf("Esta é a última instrução da função main()\n"); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | A sequência de chamada de funções pode ser ilustrada da forma: | ||
+ | |||
+ | [[imagem:FuncChamadaFuncoes.png|600px]] | ||
+ | |||
+ | EXERCÍCIO: Compile e execute o programa acima. Verifique a ordem de impressão das mensagens e compare com as chamadas das funções. | ||
+ | |||
+ | NOTA: Uma função pode ser chamada várias vezes no programa. | ||
+ | É O REAPROVEITAMENTO DE CÓDIGO... | ||
+ | |||
+ | ====Passando parâmetros e recebendo valores de retorno==== | ||
+ | |||
+ | Uma função normalmente resolve um determinado problema para um determinado conjunto de dados e produz uma saída. Estes dados podem ser passados como parâmetros e a saída pode ser retornada pela função. | ||
+ | |||
+ | Exemplo: Uma função ''media_nums''() que retorna a média de 3 números reais passados como parâmetros | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | #include <stdio.h> | ||
+ | |||
+ | float media_nums(float num1, float num2, float num3) | ||
+ | { | ||
+ | float media_local; | ||
+ | |||
+ | media_local = (num1 + num2 + num3)/3; | ||
+ | return media_local; | ||
+ | } | ||
+ | |||
+ | main() | ||
+ | { | ||
+ | float media, aux1, aux2, aux3; | ||
+ | |||
+ | printf("\nEntre com numero 1: "); | ||
+ | scanf ("%f",&aux1); | ||
+ | |||
+ | printf("\nEntre com numero 2: "); | ||
+ | scanf ("%f",&aux2); | ||
+ | |||
+ | printf("\nEntre com numero 3: "); | ||
+ | scanf ("%f",&aux3); | ||
+ | |||
+ | media = media_nums(aux1, aux2, aux3); | ||
+ | printf ("\nmedia dos 3 numeros é %f\n", media); | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | Deve ser observado que: | ||
+ | *após o nome da função, entre parênteses, são fornecidos os três parâmetros com os seus respectivos ''tipos''. Os valores (conteúdos das variáveis) ''aux1'', ''aux2'' e ''aux3'' são copiados para as variáveis ''num1'', ''num2'' e ''num3'' da função ''media_nums()''. | ||
+ | *a função ''media_nums()'' retorna um valor do tipo ''float'' (informado antes do nome da função) que é o valor da variável ''media_local''. Este valor é copiado para a variável media da função ''main()'' | ||
+ | *as variáveis ''num1'', ''num2'' e ''num3'' bem como a variável media_local possuem escopo LOCAL, ou seja, são "vistas" somente pela função ''media_nums()''; | ||
+ | *as variáveis ''media'', ''aux1'', ''aux2'' e ''aux3'' também possuem escopo LOCAL, ou seja são "vistas" somente pela função ''main()''; | ||
+ | |||
+ | NOTE que o formato de declaração de uma função é | ||
+ | |||
+ | tipo_retorno nome_funcao( lista_de_parametros ) | ||
+ | { | ||
+ | declaracao_variaveis_locais | ||
+ | |||
+ | instruções | ||
+ | } | ||
+ | |||
+ | Por enquanto, assumiremos que variáveis devem ser somente declaradas no início da função. Existem situações que poderemos relaxar esta afirmação. | ||
+ | |||
+ | ====Um pouco mais sobre parâmetros==== | ||
+ | |||
+ | O termo ''argumento'' ou ''parâmetro real'' (atual) é usado para referenciar os valores que estão sendo passados na CHAMADA da função. Os ''parâmetros formais'' referem-se aos parâmetros listados na função. É comum, no entanto, usar os termos argumentos e parâmetros como sinônimos e identificados pelo contexto em que estão sendo usados. | ||
+ | |||
+ | A passagem de parâmetros POR VALOR diz respeito a copiar o valor do argumento na CHAMADA da função para a variável associada ao parâmetro na função. Mais tarde falaremos na passagem de parâmetro POR REFERÊNCIA. Por ora, usaremos a passagem | ||
+ | POR VALOR. | ||
+ | |||
+ | Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis. | ||
+ | Eles podem ser uma expressão qualquer (uma expressão SEMPRE resulta em um VALOR). | ||
+ | |||
+ | Exemplo de chamadas para a função ''media_nums()'': | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | |||
+ | main() | ||
+ | { | ||
+ | float media, x,y,z; | ||
+ | |||
+ | x = 5.7; | ||
+ | y = 9.8; | ||
+ | |||
+ | /* exemplo de chamada 1 */ | ||
+ | media = media_nums(4.8,x,y*3); | ||
+ | |||
+ | /* exemplo de chamada 2 */ | ||
+ | media = media_nums (x+y,y*y+5,(x+y)/2); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Deve ser observado que: | ||
+ | * na chamada 1 do exemplo, os parâmetros são uma CONSTANTE, o valor de x, e o valor de y*3. Note que o compilador deve gerar código para resolver estas expressões antes de INVOCAR a função!. | ||
+ | * na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA. | ||
+ | |||
+ | ===Variáveis GLOBAIS e variáveis LOCAIS === | ||
+ | |||
+ | Se variáveis são declaradas dentro de uma função, então a visbilidade (ESCOPO) destas variáveis é LOCAL. Nenhuma outra função tem acesso a estas variáveis. | ||
+ | |||
+ | Uma variável pode ser GLOBAL, ou seja, declarada FORA das funções. Neste caso a variável é VISTA por todas as funções. Seja o exemplo anterior modiificado: | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | #include <stdio.h> | ||
+ | |||
+ | float media; /* Variável GLOBAL */ | ||
+ | |||
+ | void media_nums(float num1, float num2, float num3) | ||
+ | { | ||
+ | media = (num1 + num2 + num3)/3; | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | main() | ||
+ | { | ||
+ | float aux1, aux2, aux3; /* Variáveis LOCAIS */ | ||
+ | |||
+ | printf("\nEntre com numero 1: "); | ||
+ | scanf ("%f",&aux1); | ||
+ | |||
+ | printf("\nEntre com numero 2: "); | ||
+ | scanf ("%f",&aux2); | ||
+ | |||
+ | printf("\nEntre com numero 3: "); | ||
+ | scanf ("%f",&aux3); | ||
+ | |||
+ | media_nums(aux1, aux2, aux3); | ||
+ | printf ("\nmedia dos 3 numeros é %f\n", media); | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | Neste exemplo, a variável ''media'' é declarada como GLOBAL. Ela é MODIFICADA diretamente pela função ''media_nums()'' e impressa pela função ''main()'' | ||
+ | |||
+ | NOTE que como a função ''media_nums()'' não retorna valor então declaramos | ||
+ | seu tipo de retorno como ''void'' que significa aqui NADA ou VAZIO. | ||
+ | |||
+ | NOTE também que MESMO que a função retorne um valor, não é obrigatório colocá-la | ||
+ | no lado direito do sinal de atribuição. | ||
+ | |||
+ | Na realidade, uma função pode ser chamada dentro de qualquer expressão. Por exemplo, | ||
+ | para o caso em que a função ''media_nums()'' retorna um valor, ela poderia ser usada como: | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | #include <stdio.h> | ||
+ | |||
+ | float media_nums(float num1, float num2, float num3) | ||
+ | { | ||
+ | float media_local; | ||
+ | |||
+ | media_local = (num1 + num2 + num3)/3; | ||
+ | return media_local; | ||
+ | } | ||
+ | |||
+ | main() | ||
+ | { | ||
+ | float media, aux1, aux2, aux3; | ||
+ | printf("\nEntre com numero 1: "); | ||
+ | scanf ("%f",&aux1);). | ||
+ | |||
+ | printf("\nEntre com numero 2: "); | ||
+ | scanf ("%f",&aux2); | ||
+ | |||
+ | printf("\nEntre com numero 3: "); | ||
+ | scanf ("%f",&aux3); | ||
+ | |||
+ | media = media_nums(aux1, aux2, aux3); | ||
+ | printf ("\nmedia dos 3 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2, aux3)); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== Nome de variáveis ==== | ||
+ | |||
+ | Um nome de variável pode conter letras, dígitos e o ''underscore''(sublinhado). Ela DEVE iniciar com um ''underscore'' ou uma letra. Letras maúsculas e minúsculas podem ser usadas e são distinguidas (o C é CASE SENSITIVE | ||
+ | |||
+ | Variáveis LOCAIS e GLOBAIS podem ter o mesmo nome. A variável LOCAL terá preferência no uso. | ||
+ | |||
+ | Exercício: Execute o programa abaixo e verifique as saídas. | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | #include <stdio.h> | ||
+ | |||
+ | int i=1; /* GLOBAL */ | ||
+ | |||
+ | func() | ||
+ | { | ||
+ | int i=100; /* LOCAL */ | ||
+ | i=i+1; /* incrementa LOCAL */ | ||
+ | printf( "Valor de i = %d na função func()\n", i ); | ||
+ | } | ||
+ | |||
+ | main() | ||
+ | { | ||
+ | i=i+1; /* incrementa GLOBAL */ | ||
+ | func(); | ||
+ | printf( "Valor de i = %d \n", i ); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | NOTA: não é recomendado o uso de variáveis com o mesmo nome. | ||
+ | |||
+ | ====Iniciando variáveis na declaração==== | ||
+ | |||
+ | Tanto as variáveis LOCAIS como as GLOBAIS podem ser inicializadas na declaração. | ||
+ | |||
+ | Exemplo: | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | |||
+ | int alfa=1; | ||
+ | |||
+ | main() | ||
+ | { | ||
+ | float beta=1.5; | ||
+ | |||
+ | printf("Valor de alfa = %d e valor de beta = %f\n", alfa, beta); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | NOTA: variáveis LOCAIS não são iniciadas automaticamente: cabe ao programador iniciá-la corretamente. | ||
+ | |||
+ | NOTA: variáveis GLOBAIS são iniciadas automaticamente com zero. | ||
+ | Mas mantenha-se informado sobre o sistema que está trabalhando... | ||
+ | Em sistemas embarcados pode não ser verdade! | ||
+ | |||
+ | ====Um pouco mais sobre parâmetros==== | ||
+ | |||
+ | O termo ''argumento'' ou ''parâmetro real'' (atual) é usado para referenciar os valores que estão sendo passados na CHAMADA da função. Os ''parâmetros formais'' referem-se aos parâmetros listados na função. É comum, no entanto, usar os termos argumentos e parâmetros como sinônimos e identificados pelo contexto em que estão sendo usados. | ||
+ | |||
+ | A passagem de parâmetros POR VALOR diz respeito a copiar o valor do argumento na CHAMADA da função para a variável associada ao parâmetro na função. Mais tarde falaremos na passagem de parâmetro POR REFERÊNCIA. Por ora, usaremos a passagem | ||
+ | POR VALOR. | ||
+ | |||
+ | Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis. | ||
+ | Eles podem ser uma expressão qualquer (uma expressão SEMPRE resulta em um VALOR). | ||
+ | |||
+ | Exemplo de chamadas para a função ''media_nums()'': | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | |||
+ | main() | ||
+ | { | ||
+ | float media, x,y,z; | ||
+ | |||
+ | x = 5.7; | ||
+ | y = 9.8; | ||
+ | |||
+ | /* exemplo de chamada 1 */ | ||
+ | media = media_nums(4.8,x,y*3); | ||
+ | |||
+ | /* exemplo de chamada 2 */ | ||
+ | media = media_nums (x+y,y*y+5,(x+y)/2); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Deve ser observado que: | ||
+ | * na chamada 1 do exemplo, os parâmetros são uma CONSTANTE, o valor de x, e o valor de y*3. Note que o compilador deve gerar código para resolver estas expressões antes de INVOCAR a função!. | ||
+ | * na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA. | ||
+ | |||
{{collapse bottom}} | {{collapse bottom}} |
Edição das 13h46min de 13 de março de 2014
PRG1 - PROGRAMAÇÃO I
DADOS DA DISCIPLINA
CARGA HORÁRIA
TOTAL: 72 HORAS (4 HORAS/SEMANA)
TEÓRICA: 36 HORAS
LABORATÓRIO: 36 HORAS
DIAS COM AULA: 36 (18 semanas)
AVALIAÇÂO
Avaliações Semanais
Toda semana nas quinta feiras (aproximadamente 16 avaliações) - conceito se possível na hora
- meses de avaliação (março a junho)
- a última avaliação do mês terá caráter de recuperação
- não será permitida a consulta na avaliação
PROJETO FINAL
- grupos com 3 alunos;
- avaliação individual.
RECUPERAÇÃO FiNAL
- Ficará para recuperação o aluno que não conseguiu obter o conceito mínimo para passar em pelo menos uma das etapas avaliadas (mês) OU não obteve o sucesso no PROJETO FINAL
- última aula do semestre
- recuperação toda matéria
PRÉ REQUISITOS: LÓGICA
EMENTA
Introdução a lógica de programação e algoritmos. Constantes, variáveis e tipos de dados. Operadores aritméticos, relacionais e lógicos. Concepção de fluxograma e pseudocódigo. Estruturas de decisão e estruturas de repetição. Introdução a linguagem de programação c. Vetores de caracteres e multidimensionais. Ponteiros e aritmética de ponteiros. Funções: chamada por valor e por referência. Chamada recursiva de funções. Tipos de dados compostos. Operação com arquivos textos e binários.
CRONOGRAMA DE AULAS
Aula | Data | Horas | Conteúdo | Recursos | |
---|---|---|---|---|---|
1 | 13/2 | 2 | Aula introdução a lógica de programa. Conceito de algoritmos. Representação de algoritmos. Fluxograma. Variáveis e constantes. Expressões com operadores aritméticos e de atribuição. | ||
2 | 14/2 | 2 | Estruturas de decisão. Expressões com operadores lógicos e relacionais. | ||
3 | 20/2 | 2 | Introdução a programação C. Declaração de variáveis inteiras, reais e char no C. Uso do compilador gcc. Estruturas de decisçao com if e i eles. Expressões com operadores aritméticos, lógicos e relacionais. Operador de atribuição. | ||
4 | 21/2 | 2 | Lógica de programação: estruturas de repetição usando fluxogramas | ||
5 | 27/2 | 2 | Estruturas de repetição com a linguagem C: while, do while, for, goto. Uso do break e do continue. Uso do gdb em linha de comando. | ||
6 | 28/2 | 2 | Exercícios de Fixação | ||
7 | 6/3 | 2 | Estruturas de decisão. Comando switch. Outros comandos. Precedência de operadores no C. | ||
8 | 7/3 | 2 | Exercícios de Fixação. | ||
9 | 13/3 | 2 | Lógica de programação: quebrando problemas em subproblemas. Uso de subrotinas. Funções no C. Passagem de parâmetro e retorno de valor. AVALIAÇÂO 1 | ||
10 | 14/3 | 2 | Conceito de vetores. Vetores no C | ||
11 | 20/3 | 2 | Exercícios de vetores. AVALIAÇÂO 2 | ||
12 | 21/3 | 2 | Strings no C. Processamento de Strings. Exercícios | ||
13 | 27/3 | 2 | Strings no C. Processamento de Strings. AVALIAÇÂO 3 | ||
14 | 28/3 | 2 | Strings no C. Processamento de Strings. Exercícios | ||
15 | 3/4 | 2 | Exercícios de Fixação; AVALIAÇÂO 4 | ||
16 | 4/4 | 2 | RECUPERAÇÃO I | ||
17 | 10/4 | 2 | Operação com Matrizes no C | ||
18 | 11/4 | 2 | Exercícios com matrizes. AVALIAÇÃO 5 | ||
19 | 17/4 | 2 | Estruturas | ||
20 | 24/4 | 2 | Exercícios. AVALIAÇÂO 6 | ||
21 | 25/4 | 2 | Estruturas e vetores (Tabelas com estruturas). Typedef | ||
22 | 8/5 | 2 | Exercícios. AVALIAÇÃO 7 | ||
23 | 9/5 | 2 | RECUPERAÇÃO II | ||
24 | 15/5 | 2 | Tópicos adicionais: diretivas de préprocessamento. Compilação condicional; | ||
25 | 16/5 | 2 | Ponteiros – parte 1 | ||
26 | 22/5 | 2 | Exercícios. AVALIAÇÃO 8 | ||
27 | 23/5 | 2 | Ponteiros – parte 2 | ||
28 | 29/5 | 2 | Exercícios. AVALIAÇÃO 9 | ||
29 | 30/5 | 2 | Uso do make. Apresentação do Projeto Final. | ||
30 | 5/6 | 2 | Operação com arquivos – parte 1 | ||
31 | 6/6 | 2 | Exercícios. AVALIAÇÃO 10 | ||
32 | 12/6 | 2 | Operação com arquivos – parte 2 | ||
33 | 13/6 | 2 | Exercícios. AVALIAÇÂO 11 | ||
34 | 26/6 | 2 | RECUPERAÇÃO III | ||
35 | 27/6 | 2 | Projeto Final – Avaliação | ||
36 | 3/7 | 2 | Aula de Recuperação | ||
37 | 4/7 | 2 | Aula de Recuperação | ||
38 | 10/7 | 2 | Aula de Recuperação | ||
39 | 11/7 | 2 | RECUPERAÇÂO FINAL | ||
40 | / | ||||
TOTAL | 78 |
Bibliografia Básica
- SCHILDT, Herbert. C Completo e Total - 3.ed. [S.l.]: Makron, 1997. 830p. ISBN 978-8534605953
Referências Complementares
- Apostila adotada: Curso de Linguagem C - Engenharia Elétrica - UFMG
AULAS
AULA 1 DIA 13/02/2014 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
AULA 1 DIA 13/03/2014Como fazer um churrascoVamos observar atentamente este vídeo para iniciarmos o nosso curso de programação: EmbedVideo received the bad id "U0xSYIXE9vo#!" for the service "youtube". O que tem o churrasco com a nossa aula?? Trata-se de uma sequência de passos para execução de um objetivo. EXERCÍCIO: Na forma textual, descrever as etapas para fazer um bom churrasco. O que é um algoritmoUm algoritmo pode ser visto como uma sequência de instruções ou operações que resolvem um dado problema. A receita de um bom churrasco corresponde a um algoritmo. Como representar um algoritmo ?Uma forma é representar na forma textual ordenada: 1.Comprar a carne 2.Colocar carvão na churrasqueira 3.Acender o carvão 4.Cortar a carne (picanha) 5.Espetar a carne 6.Salgar a carne 7.Colocar a carne na churrasqueira 8.Aguardar a carne ficar no ponto desejado 9.Bater a carne 10.Servir a carne Outras formas são mais apropriadas para o uso no meio computacional:
A PENSAR: É possível mudar a ordem das instruções? É possível paralelizar algumas instruções?
E para quem são os algoritmos?Uma receita de bolo é apropriada para ser executada por um ser humano. Um procedimento de como trocar um pneu também. Mas muitas vezes queremos que o algoritmo seja executado por uma máquina! O computador é perfeito para isto! Neste curso vamos nos concentrar no desenvolvimento de algoritmos simples, desde a sua concepção até a sua implementação através de uma LINGUAGEM DE PROGRAMAÇÃO - a linguagem C , por exemplo. Um PROGRAMA implementa um algoritmo. É o algoritmo materializado na forma de uma sequência de instruções. Neste sentido, vamos entender minimamente o funcionamento de um computador (próxima aula) A Descrição de Algoritmos usando FluxogramasUm fluxograma é uma linguagem semi-gráfica que pode ser utilizada para descrição de algoritmos. Exemplo: O algoritmo de cálculo da média de dois números: Pontos fortes:
Ponto fraco:
Observe no exemplo anterior que nada é dito sobre as variáveis NUM1, NUM2 e MEDIA. Símbolos de um FluxogramaTeste de MesaConstantes, VariáveisAlgoritmos operam sobre dados. O que podem ser estes dados? Variáveis e Constantes No exemplo anterior podemos identificar três variáveis NUM1, NUM2 e MEDIA Também podemos identificar uma CONSTANTE. O número 2.
Ex: NUM1 = 5.5 /* NUM1 é uma variável real */
Ex: RES = TRUE /* RES é uma variável booleana */
Ex: LETRA = 'A'
Ex: FRASE = "ALO MUNDO" E como estas variáveis armazenam os dados?? Depende da linguagem usada. Vamos passar uma primeira noção do C ExpressõesExpressões sentenças que relacionam variáveis e constantes através de operadores matemáticos e que RESULTAM em um valor. A instrução do algoritmo: MEDIA = (NUM1 + NUM2) / 2 será considerada como uma expressão, que usa os operadores '+', '/' e '=' O operador '=' é um OPERADOR DE ATRIBUIÇÃO e indica que a expressão do lado direito do '=' será atribuída a variável do lado esquerdo. Neste curso, para mantermos coerência com a Linguagem C, consideraremos que a expressão como um todo resulta no valor que é atribuído a variável. Operadores AritméticosOs operadores aritméticos que usaremos neste curso serão os disponíveis no C:
O único operador desconhecido aqui é o resto, cujo significado é o resto entre dois númerosinteiros. Exemplo, se B possui o valor 9, então o resultado da atribuição na expressão: A = B%2 será 1. Representando o algoritmo com pseudo-código
|
AULA 2 DIA 14/02/2014 | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
AULA 2 DIA 14/02/2014ObjetivosO aluno deverá saber utilizar comandos e expressões em pseudo-código e fluxogramas usando:
Expressões com operadores relacionaisNa aula anterior estudamos como construir expressões usando operadores aritméticos e o operador de atribuição. Vamos continuar este tópico aumentando o poder das expressões através dos operadores relacionais e lógicos. Os operadores relacionais permitem realizar comparações entre dois operandos. Os operadores são os seguintes:
Note que com operadores lógicos podemos construir expressões tais como indicado no exemplo abaixo: Exemplo: O algoritmo abaixo lê dois número inteiros para dentro das variáveis A e B e atribue à variável X o resultado da comparação do primeiro com o segundo. Observe que a variável X é do tipo booleano.
|
AULA 3 DIA 22/02/2014 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
AULA 3 DIA 22/02/2014ObjetivosO aluno devera ser capaz de:
Possíveis linguagens de programaçãoNa prática, é inviável desenvolver programas complexos em LINGUAGEM DE MÁQUINA. Em geral, utilizamos linguagens de ALTO NÍVEL que podem, de alguma forma, serem traduzidas (compiladas) para a linguagem de baixo nível ou interpretadas em tempo de execução. Exemplo:
Neste curso utilizaremos a linguagem C. Por que? É uma linguagem muito usada na implementação de produtos eletrônicos, incluindo àqueles voltados as Telecomunicações. Introdução a linguagem C
EmbedVideo received the bad id "rGCbvqz6Kt4#!" for the service "youtube".
Visão geral do processo de compilação com gcc
Compilando um programa CNeste curso usaremos o compilador da coleção gcc do projeto GNU. O manual completo do gcc pode ser encontrado aqui. O processo de desenvolvimento do programa envolve:
mkdir ExerciciosC cd Exercicios Exemplo: salve o programa abaixo como teste.c
#include <stdio.h>
main()
{
printf("Alo Mundo\n");
}
gcc teste.c -o teste
./teste Nota: o atributo -o permite que se forneça um nome para o executável diferente de a.out É possível somente compilar (gerar código objeto): gcc -c teste.c Observe os subprodutos listando com detalhes: ls -l Estrutura do Programa em CUm programa em C pode ser visto como um conjunto de uma ou mais funções:
#include <stdio.h>
main()
{
printf("Alo Mundo\n");
}
No programa acima temos uma única função: a função main() Uma função é um pedaço de código delimitado por chaves e com um nome. Todo programa C bem comportado deve ter um função main. A primeira instrução desta função é o ponto de entrada do código do usuário. A primeira instrução do programa acima é uma chamada a uma função da biblioteca: o printf(). Esta função permite mostrar dados no terminal. Não é possível colocar instruções fora de funções! Vamos ver algumas variações do Alo Mundo: #include <stdio.h>
main()
{
printf("Alo Mundo 1\n");
printf("Alo Mundo 2\n");
printf("Alo Mundo 3\n");
printf("Alo Mundo 4\n");
printf("Alo Mundo 5\n");
}
e #include <stdio.h>
main()
{
printf("Alo Mundo 1");
printf("Alo Mundo 2\n");
printf("Alo Mundo 3\n\n");
printf("Alo Mundo 4\n");
printf("Alo Mundo 5\n");
}
Observe nestes exemplos a ordem de execução das instruções e o uso do caracter de nova linha. Declarando variáveis inteiras e reais locaisNo "c" temos que declarar as variáveis que serão utilizadas no programa. Se estas variáveis forem declaradas DENTRO da função elas serão "vistas" somente localmente (escopo local). Este conceito será estendido para blocos de códigos posteriormente.
#include <stdio.h>
main()
{
/* aqui começam as declarações de variáveis */
int x; /* declaração de uma variável inteira */
float y; /* declaração de uma variável real */
/* aqui começam as instruções do programa principal */
x=5; /* atribuindo o valor 5 (constante) a variável x */
y=6.5;
}
No exemplo anterior criamos duas variáveis : x e y. Lembrando que variáveis podem ser vistas como um lugar que pode armazenar um valor. Para simplificar ainda mais, podemos imaginar a variável como uma CAIXA onde podemos armazenar um valor. A CAIXA possui um nome e um tipo. O nome IDENTIFICA a CAIXA enquanto o tipo da variável determina a natureza dos valores que podemos armazenar na CAIXA: +-----+ | 5 | x +-----+ A variável x é do tipo int e, portanto, está apta a armazenar valores inteiros. Já a variável y é do tipo float e está apta a receber valores reais. +-----+ | 6.5 | y +-----+ Observe que as instruções de atribuição acima envolvem constantes também. Funções de entrada e saída de dadosNo "c" não existe instrução especialmente para leitura ou saída de dados. Este procedimento é realizado através de funções da biblioteca. Na sequência são mostradas duas funções "clássicas" de entrada e saída de dados: o printf() - já apresentado - e o scanf(). Esta última função permite entrada de dados.
#include <stdio.h>
main()
{
int x; /* declaração de uma variável inteira */
float y; /* declaração de uma variável real */
printf ("Entre com o valor de x ");
scanf("%d",&x);
printf ("Entre com o valor de y ");
scanf("%f",&y);
printf ("O valor de x é %d\n",x);
printf ("O valor de y é %f\n",y);
}
Uma variação do uso do printf neste exemplo é: #include <stdio.h>
main()
{
int x; /* declaração de uma variável inteira */
float y; /* declaração de uma variável real */
printf ("Entre com o valor de x ");
scanf("%d",&x);
printf ("Entre com o valor de y ");
scanf("%f",&y);
printf ("O valor de x é %d e o valor de y é %f\n",x, y);
}
Construindo expressões no COperador de AtribuiçãoO operador de atribuição = é amplamente usado para atribuir valores para variáveis. Veja o exemplo abaixo. Dois números do tipo float são lidos para as variáveis x e y e a média é calculada e colocada na variável média. #include <stdio.h>
main()
{
float x,y;
float media;
printf("Entre com x\n");
scanf("%f", &x);
printf("Entre com y\n");
scanf("%f", &y);
media = (x+y)/2;
printf("Valor de media = %f\n",media);
}
Um diferencial do C com relação a outras linguagens é que a atribuição pode ser realizada várias vezes dentro de uma mesma instrução. Veja o exemplo: #include <stdio.h>
main()
{
int x,y,w;
x=1;
w=y=x+1;
printf("x=%d y=%d w=%d\n", x,y,w);
w=2*(y=x+1);
printf("x=%d y=%d w=%d\n", x,y,w);
}
NOTE que o código: w=2*y=x+1; produz um erro de compilação: erro: lvalue required as left operand of assignment Ver conceito de lvalue e rvalue aqui. O problema é que A ESQUERDA do sinal de atribuição sempre deve existir uma referência a uma área de memória (normalmente uma variável). A semântica da atribuição é copiar o valor computado a direita PARA a área referenciada a esquerda. Operadores aritméticosOs operadores aritméticos básicos são àqueles apresentados na aula anterior.
Exercícios
|
AULA 4 DIA 21/02/2014 | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Objetivos
Operadores Relacionais e LógicosOs operadores relacionais e lógicos são os mesmos vistos na aula anterior.
Ver Operadores Relacionais e Lógicos Comandos de decisão if() e if() else
#include <stdio.h>
main()
{
int x; /* declaração de uma variável inteira */
int y; /* declaração de uma variável inteira */
printf ("Entre com o valor de x ");
scanf("%d",&x);
printf ("Entre com o valor de y ");
scanf("%d",&y);
if (y>x)
printf("MSG1:y é maior que x\n");
if (y>x)
printf("MSG2:y é maior que x\n");
else
printf("MSG3:y é igual ou menor que x\n");
}
Outro exemplo, usando blocos:
#include <stdio.h>
main()
{
int x,y,z; /* declaração de uma variável inteira */
printf ("Entre com o valor de x ");
scanf("%d",&x);
printf ("Entre com o valor de y ");
scanf("%d",&y);
if (y>x) {
printf("MSG1: y é maior que x\n");
z = y-x;
printf("MSG2: Neste caso z = %d\n", z);
} else {
printf("MSG3: y é igual ou menor que x\n");
z = x-y;
printf("MSG4: Neste caso z = %d\n", z);
}
}
No C, qualquer expressão que resulta em 0 é considerada FALSA e qualquer expressão com valor diferente de 0 é VERDADEIRA. Exemplo: if (2)
printf("expressão sempre VERDADEIRA");
if ('2')
printf("expressão sempre VERDADEIRA");
if (1-1)
printf("expressão sempre FALSA");
if (x=1) /* um erro comum - sinal de atribuição no lugar de == */
printf("expressão sempre VERDADEIRA");
Tipo CharUma variável do tipo caracter é tratada como um número inteiro e declarada com o tipo char, que na prática é um número inteiro de byte. Exemplo #include <stdio.h>
main ()
{
char x='A',y=65,w=0x41,z;
scanf("%c",&z);
printf("Caracter lido = %c\n",z);
printf("Caracter lido = %d\n",z);
printf("Caracter lido = %x\n",z);
if (z==x)
printf("Iguais 1\n");
if (z==y)
printf("Iguais 2\n");
if (z==w)
printf("Iguais 3\n");
}
IndentaçãoExercícios
|
AULA 5 DIA 27/02/2014 |
---|
AULA 6 DIA 29/08/2013ObjetivosO aluno deverá ser capaz de colocar estruturas de repetição especificadas em fluxogramas ou pseudo-código na forma de estruturas em linguagem C. Estruturas de RepetiçãoExistem 4 estruturas/comandos que permitem implementar loops ou repetições de blocos de código:
NOTA 1: Observe que repetir o código siginifica voltar a executá-lo, normalmente sobre o controle de uma expressão lógica. O comando while():teste da repetição no começoO comando while permite implementar loops com controle no início: #include <stdio.h>
main()
{
int contador;
contador=0;
while (contador<5) {
printf("valor do contador = %d\n", contador);
contador=contador+1;
}
}
Variação do exemplo anterior: #include <stdio.h>
main()
{
int contador;
contador=0;
while (contador<5) {
printf("valor da expressão = contador < 5 é %d\n", contador<5);
printf("valor do contador = %d\n", contador);
contador=contador+1;
}
printf("NO FINAL a expressão contador < 5 é %d\n", contador<5);
}
A estrutura do comando, informalmente, é: while (expressão) instrução_simples; ou while (expressão) { lista_de_instruções } Vamos ver a correspondência do comando while com um fluxograma: NOTE que no exemplo anterior o contador inicialmente DEVE conter um valor válido. Comando do while: controle do loop no finalO comando do while() permite a repetição de uma ou mais instruções, com controle do loop no final. Isto permite que o bloco seja executado pelo menos uma vez. #include <stdio.h>
main()
{
int contador;
contador=0;
do {
printf("valor do contador = %d\n", contador);
contador=contador+1;
} while (contador<5);
}
A estrutura do comando, informalmente, é: do instrução_simples; while (expressão); ou do { lista_de_instruções } while (expressão); Comando for()O comando for() permite uma forma mais elaborada de loop, com controle no início do bloco de repetição. #include <stdio.h>
main()
{
int i;
for (i=0;i<10;i=i+1)
printf("i =%d\n",i);
}
A estrutura do comando é: for(expressão_inicial;expressão_de_controle; expressão_de_final_de _bloco) instrução_simples; ou for(expressão_inicial;expressão_de_controle; expressão_de_final_de _bloco) { lista_de_instruções } Aninhamento de loops#include <stdio.h>
main()
{
int i,j;
for (i=0;i<3;i++) {
for (j=0;j<4;j++) {
printf("valor de j = %d\n", j);
}
printf("valor de i = %d\n", i);
}
}
Comando gotoO comando goto é um dos mais antigos da programação. A ideia é comandar um salto para um determinado ponto específico do programa marcado por um rótulo (LABEL). Para utilizá-lo deve-se, portanto, marcar o ponto para onde será feito o salto usando um LABEL. Exemplo: main()
{
int i;
i=0;
PONTO1:
printf("Laço de número %d\n", i);
i++;
if (i<10)
goto PONTO1;
}
Devido a ser uma instrução "desestruturante", em geral NÂO se recomenda o uso deste comando. Em alguns casos de tratamento de erro pode ser interessante o uso do goto. Leia um pouco mais sobre o goto aqui. Loop InfinitoÉ possível implementar loops infinitos com qualquer uma das instruções acima. Exemplo com comando for: main()
{
for(;;) {
/* Este bloco se executará infinitamente */
}
}
ou com o comando while: main()
{
while(1) {
/* Este bloco se executará infinitamente */
}
}
aaaaaaaaaa a a aaaaaaaaaa |
AULA 6 DIA 28/02/2014 |
---|
Exercícios 1.Usando o comando for aninhado, construa um programa que implemente a figura abaixo. A margem esquerda (margem de espaços), o caracter do desenho, o número de linhas vazadas e o tamanho horizontal da figura deve ser lido pelo teclado. aaaaaaaaaa a a aaaaaaaaaa #include <stdio.h>
main()
{
int i, j,num_linhas, num_colunas, margem;
printf("Entre com linhas\n");
scanf ("%d",&num_linhas);
printf("Entre com colunas\n");
scanf ("%d",&num_colunas);
printf("Entre com margem\n");
scanf ("%d",&margem);
/* subproblema 1 */
for (i=0;i<margem;i=i+1)
printf(" ");
for (i=0;i<num_colunas;i=i+1)
printf("A");
printf("\n");
/*subproblema 3 */
for(j=0;j<num_linhas-2;j++) {
/*subproblema 2 */
for (i=0;i<margem;i=i+1)
printf(" ");
printf("A");
for(i=0;i<num_colunas-2;i=i+1)
printf(" ");
printf("A");
printf("\n");
}
/* subproblema 1 */
for (i=0;i<margem;i=i+1)
printf(" ");
for (i=0;i<num_colunas;i=i+1)
printf("A");
printf("\n");
}
2.Construa um programa para desenhar a seguinte figura de forma parametrizável: AAAAAAAAAAAAAAAA AAAAAAAAAAAAAA AAAAAAAAAAAA AAAAAAAAAA AAAAAAAA AAAAAA AAAA AA BB BBBBB BBBBBBBB BBBBBBBBBBB BBBBBBBBBBBBBB BBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBB 3.#Estude o programa (referência) abaixo: /* rand example: guess the number */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main ()
{
int iSecret, iGuess;
/* initialize random seed: */
srand ( time(NULL) );
/* generate secret number: */
iSecret = rand() % 10 + 1;
do {
printf ("Guess the number (1 to 10): ");
scanf ("%d",&iGuess);
if (iSecret<iGuess)
printf ("The secret number is lower\n");
else {
if (iSecret>iGuess)
printf ("The secret number is higher\n");
}
} while (iSecret!=iGuess);
printf ("Congratulations!\n");
return 0;
}
srand ( time(NULL) ); iSecret = rand() % 10 + 1; 4.Sobre o exercício 3, implemente uma versão usando o comando while(). 5.Elabore um programa que lê um número inteiro e imprime todos os números pares entre 1 e este número.
|
AULA 7 DIA 6/03/2014 |
---|
AULA 7 DIA 6/03/2014Objetivos
Uso de break para sair de loopsEm exercícios anteriores, a finalização de um loop normalmente se dá pela expressão de controle de loop associado a instrução usada. É possível sair de um loop na força bruta usando a instrução break: #include <stdio.h>
main()
{
int i,j;
for (i=0;i<10;i++) {
if (i==5)
break;
}
printf("valor de i=%d\n", i);
}
Note que o break sempre sai do loop mais próximo a ele. #include <stdio.h>
main()
{
int i,j;
for (i=0;i<3;i++) {
for (j=0;j<4;j++) {
if (j==1) {
break;
}
printf("valor de j = %d\n", j);
}
if (i==2)
break;
("valor de i = %d\n", i);
}
}
Uso do continue para prosseguir no início do loop#include <stdio.h>
main()
{
int i,j;
for (i=0;i<3;i++) {
if (i==1) {
continue;
}
printf("valor de j = %d\n", j);
for (j=0;j<4;j++) {
if (j==1) {
continue;
}
printf("valor de j = %d\n", j);
}
}
}
Usando o gdb para depurar programasÈ possível controlar a execução de um programa usando um outro programa, chamado depurador (debugger), para controlar a execução do primeiro. A GNU desenvolveu o debugger gdb que é hoje amplamente utilizado por desenvolvedores. Seja o programa armazenado no arquivo teste.c:#include <stdio.h>
main()
{
int x,y;
x = 2;
y = 0;
while (y<5)
x++;
printf ("Valor de x = %d\n",x);
}
Para que um programa possa ser depurado, devemos compilá-lo da forma: gcc -g teste.c -o teste
O gdb pode então ser chamado da forma: gdb teste Um breakpoint pode ser colocado em qualquer linha ou entrada de função do programa. Para colocar um breakpoint na entrada da função pode-se fazer: b main Para executar o programa basta fazer o comando run: r A execução para no breakpoint. A instrução mostrada ainda vai ser executada. Para acompanhar o valor de variáveis pode-se colocá-las em display: display x display y Para execução passo a passo pode-se utilizar o comando next: n Para ver o Para ver o conteúdo de uma variável pode-se ainda fazer o comando print: print x
Usando funções da biblioteca matemáticaPara usar as funções matemáticas da biblioteca padrão, fazer os seguintes passos:
#include <stdio.h>
#include <math.h>
main()
{
float x,y; /* declaração de duas variáveis reais */
printf ("Entre com o valor de x ");
scanf("%f",&x);
y = sqrtf(x);
printf ("Raiz de x = %lf", y);
}
NOTA: a maior parte de parâmetros e valores de retorno das funções matemáticas são reais de dupla precisão (double).
gcc ex1.c -o ex1 -lm EXERCÍCIOS
|
AULA 8 DIA 7/03/2014 |
---|
AULA 8 DIA 7/03/2014Exercícios
|
AULA 7 DIA 13/03/2014
Objetivos
O aluno deverá ser capaz de:
- dividir problemas em subproblemas e utilizar subrotinas para organizar a solução.
- passar parâmetros em funções e retonar valores.
Quebrando um problema em subproblemas: SUBPROGRAMAS
PROBLEMA: Aprimorar o exemplo do controle de acesso para que, no caso de 3 tentativas de acesso seguidas, com senha errada, o sistema seja bloqueado.
- DADOS DE ENTRADA: SENHA /* variável que armazena a senha entrada pelo usuário ou administrador */
- DADOS DE SAÍDA: mensagem de abertura da porta / usuário bloqueado*/
- VARIÁVEIS INTERMEDIÁRIAS: CONT_ACESSO /* valor inicial zero - incrementada a cada senha inválida */
Note que a variável CONT_ACESSO é iniciada com zero e incrementada a cada erro no fornecimento da senha. A atribuição CONT_ACESSO = CONT_+ACESSO + 1 deve ser interpretada da forma: acesse o valor de CONT_ACESSO e some 1 a este valor. Coloque o resultado novamente em CONT_ACESSO (o conteúdo anterior é sobrescrito!)
Neste procedimento pode ser observado que:
- começa a aparecer uma certa complexidade no fluxograma;
- Além disto, não ficou uma abordagem muito interessante, pois se for o administrador que erra a senha, ele pode bloquear o usuário;
- não existe forma de desbloquear a senha (zerar o contador), a não ser mudando a senha.
Em síntese, existem subproblemas adicionais a serem resolvidos. Como podemos resolvê-los sem deixar um fluxograma complexo?
Usaremos a caixa de processos pré-definidos que usaremos para invocar funções que resolvem determinado subproblema.
Inicialmente, vamos construir três subprogramas:
- Iniciar_Sistema(): inicia variáveis do sistema, colocando o sistema em um estado inicial conhecido;
- Tratar_Admin(): é o código que trata a funcionalidade associada ao administrador;
- Tratar_User(): é a funcionalidade que trata o usuário (procedimento de abrir porta, bloquear etc).
OBS: Note que foi usada uma variável auxiliar AUX que permite ajustar o valor de número de acessos a ser mostrado no display. Note também que na caixa DISPLAY foi usado uma string a ser impressa e a variável AUX cujo conteúdo deve ser impresso. Ambos separados por vírgula.
PARÂMETROS E RETORNO DE VALORES EM SUBPROGRAMAS
Para tornar ainda mais interessante o uso de subprogramas, vamos ver o conceito de passagem de parâmetros e retorno de valores.
Quando chamamos (invocamos) um subprograma podemos passar valores (dados de entrada) para este subprograma. Estes valores são passados através de variáveis especiais que chamamos de parâmetros.
Parâmetros podem ser passados por valor e por referência. Por valor é quando os dados a serem passados na invocação do subprograma são copiados para uma variável do subprograma.
Os parâmetros são passados por referência quando o que é passado para o subprograma é simplesmente o endereço da variável repassada na invocação do subprograma.
Não existe uma forma explícita de definir os parâmetros em um fluxograma. Deve-se realizar um comentário antes ou ao lado do mesmo especificando o tipo e como será tratado o parâmetro.
EXEMPLO: Seja elaborar um fluxograma correspondente a uma subprograma que deve calcular o fatorial de um número inteiro passado como parâmetro. O subprograma deve retornar o valor calculado.
A função fatorial é definida por:
Neste fluxograma, o subprograma denominado CalcFatorial recebe um valor no parâmetro N (implicitamente inteiro) e retorna o valor calculado do fatorial.
O fluxograma principal invoca duas vezes o subrograma. O retorno é armazenado nas variáveis NUM1 e NUm3.
Quando um subprograma retorna um valor, ele é chamado de função. Para manter coerência com o C chamaremos qualquer subrprograma de função (independente de retornar valor).
Exemplo de Função usando pseudo-código
Seja uma função que retorna a média de 5 números reais passados como parâmetros:
real FUNCAO(real num1, real num2, real num3, real num 4, real num5)
VARIAVEIS
media: real
INICIO
media = (num1+num2+num3+num4+num5) /5
RETORNAR media
FIM
</syntaxhighlight>
EXERCÍCIOS
EXERCÍCIO 1: Implementar uma função (subprograma), usando fluxograma, que recebe dois números inteiros como parâmetro. A função retorna 1 se os números forem iguais, 0 se o primeiro número maior que o segundo e -1 se o segundo for maior que o primeiro.
Mostre um exemplo de uso a partir de um fluxograma principal.
EXERCÍCIO 2: Usando a formula de Heron, implemente na forma de pseudo-código uma função que recebe três números reais (lados de um triângulo) e retorne o valor da área do mesmo.
EXERCÍCIO 3: Implementar uma função (subprograma), usando fluxograma, para computar o valor da PG, dados como parâmetros s e q, onde "s" é o número inicial e "q" a razão da progressão. A função deve retornar um número real que é o valor da PG.
Obs: Para PG tem-se:
- ou
EXERCÍCIO 4: Modificar o sistema de controle de acesso para incluir a inserção de nome de usuário (USERID) e senha (SENHA). Prever a existência de dois usuários (USERID_1, USERID_2, SENHA_1, SENHA_2). O admin poderá ser identificado pelo nome ADMIN. Prever bloqueio por usuário (duas variáveis contadores).
Sugestão: criar funcões separadas para tratamento de cada usuário. Em breve veremos como podemos contornar esta duplicação através da parametrização de funções/subprogramas.
Funções no C
Chamando funções
Um programa em C basicamente é um conjunto de funções.
Uma função pode ser vista como um subprograma para o qual podemos repassar
dados de entrada através de parâmetros e receber os resultados através
do retorno da função.
Normalmente, um programa bem comportado em C possui pelo menos uma função: a função main(). Esta função
é chamada no início da execução do programa. A primeira instrução da função main() é a primeira instrução
executada pelo programa (pelo menos do ponto de vista do programador). Da mesma forma, a última instrução
desta função é a última instrução a ser chamada.
Um programa normalmente vai apresentar um conjunto de funções. Por exemplo:
#include <stdio.h>
func4()
{
printf("Esta é a função func4()\n");
}
func3()
{
printf("Esta é a função func3()\n");
func4();
}
func2()
{
printf("Esta é a função func2()\n");
}
func1()
{
printf("Esta é a função func1()\n");
func2();
func3();
}
main()
{
printf("Esta é a primeira instrução da função main()\n");
func1();
printf("Esta é a última instrução da função main()\n");
}
A sequência de chamada de funções pode ser ilustrada da forma:
EXERCÍCIO: Compile e execute o programa acima. Verifique a ordem de impressão das mensagens e compare com as chamadas das funções.
NOTA: Uma função pode ser chamada várias vezes no programa.
É O REAPROVEITAMENTO DE CÓDIGO...
Passando parâmetros e recebendo valores de retorno
Uma função normalmente resolve um determinado problema para um determinado conjunto de dados e produz uma saída. Estes dados podem ser passados como parâmetros e a saída pode ser retornada pela função.
Exemplo: Uma função media_nums() que retorna a média de 3 números reais passados como parâmetros
#include <stdio.h>
float media_nums(float num1, float num2, float num3)
{
float media_local;
media_local = (num1 + num2 + num3)/3;
return media_local;
}
main()
{
float media, aux1, aux2, aux3;
printf("\nEntre com numero 1: ");
scanf ("%f",&aux1);
printf("\nEntre com numero 2: ");
scanf ("%f",&aux2);
printf("\nEntre com numero 3: ");
scanf ("%f",&aux3);
media = media_nums(aux1, aux2, aux3);
printf ("\nmedia dos 3 numeros é %f\n", media);
}
Deve ser observado que:
- após o nome da função, entre parênteses, são fornecidos os três parâmetros com os seus respectivos tipos. Os valores (conteúdos das variáveis) aux1, aux2 e aux3 são copiados para as variáveis num1, num2 e num3 da função media_nums().
- a função media_nums() retorna um valor do tipo float (informado antes do nome da função) que é o valor da variável media_local. Este valor é copiado para a variável media da função main()
- as variáveis num1, num2 e num3 bem como a variável media_local possuem escopo LOCAL, ou seja, são "vistas" somente pela função media_nums();
- as variáveis media, aux1, aux2 e aux3 também possuem escopo LOCAL, ou seja são "vistas" somente pela função main();
NOTE que o formato de declaração de uma função é
tipo_retorno nome_funcao( lista_de_parametros )
{
declaracao_variaveis_locais
instruções
}
Por enquanto, assumiremos que variáveis devem ser somente declaradas no início da função. Existem situações que poderemos relaxar esta afirmação.
Um pouco mais sobre parâmetros
O termo argumento ou parâmetro real (atual) é usado para referenciar os valores que estão sendo passados na CHAMADA da função. Os parâmetros formais referem-se aos parâmetros listados na função. É comum, no entanto, usar os termos argumentos e parâmetros como sinônimos e identificados pelo contexto em que estão sendo usados.
A passagem de parâmetros POR VALOR diz respeito a copiar o valor do argumento na CHAMADA da função para a variável associada ao parâmetro na função. Mais tarde falaremos na passagem de parâmetro POR REFERÊNCIA. Por ora, usaremos a passagem
POR VALOR.
Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis.
Eles podem ser uma expressão qualquer (uma expressão SEMPRE resulta em um VALOR).
Exemplo de chamadas para a função media_nums():
main()
{
float media, x,y,z;
x = 5.7;
y = 9.8;
/* exemplo de chamada 1 */
media = media_nums(4.8,x,y*3);
/* exemplo de chamada 2 */
media = media_nums (x+y,y*y+5,(x+y)/2);
}
Deve ser observado que:
- na chamada 1 do exemplo, os parâmetros são uma CONSTANTE, o valor de x, e o valor de y*3. Note que o compilador deve gerar código para resolver estas expressões antes de INVOCAR a função!.
- na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA.
Variáveis GLOBAIS e variáveis LOCAIS
Se variáveis são declaradas dentro de uma função, então a visbilidade (ESCOPO) destas variáveis é LOCAL. Nenhuma outra função tem acesso a estas variáveis.
Uma variável pode ser GLOBAL, ou seja, declarada FORA das funções. Neste caso a variável é VISTA por todas as funções. Seja o exemplo anterior modiificado:
#include <stdio.h>
float media; /* Variável GLOBAL */
void media_nums(float num1, float num2, float num3)
{
media = (num1 + num2 + num3)/3;
return;
}
main()
{
float aux1, aux2, aux3; /* Variáveis LOCAIS */
printf("\nEntre com numero 1: ");
scanf ("%f",&aux1);
printf("\nEntre com numero 2: ");
scanf ("%f",&aux2);
printf("\nEntre com numero 3: ");
scanf ("%f",&aux3);
media_nums(aux1, aux2, aux3);
printf ("\nmedia dos 3 numeros é %f\n", media);
}
Neste exemplo, a variável media é declarada como GLOBAL. Ela é MODIFICADA diretamente pela função media_nums() e impressa pela função main()
NOTE que como a função media_nums() não retorna valor então declaramos
seu tipo de retorno como void que significa aqui NADA ou VAZIO.
NOTE também que MESMO que a função retorne um valor, não é obrigatório colocá-la
no lado direito do sinal de atribuição.
Na realidade, uma função pode ser chamada dentro de qualquer expressão. Por exemplo,
para o caso em que a função media_nums() retorna um valor, ela poderia ser usada como:
#include <stdio.h>
float media_nums(float num1, float num2, float num3)
{
float media_local;
media_local = (num1 + num2 + num3)/3;
return media_local;
}
main()
{
float media, aux1, aux2, aux3;
printf("\nEntre com numero 1: ");
scanf ("%f",&aux1);).
printf("\nEntre com numero 2: ");
scanf ("%f",&aux2);
printf("\nEntre com numero 3: ");
scanf ("%f",&aux3);
media = media_nums(aux1, aux2, aux3);
printf ("\nmedia dos 3 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2, aux3));
}
Nome de variáveis
Um nome de variável pode conter letras, dígitos e o underscore(sublinhado). Ela DEVE iniciar com um underscore ou uma letra. Letras maúsculas e minúsculas podem ser usadas e são distinguidas (o C é CASE SENSITIVE
Variáveis LOCAIS e GLOBAIS podem ter o mesmo nome. A variável LOCAL terá preferência no uso.
Exercício: Execute o programa abaixo e verifique as saídas.
#include <stdio.h>
int i=1; /* GLOBAL */
func()
{
int i=100; /* LOCAL */
i=i+1; /* incrementa LOCAL */
printf( "Valor de i = %d na função func()\n", i );
}
main()
{
i=i+1; /* incrementa GLOBAL */
func();
printf( "Valor de i = %d \n", i );
}
NOTA: não é recomendado o uso de variáveis com o mesmo nome.
Iniciando variáveis na declaração
Tanto as variáveis LOCAIS como as GLOBAIS podem ser inicializadas na declaração.
Exemplo:
int alfa=1;
main()
{
float beta=1.5;
printf("Valor de alfa = %d e valor de beta = %f\n", alfa, beta);
}
NOTA: variáveis LOCAIS não são iniciadas automaticamente: cabe ao programador iniciá-la corretamente.
NOTA: variáveis GLOBAIS são iniciadas automaticamente com zero.
Mas mantenha-se informado sobre o sistema que está trabalhando...
Em sistemas embarcados pode não ser verdade!
Um pouco mais sobre parâmetros
O termo argumento ou parâmetro real (atual) é usado para referenciar os valores que estão sendo passados na CHAMADA da função. Os parâmetros formais referem-se aos parâmetros listados na função. É comum, no entanto, usar os termos argumentos e parâmetros como sinônimos e identificados pelo contexto em que estão sendo usados.
A passagem de parâmetros POR VALOR diz respeito a copiar o valor do argumento na CHAMADA da função para a variável associada ao parâmetro na função. Mais tarde falaremos na passagem de parâmetro POR REFERÊNCIA. Por ora, usaremos a passagem
POR VALOR.
Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis.
Eles podem ser uma expressão qualquer (uma expressão SEMPRE resulta em um VALOR).
Exemplo de chamadas para a função media_nums():
main()
{
float media, x,y,z;
x = 5.7;
y = 9.8;
/* exemplo de chamada 1 */
media = media_nums(4.8,x,y*3);
/* exemplo de chamada 2 */
media = media_nums (x+y,y*y+5,(x+y)/2);
}
Deve ser observado que:
- na chamada 1 do exemplo, os parâmetros são uma CONSTANTE, o valor de x, e o valor de y*3. Note que o compilador deve gerar código para resolver estas expressões antes de INVOCAR a função!.
- na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA.
|}