Mudanças entre as edições de "AULA 4 - Programação 1 - Engenharia"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Linha 13: Linha 13:
 
</center>
 
</center>
 
</blockquote>
 
</blockquote>
=Objetivos=
 
  
 
<blockquote style="background: lightgray; border: 1px solid black; padding: 1em;">
 
<blockquote style="background: lightgray; border: 1px solid black; padding: 1em;">

Edição das 13h45min de 16 de agosto de 2019

Objetivos

O aluno devera ser capaz de:

  • descrever o processo de compilação;
  • diferenciar código fonte, objeto e executável;
  • compilar, executar pequenos programa em C usando o gcc;
  • declarar e usar variáveis locais inteiras e reais;
  • usar de forma simplificada as funções de entrada e saída: scanf() e printf.
  • depurar pequenos programas usando gdb modo texto

Processo de Desenvolvimento de um Programa

Possíveis linguagens de programação

Na 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:

  • Linguagem C
  • Fortran
  • Basic
  • C++
  • Pascal
  • Java
  • Python
 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.
 Ver estudo abaixo...

Introdução a linguagem C

Visão no Desenvolvimento do Programa

DeFluxoParaBinario.jpg

A figura acima mostra o processo de desenvolvimento de um programa:

  • Inicialmente deve-se conceber os algoritmos a serem implementados. Um fluxograma ou pseudocódigo pode ser usado nesta fase;
  • Um programa em linguagem de alto nível (AS MÀQUINAS NÃO ENTENDEM) é implementado (CÓDIGO FONTE);
  • Eventualmente, um código assembly ainda pode ser gerado (no processo de compilação) a partir do programa de alto nível. Assembly é mapeado

diretamente em linguagem de máquina. O ser humano especialista entende mas a máquina NÂO;

  • O código de máquina (instruções na forma de BYTES) é gerado (no processo de compilação). Arquivos objeto e binário final estão nesta categoria.

Visão geral do processo de compilação com gcc

  • Linguagens compiladas (ex: C) versus linguagens interpretadas (ex: Basic)

Diagrama-aula4.jpg

Compilando um programa C

Neste 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:

  • Editar o programa com um editor de texto tal como o vi ou gedit;
  • Salvar o programa com a terminação ".c" (ou ".h" se for um cabeçalho);


NOTA: crie um diretório para trabalhar nos exercícios que se seguem:

mkdir ExerciciosC
cd Exercicios

Exemplo: salve o programa abaixo como teste.c

 

#include <stdio.h>

main()
{
  printf("Alo Mundo\n");
}
  • Compilar/gerar executável do programa usando o gcc:
 gcc teste.c -o teste
  • Testar o programa:
./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 C

Um 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 locais

No "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 dados

No "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 C

Operador de Atribuição

O 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éticos

Os operadores aritméticos básicos são àqueles apresentados na aula anterior.

Operador Significado
+ adição
- subtração
* multiplicação
/ divisão
% resto

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.

Documentação do GDB

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 flag -g garante que seja incorporada informação simbólica e textual para a depuração.

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 conteúdo de uma variável pode-se ainda fazer o comando print:

print x

Exercícios

  1. Implementar um programa em C para receber a resistência em ohms de 2 resistores e então calcular a resistência série e paralela dos mesmos.
    Solução - Exercicio 01
    #include <stdio.h>
    
    main()
    {
     float r1,r2,reqS,reqP;
     printf("Entre com r1:\n");
     scanf("%f",&r1);
     printf("Entre com r2:\n");
     scanf("%f",&r2);
     reqS = r1+r2; 
     reqP = (r1*r2)/(r1+r2);
     printf ("Valor da req serie = %f\n",reqS);
     printf ("Valor da req paralelo = %f\n",reqP);
    }
    
  2. Implementar um programa C que lê quatro números inteiros para dentro de quatro variáveis: alfa, beta, gama e delta. O programa deve trocar os conteúdos destas variáveis(o que estiver em alfa para beta, de beta para gama, de gama para alfa). Imprimir os valores das variáveis antes e depois da troca.
    Solução - Exercicio 02
    #include <stdio.h>
    
    //solução usando duas variáveis auxiliares.
    
    int main()
    {
        int alfa,beta,gama,delta,aux1, aux2;
    
        printf("Entre com alfa\n");
        scanf("%d", &alfa);
        printf("Entre com gama\n");
        scanf("%d", &gama);
        printf("Entre com beta\n");
        scanf("%d",&beta);
        printf("Valor de alfa = %d\n",alfa);
        printf("Valor de gama = %d\n",gama);
        printf("Valor de beta = %d\n",beta);
     
        printf("Iniciam-se as trocas\n");
        aux1 = beta; //armazena valor antigo de Beta
        beta = alfa;
        printf("Novo valor de beta = %d\n",beta);
        aux2 = gama; //armazena valor antigo de Gama
        gama = aux1;
        printf("Novo valor de gama = %d\n",gama);
        alfa = aux2;
        printf("Novo valor de alfa = %d\n",alfa);
     
    }
    
    //SOLUÇÃO 2
    
    #include <stdio.h>
    
    //solucao com a variacao usando um aux para as variaveis nao ficar com mesmo valor
    main()
    {
        int alfa,beta,gama,delta,aux;
        printf("Entre com alfa\n");
        scanf("%d", &alfa);
        printf("Entre com delta\n");
        scanf("%d",&delta);
        printf("Entre com gama\n");
        scanf("%d", &gama);
        printf("Entre com beta\n");
        scanf("%d",&beta);
        printf("Valor de alfa = %d\n",alfa);
        printf("Valor de delta = %d\n",delta);
        printf("Valor de gama = %d\n",gama);
        printf("Valor de beta = %d\n",beta);
    
        printf("Iniciam-se as trocas\n");
        aux = beta;//utiliza-se a variavel 'aux' para armazenar o conteudo sem  perder o valor da variavel original
        beta = alfa;//coloca o conteudo de alfa para beta
        printf("Novo valor de beta = %d\n",beta);
        beta = aux;//volta o valor original da variavel utilizando o conteudo de 'aux'
        aux = gama;//novamente se utiliza 'aux'...
        gama = beta;//coloca o conteudo de beta para gama
        printf("Novo valor de gama = %d\n",gama);
        gama = aux;//volta o valor original da variavel utilizando o conteudo de 'aux'
        aux = alfa;
        alfa = gama;//coloca o conteudo de gama para alfa
        printf("Novo valor de alfa = %d\n",alfa);
    }
    
  3. Implementar um programa C que converte graus Farenheit em Celsius. Lembrar que
    Solução - Exercicio 03
    #include <stdio.h>
     
    main()
    {
      float f;
      float c;
     
      printf("Entre com graus em Farenheit\n");
      scanf("%f", &f);
      c = (f-32)/1.8;
      printf("Valor em celsius = %f\n",c);
    }
    
  4. Implementar um programa C que lê dois números inteiros e imprime o resto da média entre os dois.
    Solução - Exercicio 04
    #include<stdio.h>
    #include<math.h>
    main()
    {
      int x,y;
      float resto;
       
      printf("Entre com x\n");
      scanf("%f", &x);
      printf("Entre com y\n");
      scanf("%f", &y);
      resto = ((x+y)/2) % 2;//usamos o operador % para obter o resto da divisão
      printf("Valor do resto da media = %d\n",resto);
    }
    
  5. Implementar um programa C que calcula a área e comprimento de uma circunferência dado o raio.
    Solução - Exercicio 05
    #include <stdio.h>
     
    main()
    {
      float area,comp;
      float raio;
     
      printf("Entre com o raio do circulo\n");
      scanf("%f", &raio);
      comp = 2*3.1415*raio;
      printf("Valor da comprimento do circulo = %f\n",comp);
      area = 3.1415*raio*raio;
      printf("Valor da area do circulo = %f\n",area);
    }
    
  6. Implementar um programa C para calcular a corrente elétrica sobre um resistor dado a tensão sobre ele e a resistência em ohms.
    Solução - Exercicio 06
    #include <stdio.h>
     
    main()
    {
      float v,i,r;
      
     
      printf("Entre com a resistencia\n");
      scanf("%f", &r);
      printf("Entre com a tensao\n");
      scanf("%f",&v);
      i = v/r;
      printf("Valor da corrente = %f\n",i);
    }
    
  7. Considere dois vetores A e B dados pelas coordenadas em (x,y) em um espaço bidimensional. Considerando que para dois vetores A e B[1] da forma:
    Tem -se que o produto escalar entre dois vetores A e B é escrito como sendo:
    Implemente um programa C para calcular o produto escalar entre dois vetores representados no plano (2 dimensões), ou seja, devem ser fornecidas as coordenadas dos vetores. NOTE que NÃO é para usar declaração de vetores pois ainda não vimos. Crie 4 variáveis para receber as coordenadas: vx1,vy1,vx2,vy2
    Solução - Exercicio 07
    #include <stdio.h>
     
    main()
    {
      float vx1,vx2,vy1,vy2;
      float result;
     
      printf("Entre com o x do primeiro vetor\n");
      scanf("%f",&vx1);
      printf("Entre com o y do primeiro vetor\n");
      scanf("%f",&vy1);
      printf("Entre com o x do segundo vetor\n");
      scanf("%f",&vx2);	  
      printf("Entre com o y do segundo vetor\n");
      scanf("%f",&vy2);
      printf("O primeiro vetor ficou assim = (%f,%f)\n",vx1,vy1);
      printf("O segundo vetor ficou assim = (%f,%f)\n",vx2,vy2);
      result = (vx1*vx2) + (vy1*vy2);//equacao do produto escalar tem que retornar um numero
      printf("Valor do produto escalar = %f\n",result);
    }
    
  8. Faça um programa C para calcular o coeficiente angular e o coeficiente linear de uma reta DADOS dois pontos P(p1,p2) e Q (q1,q2).

DESAFIOS

  1. Faça um programa C para computar o desvio padrão de uma população representada por 7 números reais. Usar:
    (extraído da wikipedia [2])
    (extraído da wikipedia [3])
    SUGESTÃO: computar primeiramente a média OBS: Notar que o desvio padrão acima é de uma população. O desvio padrão de uma amostrausa a divisão por . Uma discussão para a dsiciplina da estatística. Para resolução deste exercício deve-se usar uma função de raiz quadrada (ver https://en.cppreference.com/w/c/numeric/math/sqrt)