PRG1-2014-1-Engenharia Programação 1 - Engenharia

De MediaWiki do Campus São José
Ir para: navegação, pesquisa

PRG1 - PROGRAMAÇÃO I

Índice

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

AULAS

AULA 1 DIA 13/02/2014

AULA 1 DIA 13/03/2014

Como fazer um churrasco

Vamos 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 algoritmo

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

  • pseudo-código
  • fluxogramas
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 Fluxogramas

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

FluxogramaMediaDoisNumeros.jpg

Pontos fortes:

  • permite fácil entendimento do algoritmo, mesmo para pessoas leigas;

Ponto fraco:

  • a descrição das estrutura dos dados inexiste. O usuário deve descrevê-los a parte;
Observe no exemplo anterior que nada é dito sobre as variáveis NUM1, NUM2 e MEDIA.

Símbolos de um Fluxograma

TabelaSimbolosFluxograma.jpg

Teste de Mesa

TesteMesaMediaDoisNumeros.jpg

Constantes, Variáveis

Algoritmos 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.

  • Tipo de Variáveis:
    • Numéricas: reais e inteiras
Ex: NUM1 = 5.5 /* NUM1 é uma variável real */
    • Booleanas: true ou false
Ex: RES = TRUE /* RES é uma variável booleana */ 
    • caracter:
Ex: LETRA = 'A'
    • alfanumérica
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ões

Expressõ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éticos

Os operadores aritméticos que usaremos neste curso serão os disponíveis no C:

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

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

ALGORITMO MEDIA VARIAVEIS

  NUM1: INTEIRO
  NUM2: INTEIRO
  MEDIA: REAL

INICIO

  LER NUM1
  LER NUM2
  MEDIA = (NUM1+NUM2)/2
  MOSTRAR MEDIA

FIM </syntaxhighlight>

Representando o algoritmo em linguagem C

#include <stdio.h>

main()
{
  int num1,num2;
  float media;

  scanf("%d",&num1);
  scanf("%d",&num2);
  media = (num1+num2)/2.0;
  prinft("media = %f\n", media);
}

Exercícios

1.Fazer um algoritmo na forma de fluxograma para calcular o valor y de uma função de uma reta dado x. Identifique quem são as variáveis e constantes do problema.

2.Fazer um algoritmo na forma de fluxograma para calcular o DELTA de uma equação do segundo grau, dados os coeficientes a e b. OBS: .

2A.Apresente uma variação de solução do exercício (2) usando apenas duas variáveis para armazenamento de dados.

3.Implementar um algoritmo na forma de fluxograma para calcular o ponto de intersecção de duas retas dados: a1,b1,a2 e b2.

4.Implementar um algoritmo na forma de pseudocódigo para calcular a conversão de CELSIUS para Farenheit.

5.Implementar um algoritmo na forma de pseudo-código para calcular a corrente sobre um resistor, dado a tensão V aplicada sobre ele. Considere um resistor com R constante de 1K ohm.

6.Incremente o exercício 5 para computar também a potência dissipada sobre o resistor.

7.Implementar um algoritmo na forma de pseudo-código para converter um ângulo em radianos para graus.

8.O problema da raposa, do milho e da galinha

EmbedVideo received the bad id "yifW9XueSaI#!" for the service "youtube".


EXERCÍCIO 8A: Descrever na forma de etapas um 
solução para o problema da raposa, do milho e da galinha.
Note que somente é possível escrever o algoritmo se tivermos uma solução para o problema.
EXERCÍCIO 8B: Descrever na forma de etapas uma 
solução para o problema dos canibais/padres.

9.Torres de Hanoi

Veja este jogo:

EmbedVideo received the bad id "hLnuMXO95f8#!" for the service "youtube".
EXERCÍCIO 9A: Escrever na forma de etapas numeradas a solução para o problema 
das torres de Hanói usando 3 discos.
EXERCÍCIO 9B: Escrever na forma de etapas numeradas a solução para o problema 
das torres de Hanói usando 4 discos.

10.Implementar um fluxograma para computar a área e o comprimento de uma circunferência dado o RAIO.

11.Implementar um fluxograma para ler um número complexo (ler por partes) no formato retangular e apresentar o módulo e o ângulo EM GRAUS do mesmo (formato polar). Suponha que você dispõe de uma função ATG() que calcula o arco em radianos de uma dada tangente.

12.Implementar um fluxograma para apresentar a velocidade no instante T (a ser fornecido) de um corpo de massa 1Kg que está inicialmente parado (em T=0) e submetido a força F também fornecida como entrada. Despreze atrito.

      Vi=0
      O--> 
      m=1Kg    F=1N
AULA 2 DIA 14/02/2014

AULA 2 DIA 14/02/2014

Objetivos

O aluno deverá saber utilizar comandos e expressões em pseudo-código e fluxogramas usando:

  • Operadores Relacionais e Lógicos
  • Comandos de Decisão
  • Comandos de decisão com aninhamento

Expressões com operadores relacionais

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

Operador Significado
> maior que
>= maior ou igual que
< menor que
<= menor ou igual que
== igual a (se o operando a esquerda é maior que o da direita)
!= diferente de (se o operando a esquerda é diferente do da direita)

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.


ALGORITMO exemplo VARIÁVEIS:

  A: inteiro
  B: inteiro
  X: booleana

INÍCIO

  LER A
  LER B
  X = A>B
  MOSTRAR "A condição A>B é ", X

FIM </syntaxhighlight>

Exercício: Fazer um fluxograma para o algoritmo acima.

Operadores Lógicos

É possível construir expressões ainda mais completas usando os operadores lógicos, apresentados abaixo:

Operador Significado
&& AND (E)
|| OR (OU)
! NOT (NÃO)


Uma expressão lógica tem como resultado da sua avaliação um valor VERDADEIRO ou FALSO. Para manter a coerência com a linguagem C qualquer expressão que resultar em 0 será considerada FALSA e se resultar em algo diferente de 0 será considerada verdadeira.

Exemplo: Considere uma variação do exercício anterior onde se compara 3 números inteiros: o primeiro com o segundo e o primeiro com o terceiro.

ALGORITMO exemplo VARIÁVEIS:

  A: inteiro
  B: inteiro
  C: inteiro
  X: booleana

INÍCIO

  LER A
  LER B
  LER C
  X = A>B E A < C
  MOSTRAR "A expressão A>B E A<C é ", X

FIM </syntaxhighlight>

Exercício: Implementar em pseudo-código um algoritmo para ler um número inteiro positivo e imprimir TRUE ou FALSE se o número estiver dentro da faixa 5 e 10.

Sheldon e o fluxograma da amizade

Vamos observar o fluxograma da amizade do Sheldom da série de TV "Big Bang Theory"

EmbedVideo received the bad id "VAX4jLlNo-Q#!" for the service "youtube".

Observe que a caixa no formato de LOSANGO permite testar uma condição: é uma caixa de decisão.

Controle do Fluxo de Execução: Estruturas de Decisão

Você deve ter observado que instruções simples (retângulo) possuem uma entrada e uma saída indicando que o fluxo de saída está claramente determinado.

Em algumas situações é necessário realizar algum teste sobre uma expressão e neste caso a execução é condicional. O teste da expressão pode resultar em VERDADEIRO e neste caso uma sequência de ações é realizada. Se o resultado for FALSO, uma outra sequência é realizada.

Seja o problema:

Problema do Controle de Acesso

PROBLEMA: Controlar o acesso a uma porta usando uma senha pré-configurada no sistema.

DADO DE ENTRADA: SENHA (variável alfanumérica)

DADO DE SAÌDA: porta aberta (simulado com msg "PORTA ABERTA") ou mensagem de "SENHA NAO CONFERE"

VARIÁVEIS: SENHA (tiipo alfanumérica)

Algoritmo usando Fluxograma

FluxogramaControleAcessoI.jpg

Algoritmo usando Pseudo-código

ALGORITMO ControleAcesso VARIÁVEIS

  SENHA: alfanumérica

INICIO

  LER SENHA 
  SE SENHA=="alfa" ENTÃO
         "Abrir a porta"
  SENÃO
         "Senha não confere"
  FIMSE
  IR PARA INICIO

FIM </syntaxhighlight>

Aninhamento de estruturas de decisão

Note que é possível aninhar estruturas de decisão. Seja o exemplo ebaico que lê três lados de um possível triângulo e imprime se NÂO é um triângulo, ou, caso seja, imprime se é EQUILÁTERO, ISÓSCELES ou ESCALENO.

ALGORITMO trangulo VARIAVEIS

 lado1,lado2,lado3: real

INICIO

 SE lado1>(lado2+lado3) OU lado2>(lado1+lado3) OU lado3>(lado1+lado2) ENTÃO
     MOSTRAR "não é triângulo"
 SENÃO
     SE lado1==lado2 E lado1==lado3 ENTÃO
        MOSTRAR "equilatero"
     SENAO
        SE lado1==lado2 OU lado1==lado3 OU lado2==lado3 ENTÃO
            MOSTRAR "isósceles"
        SENÃO
            MOSTRAR "escaleno"
     FIMSE
 FIMSE

FIM </syntaxhighlight>

Exercícios

EXERCÍCIO 1:

Elaborar um fluxograma para o o problema de controle de acesso prevendo um procedimento para modificar a senha de acesso. Neste caso a senha deverá ser armazenada em uma variável. Para tanto, assuma a existência de uma senha de administrador fixa (por exemplo, "ADMIN"). Se a senha do administrador for fornecida, mostrar uma mensagem de ENTRE COM A NOVA SENHA de senha.

Prg1-ControleAcessoEx1.jpg

EXERCÍCIO 2:

Inserir a noção de UserID. Para abrir a porta o usuário entra com o UserId e com a senha. De fábrica o UserId é "alfa" e a senha "alfa". O UserId do admin é "admin" e a senha "beta".

EXERCÍCIO 3:

Inserir a noção de bloqueio do usuário. Se o usuário comum tentar 3 vezes e errar ele é bloqueado. A mudança de UserId deve desbloquear o usuário.

EXERCÍCIO 4:

Implementar em pseudocódigo um algoritmo que lé dois números reais e imprime uma mensagem dizendo que a média entre estes dois números é maior que 5.


AULA 3 DIA 22/02/2014

AULA 3 DIA 22/02/2014

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 as funções de entrada e saída: scanf() e printf.

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.

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

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

ProcessoCompilacao.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


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.
    #include <stdio.h>
    
    main()
    {
     float r1,r2,r_serie,r_paralelo;
     
     printf("Entre com o resistor 1\n");
     scanf("%f",&r1);
    
     printf("Entre com o resistor 2\n");
     scanf("%f",&r2);
    
     r_serie = r1 + r2;
     r_paralelo = (r1*r2)/(r1+r2);
    
     printf("Equivalente série é %f e paralelo é %f\n", r_serie, r_paralelo);
    }
    
  2. Implementar um programa C que lê dois números inteiros para dentro de duas variáveis alfa e beta. O programa deve trocar os conteúdos destas variáveis(o que estiver em alfa para beta e vice-versa).
  3. Implementar um programa C que converte graus Farenheit em Celsius.
  4. Implementar um programa C que lê dois números inteiros e imprime o resto da média entre os dois.
  5. Implementar um programa C que calcula a área e comprimento de uma circunferência dado o raio.


AULA 4 DIA 21/02/2014

Objetivos

  • Utilizar os operadores relacionais e lógicos na programação C
  • Utilizar o comando de decisão if else

Operadores Relacionais e Lógicos

Os operadores relacionais e lógicos são os mesmos vistos na aula anterior.

Operador Significado
> maior que
>= maior ou igual que
< menor que
<= menor ou igual que
== igual a (se o operando a esquerda é maior que o da direita)
!= diferente de (se o operando a esquerda é diferente do da direita)


Operador Significado
&& AND (E)
|| OR (OU)
! NOT (NÃO)

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 Char

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


Limpando sujeira do teclado

Indentação

Indentação Estilos

Exercícios

  1. Implementar um programa que lê um número inteiro e imprime se o número é par ou ímpar. SUGESTÃO: Usar o operador de resto.
  2. Implementar um programa em C para ler dois números inteiros e imprimir uma mensagem indicando se os números lidos são iguais ou diferentes. Caso sejam diferentes, computar a média dos mesmos.
  3. Implementar um programa para ler 4 números inteiros e imprimir uma mensagem se a soma dos dois primeiros for igual ou menor a soma dos dois últimos.
  4. Implementar um programa para ler dois números reais e, na sequência, um número inteiro. Se o número inteiro for 1 os dois números iniciais deverão ser somados, se for 2 eles serão subtraídos, se for 3 eles serão multiplicados e se for 4 serão divididos. Mostrar mensagem de erro se o número inteiro não estiver na faixa de 1 a 4. Mostrar mensagem caso a divisão não seja possível.
  5. Um estudo sobre sensibilidade de pessoas a temperaturas da água identificou que a maioria das pessoas considera fria a água com temperaturas abaixo de 25 graus, morna entre 25 e 30 graus, e quente acima de 30 graus. Escreva um algoritmo na forma de fluxograma que mostre as palavras "fria", "morna" ou "quente" dependendo da temperatura da água que for informada. Implemente o algoritmo na forma de um programa C.
  6. Implementar um programa que recebe três números reais e então o programa testa se estes números podem formar um triângulo EQUILÁTERO, ISÓSCELES, ESCALENO ou NÃO pode ser triângulo. (ver aula anterior).
  7. Implementar um programa C para converter um ângulo em radianos para graus.
  8. Implementar um programa C que recebe os 3 coeficientes de uma equação do segundo grau e então determina as raízes da mesma.
AULA 5 DIA 27/02/2014

AULA 6 DIA 29/08/2013

Objetivos

O 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ção

Existem 4 estruturas/comandos que permitem implementar loops ou repetições de blocos de código:

  • while()
  • do while()
  • for()
  • goto label
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ço

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

Fluxograma C Comentário
Fluxo5.jpg
while(contador<5) {
   printf("Entre com x\n");
   scanf("%f",&x);
   soma=soma+x;
   contador = contador + 1;
}
comando while() aplicado sobre um bloco de instruções. Note que se for uma instrução simples, as chaves podem ser omitidas.
NOTE que no exemplo anterior o contador inicialmente DEVE conter um valor válido.

Comando do while: controle do loop no final

O 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); 
 
Fluxograma C Comentário
FluxoDoWhile-Eraldo.jpg
contador = 0;
do {
        scanf("%d",&x);
        soma=soma+x;
        if (soma>150) 
           y=z+x;
        contador++;
} while(contador<5);
Note que instruções while e if são tratadas como instruções normais que podem ser aninhadas normalmente em outros comandos.

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
}
Fluxograma C Comentário
FluxogramaComandoFor-Eraldo.jpg
for(i=0; i<10; i++) {
  printf("Laço de número %d\n", i);
  if (i==5)
      printf("Este é o laço 5\n");
}
Observe que a expressão i=0 é executada SEMPRE e uma única VEZ, no início do comando.

A expressão i<10 é o controle do loop. Se FALSA o loop é encerrado. Ela é executada após a expressão de inicialização e, na sequência, no início de cada loop. A expressão i++ é executada no final de cada loop.

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 goto

O 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 */
   }
}
  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


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;
}
Estude também o significado das instruções:
 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/2014

Objetivos

  • Uso do break e do while;
  • uso do gdb
  • uso da biblioteca matemática.

Uso de break para sair de loops

Em 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.

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

Para ver o conteúdo de uma variável pode-se ainda fazer o comando print:

print x


Existem várias aplicações gráficas que usam o gdb. Um exemplo é o nemiver.

Usando funções da biblioteca matemática

Para usar as funções matemáticas da biblioteca padrão, fazer os seguintes passos:

  • No arquivo-fonte incluir o header math.h da biblioteca matemática:
 
#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).

  • Compilar e linkar o arquivo da forma:
 gcc ex1.c -o ex1 -lm

EXERCÍCIOS

  1. Faça uma versão "politicamente incorreta" do programa de adivinhação da aula passada, Faça um loop infinito com o do while() e use uma instrução goto para sair do loop.
    /* 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");
              }
              if (iSecret==iGuess) /* se acertou salta para FIM */
                  goto FIM;
          } while(1); 
     
    FIM:  printf ("Congratulations!\n");
          return 0;
    }
    
  2. Ainda sobre o exercício 1, implemente uma versão usando o comando while().
    /* 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;
    
          /* coloca um valor em iGuess que nunca será inserido pelo usuário */
          iGuess = -1;
    
          while (iSecret!=iGuess) {
              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");
              }
          } 
     
          printf ("Congratulations!\n");
          return 0;
    }
    
  3. Ainda sobre o exercício 1, implemente uma versão usando loop infinito e o comando break;
    /* 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");
              }
              if (iSecret==iGuess) /* se acertou sai do loop */
                  break;
          } while(1); 
     
          printf ("Congratulations!\n");
          return 0;
    }
    
AULA 8 DIA 7/03/2014

AULA 8 DIA 7/03/2014

Exercícios

  1. Elaborar uma versão do programa de adivinhação que conta o número de tentativas do usuário. Se o número de tentativas for superior a 3 o programa deve dar uma mensagem e se encerrar. Usar o do while (não use goto ou break).
  2. Reimplementar o programa usando o break para sair quando o número de tentativas for ultrapassado.
  3. Implementar um programa C para calcular o fatorial de um número inteiro a ser fornecido pelo teclado.
  4. Implementar um programa c para ler N números reais (float) e calcular a média entre eles. Note que N deve ser fornecido no início. Use o comando for.
  5. Implementar um programa C que permite calcular o valor de Y dado o polinômio: e as entradas x (números reais).
  6. Implementar um programa C para computar o valor de y dado o valor de x e sabendo que
  7. Implementar um programa C que permite entrar com N números reais e então calcula a média do maior e do menor número. N deve ser fornecido inicialmente.
  8. Implementar um programa que lê um número de 0 a 9 e imprime a cor correspondente na tabela de resistores.
  9. Implementar um programa para que sejam fornecidos 5 resistências (em ohms). O programa deve calcular o equivalente série e paralelo destas resistências.
  10. Implementar uma função que sorteia 10000 valores entre 1 e 6, simulando o "jogar de um dado". Armazenar o número de ocorrências de cada um dos valores em variáveis chamadas: val1, val2,...,val6. Ao final mostrar o resultado das ocorrências. Usar o comando for.
  11. 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.
  12. 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.


AULA 9 DIA 13/03/2014

AULA 9 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 */

FluxogramaControleAcessoComContador.jpg

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).


FluxogramaControleAcessoComSubprograma.jpg

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:


FluxogramaFatorial.jpg

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:

FuncChamadaFuncoes.png

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.
AULA 10 DIA 20/03/2014

AULA 10 DIA 20/03/2014

Objetivos

  • Exercícios básicos sobre funções em C
  • Avaliação 2

Exercícios sobre funções

  1. Implementar um programa com uma função que recebe dois números inteiros como parâmetro e imprime uma mensagem caso o primeiro número seja igual ao segundo. A função não retorna nada. A função main deve mostrar como funciona a função, chamando-a três vezes com diferentes valores.
    #include <stdio.h>
    
    void compara_num(int num1, int num2)
    {
       if (num1==num2) {
          printf("Números %d e %d são iguais!!!\n", num1,num2);
       } else {
          printf("Números %d e %d são diferentes!!!\n", num1,num2);   
       }
    }
    
    void main()
    {
       int x=1;
       int y=3;
       compara_num(4,5);
       compara_num(5,8);
       compara_num(2,2);
       compara_num(x,1);
       compara_num(x*3,y);   
    }
    
  2. Refazer o exercício anterior mas agora a função não deve imprimir nada. Ela deve retornar 1 se o primeiro parâmetro é maior que o segundo, 0 se forem iguais e -1 se o segundo for maior que o primeiro.
    As alterações feitas no código, foram implementadas pela monitora Beatriz da Silveira
    
    #include <stdio.h>
    
    int compara_num(int num1, int num2)
    {
       int retorno;
    
       if (num1==num2) {
          retorno=0;
       } else {
          if(num1 > num2){
             retorno=1;
          }else
    	 retorno=-1;
       }
       return retorno;
    }
    
    int main()
    {
       int ret;
       ret = compara_num(10,7);
       if(ret==0)
            printf("Números iguais\n");
    }
    
  3. Implementar uma função que recebe um char como parâmetro. A função deve retornar 1 se é uma letra maúscula, 2 se o parâmetro é uma letra minúscula e 3 se for qualquer outro símbolo. Fazer uma função main() para testar a função.
    int testa_letra(char letra)
    {
    }
    
  4. Implementar uma função que recebe um parâmetro do tipo char. Este parâmetro representa uma letra ou símbolo. Caso o parâmetro passado seja uma letra minúscula, a função deve retornar a letra MAÚSCULA. Se o parâmetro não for uma letra então a função deve retornar -1. Se o parâmetro passado for uma letra na forma maiúscula então deve retornar 1. Solução 1:
    #include <stdio.h>
    
    /* Contribuição do Aluno Kauly */
    
    char compara(char caracter){
    	char caracterM;
    	char retorno;
    		
    	if(caracter >= 97 && caracter <= 122){
    		caracterM = caracter - 32;
    		retorno = caracterM;	
    	} else {
    		if(caracter >= 65 && caracter <= 90){
    			retorno = 1;
    		}
    	else {
    		retorno = -1;
    
    		} 
    	}
    	return retorno;
    }
    
    main(){
    
    	char mCaracter;
    	char resultado;
    
    	printf("Digite um caracter: ");
    	scanf("%c",&mCaracter);
    	printf("\n");
    	resultado = compara(mCaracter);
    	if(resultado == -1){
    		printf("Resultado :%d\n",resultado);
    	} else {
    		if(resultado == 1){
    			printf("Resultado :%d\n",resultado);
    		}
    		else {
    			printf("Resultado :%c \n",resultado);
    		}
    	}	
    }
    
    Solução 2
    #include <stdio.h>
    
    /* Contribuição do Aluno Kauly */
    
    char compara(char caracter){
    	char caracterM;
    	char retorno;
    		
    	if(caracter >= 'A' && caracter <= 'Z'){
    		caracterM = caracter - 32;
    		retorno = caracterM;	
    	} else {
    		if(caracter >= 'a' && caracter <= 'z'){
    			retorno = 1;
    		}
    	else {
    		retorno = -1;
    
    		} 
    	}
    	return retorno;
    }
    
    main(){
    
    	char mCaracter;
    	char resultado;
    
    	printf("Digite um caracter: ");
    	scanf("%c",&mCaracter);
    	printf("\n");
    	resultado = compara(mCaracter);
    	if(resultado == -1){
    		printf("Resultado :%d\n",resultado);
    	} else {
    		if(resultado == 1){
    			printf("Resultado :%d\n",resultado);
    		}
    		else {
    			printf("Resultado :%c \n",resultado);
    		}
    	}	
    }
    
  5. Implementar uma função que recebe um char como parâmetro e também um número inteiro. A função deve se comportar como mostrado abaixo:
    int imprime_letras(char letra, int vezes)
    {
    }
    main()
    { 
      imprime_letras('A',10);
    }
    
    AAAAAAAAAA
    #include <stdio.h>
    
    /* Contribuição do Aluno Kleiton */
    
    int imprime_letras(char letra, int vezes) {
    	int i;
    	for (i=0;i<vezes;i=i+1)
    		printf("%c",letra);
    }
    
    int main() {
    	char aux1;
    	int aux2;
    	printf("Informe o caracter: ");
    	scanf("%c",&aux1);
    	printf("Informe quantas vezes repetir: ");
    	scanf("%d",&aux2);
    	imprime_letras(aux1,aux2);
    	printf("\n");
    }
    
  6. Refazer o exercício anterior para:
    int imprime_letras(char letra, int vezes)
    {
    }
    main()
    { 
      imprime_letras('C',10);
    }
    
    CDEFGHIJKL
    #include <stdio.h>
    
    /* Contribuição do Aluno Kleiton */
    
    int imprime_letras(char letra, int vezes) {
    	int i;
    	for (i=0;i<vezes;i=i+1) {
    		printf("%c",letra);
    		letra=letra+1;
    	}
    }
    
    int main() {
    	char aux1;
    	int aux2;
    	printf("Informe o caracter: ");
    	scanf("%c",&aux1);
    	printf("Informe quantas vezes repetir: ");
    	scanf("%d",&aux2);
    	imprime_letras(aux1,aux2);
    	printf("\n");
    }
    
  7. Implementar uma função chamada imprime_faixa que recebe dois números inteiros como parâmetros e, caso o segundo parâmetro seja maior que o primeiro ela deve imprimir todos os números inteiros entre oos dois parâmetros (incluindo eles). A função retorna -1 se o segundo número for menor ou igual ao primeiro. Exemplo: Seja a chamada
     imprime_faixa(4,6);
    
    A saída deve ser: 4 5 6
  8. Implementar uma FUNÇÃO que converte temperaturas de graus Fahrenheit (passado como parâmetro) para Celsius (retornado).
  9. Implementar duas FUNÇÕES em C para receber a resistência em ohms de 2 resistores e então calcular a resistência série (calc_res_serie()) e paralela (calc_res_paralela()) dos mesmos.
  10. Implementar uma função C para computar o valor de y dado o valor de x passado como parâmetro e sabendo que . Testar o uso da função no main().
  11. Implementar uma função que recebe dois números complexos no formato retangular e retorna o módulo (da coordenada polar) da soma destes números.Usar as funções sqrt[1] e atan [2] da biblioteca matemática Como converter:
ou
  1. Implementar uma função que recebe dois números complexos no formato retangular e retorna o ângulo (da coordenada polar) da multiplicação destes números.
  2. Implementar uma função para calcular y dado x, onde . A função deve retornar 0 se o quociente for zero (condição erro).
  3. Implementar uma função que calcula a área de um retângulo (float) dado a base e a altura como parâmetros.
  4. Implementar uma função que recebe 4 paâmetros: base, altura de um primeiro triângulo, base e altura de um segundo triângulo. A função deve retornar 1,0 ou -1 se a área do primeiro triângulo for maior, igual ou menor que o segundo triângulo.
  5. Implementar uma função da forma: void plotar_fig(int margem, int lado, char car1, char car2, char c3). Exemplo de uso: plotar_fig(6,5,'A','B','X'). A figura deverá ser desenhada da forma (onde aparece 'b' é espaço em branco:

bbbbbbA

bbbbbbAA

bbbbbbAAA

bbbbbbAAAA

bbbbbbAAAAA

XXXXXXXXXXX

bbbbbbBBBBB

bbbbbbBBBB

bbbbbbBBB

bbbbbbBB

bbbbbbB </syntaxhighlight>


AVALIAÇÃO

implementar uma fun����o que recebe um par��metro char. Afun����o deve retornar a letra mai��scula da letra passada como par��metro retornar -1 se o par��metro passado n���o �� letra e 1 se o par��metro.

AULA 11 DIA 27/03/2014

AULA 13 DIA 27/03/2014

Objetivos

  • comando switch;
  • exercícios
  • avaliação.

Comando switch

O comando switch permite controlar o fluxo de um programa de forma condicional. O comando testa uma expressão que deve resultar em um número inteiro. Uma sequência de cláusulas case permite executar uma sequência de instruções conforme o valor da expressão. Note que esta sequência de instruções pode ser interrompida por um break.

#include <stdio.h>

int x=1;

main ()
{
  int opcao;
  printf("Entre com uma opção (número inteiro)\n");
  scanf ("%d",&opcao);
  switch(opcao) {
  case 1:
          printf("opcao 1\n");
          break; /* o break força o encerramento da instrução*/
  case 2:
          printf("opcao 2\n");
          x++;  /* instrução demonstrativa apenas */
          printf("Note que pode existir ums lista de instruções\n");
          break;
  case 3:
          printf("opcao 3\n"); /* note o efeito de não ter o break */
  case 4:
          printf("opcao 4\n");
          break;
  case 5:
          printf("opcao 5\n");
          break;
  default:
          printf("opcao default\n");
          break;    /* a opção default é opcional */
  }

Exercício 1

Implementar um programa de calculadora onde são fornecidos via scanf dois operandos reais e uma operação que pode ser uma das 4 operações. Com auxílio de um switch deve ser computado e mostrado o resultado da operação. Solução:

#include <stdio.h>


main ()
{
  float operando1, operando2, res;
  char operador;
  
  printf("Entre com operando 1\n");
  scanf ("%f",&operando1);
  printf("Entre com operando 1\n");
  scanf ("%f",&operando2);  
  printf("Entre com operador\n");
  scanf (" %c",&operador);
    
  switch(operador) {
  case '+':
          res = operando1 + operando2;
          printf("Valor da soma = %f\n", res);
          break; 
  case '-':
          res = operando1 - operando2;
          printf("Valor da diferença = %f\n", res);
          break;
  case '*':
 		  res = operando1 * operando2;
          printf("Valor da diferença = %f\n", res); 		  
          break;
  case '/':
          if (operando2 != 0) {
 		res = operando1 / operando2;
          	printf("Valor da diferença = %f\n", res);
          } else 
          	printf("Divisão por zero não permitida!\n"); 		  
          break;  
  default:
          printf("Operação inválida!\n");
          break;
  }
}

Exercício 2

Elaborar uma função que recebe como parâmetro um número inteiro de 1 a 7. A função deve imprimir Domingo se o número é 1, Segunda se 2 etc. A função deve retornar -1 caso o parâmetro esteja fora da faixa e 0 caso contrário.

Solução:
/* contribuição do aluno Iago */
#include <stdio.h>

int operar(int x)
{
  switch(x) {
    case 1:
           printf("Domingo\n");
           break; 
    case 2:
           printf("Segunda\n");
           break;
    case 3:
           printf("Terça\n");
           break;
    case 4:
           printf("Quarta\n");
           break;
    case 5:
           printf("Quinta\n");
           break;
    case 6: 
           printf("Sexta\n");
           break;
    case 7: 
           printf("Sábado\n");
           break;        
    default:
            printf("-1\n");
            return -1; 
    }
    return 0;
} 

main()
{
 
 int num;
 printf("Entre com um número:\n");
 scanf("%d",&num);
 num=operar(num);
 printf("%d\n",num); 
 
}

Exercício 3

Um funcionário irá receber um aumento de acordo com o seu plano de trabalho, de acordo com a tabela abaixo [3]: Plano Aumento A 10% B 15% C 20% Faça um programa que leia o plano de trabalho e o salário atual de um funcionário e calcula e imprime o seu novo salário. Use o comando switch.

Exercício 4

Faça um programa que leia um número entre 0 e 10, e escreva este número por extenso. Use o comando switch.


AULA 12 DIA 28/03/2013

AULA 12 DIA 28/03/2013

Objetivos

O aluno deverá:

  • compreender o conceito de vetores;
  • definir e inicializar vetores do tipo int, float e double no C;
  • passar vetores como parâmetro (sem usar o conceito de ponteiros;

ARRAYS UNIDIMENSIONAIS (VETORES)

Um vetor pode ser visto como uma variável que pode ser indexada e onde em cada posição existe um elemento do vetor. Os elementos do vetor possuem um tipo único. Uma boa analogia é comparar o vetor com uma tabela de tamanho fixo onde em cada linha pode ser armazenado um elemento.

PROBLEMA: Ler 10 números inteiros para um vetor de inteiros. Computar um segundo vetor que é o resultado da multiplicação por um escalar inteiro 5.

DADO DE ENTRADA: Os 10 números armazenados em VET1

DADO DE SAÍDA: VET2, o vetor resultado da multiplicação de VET1 por 5.


ExplicacaoVetor1.jpg

Exercício 1: Implementar um algoritmo para ler 10 números inteiros para um vetor e imprimir o número de números acima da média. OBS: Definir um contador, iniciado em zero. Calcular a media e fazer um loop sobre o vetor testando cada item para verificar se é maior que a média.

Definindo e usando vetores no C

Um vetor pode ser facilmente definido no C da forma:

TipoVetor NomeDoVetor[dimensao];

O algoritmo do fluxograma implementado anteriormente ficaria da seguinte forma em C:

#include <stdio.h>

main()
{
  int vet1[5],vet2[5];
  int i;

  for(i=0;i<5;i++) {
     printf("Entre com vet[%d] => ",i);
     scanf("%d",&vet1[i]);
     vet2[i]=vet1[i]*5;
  }
  /* para conferir- vamos imprimir o conteúdo de vet2 */
  for(i=0;i<5;i++)
     printf("vet2[%d] => %d\n",i,vet2[i]);
}

Vamos a um exemplo que mostra as possibilidades de acesso a um vetor:

main()
{
  float x[10]; /* vetor com 10 floats */
  int i;
  x[0] = 22.5; /* colocando 22.5 na posição 0 do vetor */
  x[9] = x[0] + 2.5;
  printf("Entrar com o número na posição 5\n");
  scanf("%f",&x[5]);
  i=2;
  x[i*2]=i*1.5;        /* usando uma expressão como índice */
  
  while (i<8) {        /* usando loop para acessar o vetor */
     x[i]=0.0;
     i++;
  }
}
NOTA: vetores na Linguagem C começam SEMPRE na posição 0

Iniciando vetores em C

Pode-se iniciar um vetor da forma:

#include <stdio.h>

void main()
{
  int x[10] = {2,4,7,-5,3,2,3,4,9,10}

  printf("%d\n", x[2]);
}

Passando vetores como parâmetros

Vetores não são copiados na passagem por parâmetro. Eles são passados sempre como referência. Veja o exemplo a seguir:

#include <stdio.h>

void ler_vet(int aux[5])
{
  int i;

  for (i=0;i<5;i++) {
     printf("aux[%d] <== ",i);
     scanf("%dd",&aux[i]);
  } 
}

main()
{
   int vet[5], i;

   ler_vet(vet);
   for (i=0;i<5;i++)
      printf("vet[%d]=%d\n",i,vet[i]);
}

Note como é realizada a declaração de parâmetros que são vetores. Observe no exemplo, que o vetor aux é na realidade o próprio vetor vet. Inicialmente dados são lidos para aux e depois vet é impresso.

Não é obrigatório definir o tamanho do vetor na declaração de parâmetros. Na realidade o C não verifica o acesso indevido a um elemento fora do tamanho do vetor.

Exercícios

  1. Implementar um programa em C para ler 10 números reais (float) para um vetor. Usar o comando while.
    #include <stdio.h>
    
    main()
    {
    	float x[10];
    	int i;
    
     	i=0;
     	while (i<10) {
    		printf("Entre com x[%d] -> ", i);
    		scanf("%f",&x[i]);
     		i++;
    	}	
    }
    
  2. Modificar o exercício para computar a média dos 10 números que estão no vetor.
  3. Modificar o exercício anterior para computar a quantidade de números do vetor que estão acima da média.
#include <stdio.h>


main()
{
	float x[10];
	float soma = 0, media; 
	int i, cont;
 
	/* leitura do vetor */
 	i=0;
 	while (i<10) {
		printf("Entre com x[%d] -> ", i);
		scanf("%f",&x[i]);
		soma = soma + x[i];
 		i++;
	}	
   
	/* calculo da media */
	media = soma /10;

	/* computação de números acima da média */
	cont = 0;
 	i=0;
 	while (i<10) {
		if (x[i] > media) 
	           cont++;
		i++;
	}	
	printf ("Número de números acima da média = %d\n", cont);
}
  1. Refazer os exercícios anteriores usando o comando for;
  2. Considere um vetor global de floats chamado vetRnd de tamanho 100. Construa uma função que inicia este vetor com 100 números randômicos entre 1 e 6.
  3. Sobre o exercício anterior, acrescente uma função para imprimir o número de 0s,1s,...6s do vetor.
  4. Implementar uma função que recebe dois vetores de inteiros como parâmetro e o tamanho dos mesmos (suponha vetores de mesmo tamanho). A função deve retornar o número de elementos iguais comparados posição por posição. O esqueleto da função deve ser como:
    int compara_vetores(int ve1[],int vet2[], int tamanho)
    {
      int num_elementos;
    
      return num_elementos;
    }
    

Exemplo: Para os vetores x[]={1,1,3,4,5} e y[]={1,2,3,3,5} temos três elementos iguais (nas posições 0, 2 e 4).

AULA 14 DIA 3/04/2014

AULA 14 DIA 3/04/2014

Objetivos

  • Revisão conceito de vetores;
  • avaliação.


Exercício 1:

Implementar uma função C que recebe como parâmetros um vetor de inteiros e o tamanho do vetor. A função deve retornar a média dos números ímpares contidos neste vetor. Fazer uma função main demonstrando o uso da função.

Exercício 2: Elaborar um programa C que lê duas resistências em ohms, e uma tensão aplicada sobre eles. O programa apresenta um menu da forma:

1.Calcular potência dissipada no resistor equivalente série.

2.Calcular a potência dissipada no resistor equivalente paralelo.

3.Encerrar programa.

Usar um comando switch e um comando do while para controle de execução.


Exercício 1A:

Elaborar uma função que recebe como parâmetro um vetor de floats e o tamanho deste vetor. A função deve retornar a média de todos os números contidos no vetor que estão dentro da faixa 50.0 e 125.5 (inclusive). Construir uma função main para demonstrar o funcionamento.

Exercício 1B:

Elaborar uma função que recebe como parâmetro um vetor de floats e o tamanho deste vetor. A função deve retornar a média de todos os números contidos no vetor que estão dentro da faixa 50.0 e 125.5 (inclusive). Construir uma função main para demonstrar o funcionamento.

Exercício 2:

Elaborar um programa que lê três números inteiros e então apresenta um menu de opções:

1.Calcular a soma dos fatoriais dos números.

2.Ordenar os números de forma decrescente.

3.Sair

Usar os comandos switch e do while. Se a opção é não sair então o programa deve voltar a ler os números.



AULA 15 DIA 4/04/2014

AULA 15 DIA 4/04/2014

Objetivos

  • Vetores de char e strings
  • Processamento de Strings

Tipo Char

Em aulas anteriores vimos que um caracter pode ser representado por uma sequência de bits. Utilizando um código é possível definir o significado da sequência. Um código amplamente usado é o ASCII. Com 8 bits (7 no Ascii original) tem-se então a possibilidade de representar qualquer letra, número, ou símbolo (vírgula, ponto-e-vírgula etc). Note que um número representado em ASCII NÂO serve para realizar operações aritméticas. Trata-se de representação textual, por exemplo, um dígito de um número telefone.

Em síntese, uma 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; /* três formas de representar a mesma coisa */
 
  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");
}

Armazenamento de cadeias de caracteres em vetores

Uma cadeia de caracteres ou string nada mais é que uma sequência de caracteres ASCII. Para mantermos coerência com a linguagem C, vamos assumir que uma string bem comportada termina com um zero (0, não o caracter '0' que é o número 48 decimal em ASCII). Em inglês chama-se "string NULL terminated".

Exemplo: A string "IFSC" armazenada em um vetor CADEIA, na memória de um computador, teria a seguinte implementação:

ExplicacaoString1.jpg

Estamos assumindo que cada caracter é armazenado em um byte. Uma string terminada em 0 facilita o seu processamento pois pode-se facilmente detectar o seu final. Note que no exemplo acima, a string está armazenada em um vetor CADEIA cujo tamanho excede ao da string. Os bytes que se seguem ao zero podem ser considerados lixo.

Processando cadeias de caracteres

Sabendo como uma string é armazenada na memória de um computador torna-se fácil processá-la. Por exemplo, vamos ver um algoritmo para contar o número de caracteres de uma string lida pelo teclado para dentro de um vetor CADEIA.

FluxogramaContadorCaracteresCadeia.jpg

EXERCÍCIO 1: Colocar o procedimento acima na forma de um subprograma (função) que recebe como parâmetro o vetor e retorna um número inteiro correspondente ao tamanho da cadeia.

EXERCÍCIO 2: Elaborar um fluxograma para computador o número de ocorrências do caracter 'b' em uma string lida pelo teclado. Apresentá-lo na forma de um subprograma que retorna o número de ocorrências.

EXERCÍCIO 3: Estude a tabela ASCII e elabore um fluxograma para capitalizar todos os caracteres minusculos de uma string lida pelo teclado. Apresentá-lo como subprograma.

Vetor de Char

No C é possível definir vetores do tipo char. Tais vetores permitem definir cadeias de caracteres. Para marcar um final de cadeia usa-se o número 0 (NULL),

Exemplo:

Fazer um programa para computar o número de caracteres de uma cadeia (string) lida pelo teclado.Use o comando while.
#include <stdio.h>
void main ()
{
   char alfa[50];

   int i=0;

   printf ("Entre com a cadeia: ");
   scanf("%s",alfa);
   while(alfa[i]!=0)
	i++;
   printf ("\nNumero de caracteres em %s = %d \n", alfa, i);
}

Iniciando uma cadeia na declaração

#include <stdio.h>
void main ()
{
   char alfa[50]="IFSC-SJ";

   printf ("\nNumero de caracteres em %s\n", alfa);
}

Como passar um vetor de caracteres como parâmetro

int str_len(char x[])
{
  int i=0;
  while (x[i]!=0)
    i++;
  return i;
}

Processamento de strings

Nas aulas anteriores vimos como definir e usar vetores. Vimos que é possível armazenar strings em vetores de char. O processamento de strings é de grande interesse em programação. Vamos continuar a ver alguns aspectos deste processamento.

Computando o tamanho de uma string

A função abaixo permite computar o tamanho de uma string.

int str_len(char x[])
{
  int i=0;
  while (x[i]!=0)
    i++;
  return i;
}

main()
{
  char teste[]="IFSC-SJ";
  int tamanho;

  tamanho = str_len(teste);  
}

Copiando strings

Implementar e testar uma função que copia uma cadeia de caracteres de um vetor de strings fonte para um vetor de destino, de forma similar a função strcpy.

#include <stdio.h>

void str_cpy(char auxs1[], char auxs2[])
{
   int i;
   
   for(i=0;auxs2[i]!=0;i++) 
        auxs1[i]=auxs2[i];
   auxs1[i]=0;
}

main()
{
   char str1[100], str2[100];

   printf("Entre com a string => ");
   scanf ("%s", str2);
   str_cpy(str1, str2);
   printf("\nString copiada = %s\n", str1);
}
ou
#include <stdio.h>

void str_cpy(char auxs1[], char auxs2[])
{
   int i=0;
   
   do { 
        auxs1[i]=auxs2[i];
   }while(auxs2[i++]!=0);
}

main()
{
   char str1[100], str2[100];

   printf("Entre com a string => ");
   scanf ("%s", str2);
   str_cpy(str1, str2);
   printf("\nString copiada = %s\n", str1);
}

Concatenado strings

Da mesma forma que o exmplo anterior, implementar uma função similar a função strcat que permite concatenar duas strings passadas como parâmetro.

#include <stdio.h>

void str_cat(char auxs1[], char auxs2[])
{
   int i=0;
   
   /*localizar o final da string de destino*/
  while(auxs1[i]!=0)
            i++;

  /* usando a função de cópia já implementada temos */
  str_cpy(&auxs1[i], auxs2);
}

main()
{
   char str1[100]="IFSC em ", str2[100]="Sao Jose",  x[]="teste";

   str_cat(str1, str2);
   printf("\nString copiada = %s\n", str1);
}


Exercícios

  1. Implementar um programa que computa o número de caracteres 'a' de uma string lida pelo
  2. implementar um programa que computa o número de ocorrências das subcadeias "ab" de uma string lida pelo teclado.
  3. Implementar um programa que substitui todos os 'o' de uma cadeia por 'O.
  4. Implementar uma função chamada str_cmp que recebe duas strings como parâmetro e retona 0 se elas são iguais ou 1 se elas forem diferentes. A função é case sensitive.
  5. Implementar um programa que lê duas cadeias e conta o número de caracteres iguais ocupando a mesma posição. Exemplo: suponha as cadeias "casa" e "amora". Não existem caracteres iguais na mesma posição. Já as cadeias "casa" e "cada" possuem três caracteres iguais na mesma posição
solução
#include <stdio.h>
void main ()
{
   char alfa[50], beta[50];
   int cont;
   int i=0;
 
   printf ("Entre com a cadeia:\n");
   scanf("%s",alfa);

   printf ("Entre com a cadeia:\n");
   scanf("%s",beta);
    
   cont=0;
   while(alfa[i]!=0 && beta[i]!=0){
        if (alfa[i]==beta[i])
            cont++;
	i++;
   }
   printf ("\nNumero de caracteres iguai em %s e %s na mesma posicao é %d \n", alfa, beta, cont);
}
|}
  1. Modificar o exercício anterior para que os caracteres não iguais sejam intercambiados (mas continue respeitando os finais das cadeias). Exemplo: "casa" e "malagueta" deve resultar em "mala" e "casagueta"
  2. Implementar um programa que lê duas cadeias e imprime uma mensagem caso as cadeias seja iguais.
AULA DIA 10/04/2014

AULA DIA 10/04/2014

Avaliação:

Implementar uma fun����o que recebe duas strings, como par��metro. A fun����o deve retornar um inteiro. 1 se as duas strings come��am com a mesma letra, 2 se terminam com a mesma letra, 3 se come��am e terminam com a mesma letra, 4 nenhuma situa����o anterior.

//Implementar uma fun����o que dois char como par��metros. A fun����o deve retornar a letra mai��scula da letra passada como par��metro. Retornar -1 se o par��metro passado n��o �� letra e 1 se o par��metro passado j�� est�� na forma mai��scula. minusculo pra maiusculo, menos 1 se parametro nao for letra, se parametro passado maiuscula retorna 1


/*Implementar duas string como parâmetro. A função deve retornar um inteiro 1 se as duas strings começam com a mesma letra, 2 se terminam com a mesma, 3 se começam e terminam com a mesma letra, 4 nenhuma situação anterior*/

  • Elaborar um programa C que l�� duas resist��ncias em ohms, e uma tens��o aplicado sobre eles. O programa apresenta um menu da forma:

1.Calcular a pot��ncia dissipada no resistor equivalente s��rie. 2.Calcular a pot��ncia dissipada no resistor equivalente em paralelo 3.Encerrar programa. Usar switch e do while controle de execu����o

Implementar uma fun����o com a seguinte forma: int compara_areas(float l1,float l2,float raio) fun����o deve retornar 1 se a area do retangulo for maior que a do circulo, 2 se a area for menor, 0 se for iguais pi=3,1415


AULA DIA 11/04/2014

AULA DIA 11/04/2014

Objetivos

  • Definindo matrizes no C
  • Operações com matrizes e passagem de parâmetros tipo matriz

Como definir e operar com matrizes no C

De forma similar ao vetor, basta definir a matriz usando colchetes para indicar a dimensão da variável.

Exemplo: Definir duas matrizes 2x3 já inicializadas e computar a soma das mesmas:

#include <stdio.h>

void main()
{
  int mA[2][3]={ 11,12,13,
                 21,22,23},
      mB[2][3]={1,2,3,
                1,2,3},
      mC[2][3];
  int i,j;

  for(i=0;i<2;i++){
     for(j=0;j<3;j++) {
        mC[i][j] = mA[i][j] + mB[i][j];
     }
  }
  
}

Exercício

  1. Modificar este exercício para que a função receba um parâmetro adicional do tipo inteiro. A função deve retornar a média de todos os valores da matriz soma que estão acima do valor passado como parâmetro.
  2. implementar um programa para calcular a média de todos elementos da matriz C do exemplo acima.
    #include <stdio.h>
    
    void main()
    {
      int mA[2][3]={ 11,12,13,
                     21,22,23},
          mB[2][3]={1,2,3,
                    1,2,3},
          mC[2][3];
      int i,j, soma_ac=0;
      float media;
    
      for(i=0;i<2;i++){
         for(j=0;j<3;j++) {
            mC[i][j] = mA[i][j] + mB[i][j];
            soma_ac = soma_ac + mC[i][j];
         }
      }
      media = soma_ac/6.0;
    }
    
  3. Implementar um programa para ler uma matriz quadrada NxN pelo teclado e armazená-la em uma matriz matA. Defina matA com um tamanho máximo matA[N_MAX][N_MAX].
    #include <stdio.h>
    
    #define N_MAX 50
     
    void main()
    {
      int mA[N_MAX][N_MAX];
      int i,j,dimN;
      
      /*  Entrada da dimensão   */
      printf("Entre com a dimensao\n");
      scanf ("%d",&dimN);
      
      /*      Entrada de dados  */  
      for (i=0;i<dimN;i++) {
        for (j=0;j<dimN;j++) {
           printf("Entre com  mA[%d][%d]\n",i,j);
           scanf("%d",&mA[i][j]);  
        }
      }
      
      /* impressao dos dados lidos */
      for (i=0;i<dimN;i++) {
        for (j=0;j<dimN;j++) {
           printf("=>  mA[%d][%d] => %d\n",i,j,mA[i][j]);  
        }
      }  
    }
    


Passando matrizes como parâmetro

#include <stdio.h>


void somar_mat(int aA[][3],int aB[][3], int cC[][3])
{
  int i,j;

  for(i=0;i<2;i++){
     for(j=0;j<3;j++) {
        cC[i][j] = aA[i][j] + aB[i][j];
     }
  }
}

void main()
{
  int mA[2][3]={ 11,12,13,
                 21,22,23},
      mB[2][3]={1,2,3,
                1,2,3},
      mC[2][3];

 somar_mat(mA,mB,mC);
  
}
OBSERVE que matrizes são sempre passadas como referência.

Exercício

  1. Fazer uma função que recebe duas matrizes 2x3 como parâmetros e retorna a média entre todos elementos da matriz soma destas matrizes.
  1. Implementar uma programa para calcular o determinante de uma matriz 3x3 (de reais) a ser fornecida pelo teclado.
  2. Implementar um programa para ler duas matrizes (matA e matB) e multiplicá-las, colocando o resultado em uma matriz matC.
  3. Vamos implementar um jogo similar a batalha naval da seguinte forma.
    1. Crie uma matriz de inteiros global chamada ZonaDeGuerra com 10x10 posições (iniciada com 0). Construa uma função para gerar randomicamente a posição de 1 porta-aviões (colocando 1 na sua posição), 5 fragatas (número 2) e 5 submarinos (número 3). Assuma que a cada casa onde o inimigo alvejar será somado 10 ao número da casa.
    2. Crie um contador global de tiros iniciado com 0.
    3. Crie uma função de tiro. Esta função deve ler a posição de tiro, verificar se a casa ainda não foi alvejada. Se alvejada pergunta novamente a posição. Se a posição for válida e tiver um navio então o usuário ganha pontos da seguinte forma: 10 para o porta aviões, 5 para o submarino e 3 para fragata. A função deve retornar 0 se o jogo continua, 1 se o usuário atingiu todos os navios ou 2 se o usuário teve um número máximo de tiros ultrapassado (assumir 30 tiros).
    4. Ao final do jogo é mostrado o nome do jogador, o númerode tiros dados e a pontuação obtida.
/*
   Batalha Naval
   Versão Turma PRG2014-1-IFSC
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/**********************************/
/***** DEFINIÇÕES DESTE MÓDULO  ****/
/**********************************/

#define TAM_MAT 10
#define MAX_TIROS 30
#define MAX_NOME 30

/**********************************/
/***** VARIÁVEIS GLOBAIS **********/
/**********************************/

int ZonaDeGuerra[TAM_MAT][TAM_MAT];/* Matriz do espaço de batalha */
int ContadorTiros=0;
int PontuacaoFinal;    			   /* acumula a pontuação do jogador */
char nome[MAX_NOME];
int x_sorteado;
int y_sorteado;


/***********************************/
/****  FUNÇÕES DESTE MÓDULO ********/
/***********************************/

/***** FUNÇÕES DE INICIALIZAÇÃO ****/

void ZerarMatriz()
{
  int i,j;
  
  for (i=0;i<TAM_MAT;i++)
  	for(j=0;j<TAM_MAT;j++)
  		ZonaDeGuerra[i][j]=0;
}

void SortearCasa()
{
   do {
   		/* generate secret number: */
   		x_sorteado = rand() % TAM_MAT;
   		y_sorteado = rand() % TAM_MAT;
   } while (ZonaDeGuerra[x_sorteado][y_sorteado]!=0);
   
}

PosicionarFragatas()
{ 
  int i;
  for(i=0;i<5;i++){
  	 SortearCasa();
     ZonaDeGuerra[x_sorteado][y_sorteado]=2; 	 	 
  }
}

PosicionarSubmarinos()
{ 
  int i;
  for(i=0;i<5;i++){
  	 SortearCasa();
     ZonaDeGuerra[x_sorteado][y_sorteado]=3; 	 	 
  }
}

void PosicionarPortaAvioes()
{
 SortearCasa();
 ZonaDeGuerra[x_sorteado][y_sorteado]=1;
}

void PosicionarNavios()
{
 /* initialize random seed: */
 srand ( time(NULL) );
 
 PosicionarPortaAvioes();
 PosicionarFragatas();
 PosicionarSubmarinos(); 
}

/*** FUNÇÕES DE IMPRESSÃO NA TELA **/

void ImprimeLinha(int linha)
{
  int j;
  
  printf("     ");    
  for(j=0;j<TAM_MAT;j++) {
    printf("| %d ",ZonaDeGuerra[linha][j]); 
  }
  printf("|\n");
  printf("     +---+---+---+---+---+---+---+---+---+---+\n");
}


void ImprimeMatriz()
{
  int i;
  
  printf("     +---+---+---+---+---+---+---+---+---+---+\n");
  for(i=0;i<TAM_MAT;i++)
  	ImprimeLinha(i);
}

int Tiro()
{
}

main()
{
  ZerarMatriz();
  PosicionarNavios();
  ImprimeMatriz();
  do {
     situacao = Tiro();
  while (situacao!=0);
}



AULA DIA 17/04/2014

Objetivos

  • Matrizes com caracteres
  • Exercícios

Matrizes de caracteres e vetores de strings

Um vetor de strings pode ser construído usando matrizes de char. Cada string será armazenada em uma linha do vetor. Exemplo

#include <stdio.h>

main()
{
  char TabelaUsuarios[4][10] = {
         "joao",
         "maria",
         "jose",
         "lara",
                                };
  int i;

  for (i=0;i<4;i++)
       printf("%s\n",&TabelaUsuarios[i][0]);
}
Note a forma como é realizada a inicialização da matriz.

Exercícios

  1. Implementar um programa para "abrir uma porta" para um usuário que se encontra na tabela acima.
    #include <stdio.h>
    
    char tabelaUsuarios[4][10] = {
             "joao",
             "maria",
             "josefina",
             "lara",
    };
    
    int str_cmp(char str1[],char str2[])
    {
      int i=0;
     
      while(str1[i]!=0 && str2[i]!=0) {
         if (str1[i]!=str2[i])
            break; 
         i++;
      }
      if(str1[i]==0 && str2[i]==0) 
         return 0;
      else
         return 1;
      
    }
            
    main()
    {
    
      int i;
      char nome[10];
     
      printf("Entre com seu USERID\n");
      scanf("%s", nome);
      for (i=0;i<4;i++) {
           if (str_cmp(nome,&tabelaUsuarios[i][0])==0) {
           		break;
           }
      }
      if (i==4)
      	  printf("Usuário não existente!\n"); 
      else
          printf("abrir a porta\n");   
    }
    
  2. Implementar uma tabela adicional com senhas dos usuários. O acesso deve ser concedido somente se o usuário for validado e a senha. Defina as tabelas como variáveis globais.
  3. Implementar uma modificação do exercício anterior que permite ao programa ficar em loop até que se entre com userID igual a "fim".
  4. No exercício anterior, acrescente uma tabela de contadores que permite armazenar o número de tentativas seguidas de um usuário, no caso de erro de senha. Se o número de tentativas for maior que 3 a porta não deverá mais ser aberta para o usuário (usuário bloqueado).
  5. No exercício anterior, acrecente a figura do administrador (armazenado separadamente como user "admin" e senha "12345". Ao logar o administrador será questionado por um usuário a ser desbloqueado. O administrador entra com o usuário a ser desbloquado e o sistema volta a perguntar por um userID.


AULA 18 DIA 24/04/2014

AULA 18 DIA 24/04/2014

Objetivos

  • Definição de estruturas;
  • Estruturas como parâmetros;
  • Inicialização de estruturas;
  • Cópia de estruturas;
  • Exercícios com estruturas.

Estruturas

No C é possível criar tipos de dados que representam uma estrutura. Veja o exemplo seguinte

#include <stdio.h>

struct TUsuario /* struct TUsuario é o nome do tipo que está sendo criado */
{ 
  char userID[20];
  char senha[20];
} Usuario; /* aqui é definida uma variável do  tipo struct TUsuario */

struct TUsuario TabelaUsuario[20];

main()
{
  scanf("%s", Usuario.userId);
  scanf("%s", Usuario.senha);
  scanf("%s", TabelaUsuario[10].userID);
  scanf("%s", TabelaUsuario[10].senha);
}

Neste exemplo, foi definido um tipo (modelo) para o registro (struct TUsuario) e foi criada uma variável chamada Usuario a partir deste tipo. Na sequência foi criada mais uma variável (um vetor de estruturas) chamada TabelaUsuario. Note que basta usar as palavras chave struct Usuario para criar novas variáveis. O tipo completo é definido uma única vez no início.

Exercícios

  1. Criar um programa que define uma struct para armazenamento do nome e das notas bimestrais de um aluno. Atualizar a estrutura usando o scanf.
#include <stdio.h>

#define NUM_MAX 3

struct TAluno {
  char nome[30];
  char matricula[11];
  float b1,b2,b3,b4;
} Turma[NUM_MAX];

void print_aluno(struct TAluno aux)
{
  printf("Nome -> %s\n", aux.nome);
  printf("Matrícula -> %s\n", aux.matricula);
  printf("Bimestre 1 -> %f\n", aux.b1);
  printf("Bimestre 2 -> %f\n", aux.b2);
  printf("Bimestre 3 -> %f\n", aux.b3);
  printf("Bimestre 4 -> %f\n", aux.b4);          
}

main()
{
  int i;
  
  for(i=0;i<NUM_MAX;i++) {
  	printf("Entre com o nome do aluno\n");
  	scanf("%s", Turma[i].nome);
  	printf("Entre com a matrícula do aluno\n");
  	scanf("%s", Turma[i].matricula);
  	printf("Entre com a nota do bimestre 1\n");
  	scanf("%f", &Turma[i].b1);
  	printf("Entre com a nota do bimestre 2\n");
  	scanf("%f", &Turma[i].b2);
  	printf("Entre com a nota do bimestre 3\n");
  	scanf("%f", &Turma[i].b3);
  	printf("Entre com a nota do bimestre 4\n");
  	scanf("%f", &Turma[i].b4);
  }
  for(i=0;i<NUM_MAX;i++) {
    printf("=========== Aluno %d ============\n", i);  
  	print_aluno(Turma[i]); 
  }      
}

Estruturas dentro de estruturas

Vamos ver um exemplo com estruturas definidas dentro de estruturas:

#include <stdio.h>
  
struct TEndereco{
     char rua[50];
     char numero[10];
};

struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};

void main()
{
  struct TCidadao Cidadao;

  printf("Entre com o nome\n");
  scanf ("%s",Cidadao.nome);

  printf("Entre com o cpf\n");
  scanf ("%s",Cidadao.cpf);

  printf("Entre a rua\n");
  scanf ("%s",Cidadao.endereco.rua);

  printf("Entre a numero\n");   
  scanf ("%s",Cidadao.endereco.numero);

  printf("Entre com o número de filhos\n");
  scanf ("%d",&Cidadao.num_filhos);
  
}

Exercício 1: Faça um código adicional para imprimir o conteúdo lido na estrutura.

#include <stdio.h>
 
struct TEndereco{
     char rua[50];
     char numero[10];
};
 
struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};

void print_endereco(struct TEndereco aux)
{
  printf ("Rua %s Número %s\n", aux.rua, aux.numero); 
}

void print_cidadao(struct TCidadao aux)
{
  printf("Nome: %s CPF: %s ", aux.nome, aux.cpf);
  print_endereco(aux.endereco);
  printf("Numero de filhos %d\n", aux.num_filhos);
}

void main()
{
  struct TCidadao Cidadao;
 
  printf("Entre com o nome\n");
  scanf ("%s",Cidadao.nome);
 
  printf("Entre com o cpf\n");
  scanf ("%s",Cidadao.cpf);
 
  printf("Entre a rua\n");
  scanf ("%s",Cidadao.endereco.rua);
 
  printf("Entre a numero\n");   
  scanf ("%s",Cidadao.endereco.numero);
 
  printf("Entre com o número de filhos\n");
  scanf ("%d",&Cidadao.num_filhos);
 
}

Iniciando structs na definição

Como toda variável, é possível dar valores para uma variável do tipo struct definida no programa:

#include <stdio.h>
 
struct TEndereco{
     char rua[50];
     char numero[10];
};
 
struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};
 
void main()
{
  struct TCidadao Cidadao = {"Maria",
                             "42342342234",
                             {"Rua AlfaBeta","145"},
                             5;
                            };
 
  printf("Rua do cidadao = %s\n", Cidadao.endereco.rua);
 
}

Passando estruturas como parâmetro e retornando estruturas

Se não for usado o operador "&" , um parâmetro que é estrutura será passado por cópia. Não apresentaremos agora a passagem por endereço pois necessita do conceita de ponteiro. Observe o exercício abaixo.

#include <stdio.h>
  
struct TEndereco{
     char rua[50];
     char numero[10];
};

struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};

void print_struct (struct TCidadao aux)
{
  printf("nome=%s cpf=%s\n", aux.nome, aux.cpf);
  printf("endereço inicial do aux %p\n", &aux);
}

void main()
{
  struct TCidadao Cidadao;

  printf("Entre com o nome\n");
  scanf ("%s",Cidadao.nome);

  printf("Entre com o cpf\n");
  scanf ("%s",Cidadao.cpf);

  printf("Entre a rua\n");
  scanf ("%s",Cidadao.endereco.rua);

  printf("Entre a numero\n");   
  scanf ("%s",Cidadao.endereco.numero);

  printf("Entre com o número de filhos\n");
  scanf ("%d",&Cidadao.num_filhos);
  
  print_struct(Cidadao);

  printf("endereço inicial do Cidadao %p\n", &Cidadao);
}
O que podemos concluir com os endereços que foram mostrados??? Vamos a mais um exemplo.
#include <stdio.h>
  
struct TEndereco{
     char rua[50];
     char numero[10];
};

struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
  int num_filhos;
};

struct TCidadao ler_struct()
{
  struct TCidadao aux;

  printf("Entre com o nome\n");
  scanf ("%s",aux.nome);

  printf("Entre com o cpf\n");
  scanf ("%s",aux.cpf);

  printf("Entre a rua\n");
  scanf ("%s",aux.endereco.rua);

  printf("Entre a numero\n");   
  scanf ("%s",aux.endereco.numero);

  printf("Entre com o número de filhos\n");
  scanf ("%d",&aux.num_filhos);

  return aux;
}

void print_struct (struct TCidadao aux)
{
  printf("nome=%s cpf=%s\n", aux.nome, aux.cpf);
  printf("endereço inicial do aux %p\n", &aux);
}

void main()
{
  struct TCidadao Cidadao;

  Cidadao = ler_struct();

  print_struct(Cidadao);

  printf("endereço inicial do Cidadao %p\n", &Cidadao);
}

Copiando structs

O exemplo a seguir demonstra como se pode copiar uma variável struct para outra do mesmo tipo.

#include <stdio.h>
  
struct THoras{
   int hora;
   int minuto;
   int segundo;
};

struct THoras Ontem = {2,10,57};

void main()
{
     struct THoras Hoje;
     Hoje = Ontem;

     printf("Hora hoje = %d, Minuto hoje = %d e Segundo hoje %d\n", Hoje.hora, Hoje.minuto, Hoje.segundo);
}

Aplicação no Controle de Acesso

O exemplo a seguir implementa uma parte do programa de controle de acesso usando estruturas. Neste exemplo a tabela de usuários já vem inicializada nos campos UserID e Senha.

#include <stdio.h>
#include <string.h>
 
/**********************************************/
/*** PROGRAMA DE CONTROLE DE ACESSO  **/
/** Autor: TurmaENG.TELECOM - 2012.2 */
/**********************************************/
 
/** VARIÁVEIS GLOBAIS DESTE MÓDULO ****/

struct TRegistroUsuario {
	char UserId[10];
	char Senha[10];
};

/* Tabela de Usuários */
struct TRegistroUsuario TabelaUsuarios[4] = {
         {"joao","abcd"},
         {"maria","xxxx"},
         {"jose","yyyy"},
         {"lara","zzzz"},
};

 
char userID[20];
 
 
/** FUNÇÔES DESTE MÓDULO ****/
 
void mostrar_menu_entrada_usuario()
{
  printf("*******************************\n");
  printf("Entre com o seu USERID para ter acesso\n"); 
  printf("*******************************\n");
}
 
/** Função que implementa as tarefas do administrador **/
 
void  administrar()
{
}
 
/** Função que valida um usuário e abre a porta **/
 
void tratar_usuario()
{
  char senha[10];
  int userEncontrado=1;
  int i;
 
 
 /* 
     Loop para encontrar o usuário na tabela. 
     Ao final do loop a variavel i conterá o índice do usuário (se ele estiver
     na tabela
  */
  for (i=0;i<4 && userEncontrado; i++) {
       if( strcmp(userID, TabelaUsuarios[i].UserId)==0)
             userEncontrado=0;
  }
 
  /* se usuário encontrado abre a porta */
  if (userEncontrado==0) {
	printf("Bom dia %s! Entre com a senha\n", userID);
  	scanf("%s",senha);
	i--; /* o indice do sujeito é i-1 */
	if(strcmp(senha,TabelaUsuarios[i].Senha)==0) 
	       printf("Abrir porta!!!\n");
	else
		printf("Senha Inválida\n");
  }
}
 
void main()
{
 for(;;) {
     mostrar_menu_entrada_usuario();
     scanf("%s",userID);
     if (strcmp(userID, "admin")==0) {
          administrar();
     } else {
         tratar_usuario();
     }
 }   
}

Exercício:

  1. Implementar um contador de acesso que permita bloquear o usuário após 3 tentativas seguidas. Note que caso o usuário acerte a senha, este contador deverá ser zerado.
  2. Implementar uma funcionalidade do administrador para desbloquear o usuário bloqueado.
  3. No programa de controle de senha inserir um campo na estrutura do usuário de forma a acomodar uma mensagem de boas vindas particularizada para cada usuário. A mensagem "DEFAULT" é Bom dia!
  4. Implementar na função administrar a inserção da mensagem no exercício anterior.
  5. Na solução acima criar uma função que procura usuário na tabela (já que este código é utilizado em mais do que um luga). A função deve receber o UserID a ser procurado e deve retornar um inteiro correspondente ao índice do usuário encontrado ou -1 se não for encontrado.
AULA 19 DIA 7/05/2014

Exercícios com structs

Exercício 1

Implementar uma função converte_para_polar que recebe como parâmetro um número complexo na forma retangular (representado por uma struct). A função deve retornar uma struct contendo o número complexo na forma polar.Usar as funções sqrtf e atanf da [matemáticas biblioteca matemática]. Como converter:

ou
NOTE que as funções atanf e similares retornam em RADIANOS.

Exercício 2

Implementar um programa em C para registrar notas bimestrais de alunos de uma turma. O registro de cada aluno constará em uma tabela global RegistroAlunos. Em cada registro deve constar o nome do aluno, número de matrícula (8 dígitos), notas bimestrais. Implementar funções para: dado o nome do aluno retornar a média semestral, dado o número de matrícula retornar a média anual, dado o número de mátrícula retornar o index do aluno na tabela. Fazer um programa principal para testar as funções.
#include <stdio.h>
#define NUM_ALUNOS 40
#define TAM_MAT 10

struct TRegistroAluno{
  /* A FAZER */
};

struct TRegistroAluno TabelaNotasTurma[4] = {

   /* INICIAR DADOS AQUI PARA NÃO PRECISAR ENTRAR PELO TECLADO */
};


float media_semestral(char nome[], int semestre)
{

   /* A FAZER */

   return media;
}

float media_anual(char matricula[])
{

   /* A FAZER */

   return media;
}

int retorna_index(char matricula[])
{

   /* A FAZER */

   return i;    
}

main()
{
  /* testar as funções aqui! */
}


Exercício 3

Implementar uma tabela global usando structs que permita representar as contas bancários de pessoas físicas. Cada registro deve conter nome, cpf, endereço e o saldo atual da conta. Contas podem estar negativas. Implementar uma função que permita:

  • calcular o total contas em negativo;
  • retornar o saldo de um usuário dado o seu nome;
  • retornar o saldo de um usuário dado o seu CPF;
  • calcular o total de dinheiro do banco em função do saldo das contas
#include <stdio.h>
#include <string.h>

#define TAM_CLIENTE 40
#define TAM_CPF 60
#define TAM_END 50

struct TRegistroCliente{

  /* A FAZER */
};

struct TRegistroCliente TabelaClientes[4] = {
   /* A FAZER: INICIAR COM VALORES*/
};

float saldoTotal()
{
  /* A FAZER */
  return saldoTotal;
}

int totalContasNegativas()
{
  /* A FAZER */
  return TotalContas;
}

float saldoUsuarioPorCPF(char cpf[])
{

  return saldo;
}

float saldoUsuarioPorNome(char nome[])
{

  return saldo;
}

int main()
{
 int x;
 char cpf[TAM_CPF];
 
 while(1){

   /* FAZER MENU DE OPÇÕES */
 }
}
AULA - 20 Recuperação

QUESTÃO 1

Usando o comando for, implemente uma função da forma:

 int plot_fig(int linhas, int numcar, char caracter1, char caracter2, char caracter3)

Se a função for chamada da forma:

 plot_fig (8,9,'a','B','c');

ela deve produzir:

caaaaaaaaaB

ccaaaaaaaaaB

cccaaaaaaaaaB

ccccaaaaaaaaaB

cccccaaaaaaaaaB

ccccccaaaaaaaaaB

cccccccaaaaaaaaaB

ccccccccaaaaaaaaaB


Cada linha da figura deve ser gerada com uma função:

void printLinha(int numcar1, int numcar2, char caracter1, char caracter2, char caracter3)


Se houver inconsistência nos parâmetros retornar um código de erro -1 senão retornar 0. A inconsistência é dada por uma linha negativa ou por numcar negativo (ou ambos).

QUESTÃO 2

Implementar duas funções que operam sobre vetores de inteiros da seguinte forma:

/* calcula a média do vetor passado como parâmetro e cujo tamanho é fornceido*/

float mediaVetor(int vetor[], int tamanho)
{
}


/* esta função deve usar a função acima. Ela deve comparar a média dos vetores 
passados como parâmetro e retornar 1,0 ou -1  se a média do primeiro for maior,
igual ou menor que o segundo vetor */

int comparaMediaVetores(int vetor1[], int vetor2[], int tamanho)
{
}

main()
{
/* mostrar um exemplo de funcionamento das funções acima */
/* declare dois vetores inicializados aqui */


}

AVALIAÇÂO 5


AVALIAÇÂO 5B

#include <stdio.h>

#define NUM_FORN 3
#define NUM_PECAS 5

struct tipo_endereco{
    char rua[30];
    int numero;
    char cidade[30];
};

struct tipo_fornecedor{
     char fornID[10];
     struct tipo_endereco endereco;
};

struct tipo_peca{
     char pecaID[10];
     int  num_estoque;
     float preco;
     char fornID[10];
};

struct tipo_fornecedor fornecedores[NUM_FORN] = {
     {"alfa",{"Rua Joao da Silva",1,"Florianopolis"}},
     {"beta",{"Rua Jose Cabral",10,"Sao José"}},
     {"gama",{"Rua Manuel da Silva",30,"Palhoça"}},
};

struct tipo_peca estoque_pecas[NUM_PECAS]={
     {"A100",34,2.50,"alfa"},
     {"B100",64,5.50,"alfa"},
     {"A200",100,6.50,"beta"},
     {"B200",21,8.50,"alfa"},
     {"B300",82,10.00,"gama"},
};

/* a função retorna o número de peças em estoque relativas a um dado fornecedor */
/* a função retorna 0 se não existe peças do fornecedor */
int total_pecas_por_fornecedor (char fornID[])
{
}

/* a função dá baixa no estoque de uma quantidade de uma dada peca*/
/* a função retorna -1 se ID inválido */

int baixa_em_estoque(char pecaID[], int num_pecas)
{
}

/* a função retorna o indice (indexador na tabela de fornecedores) do fornecedor da peça, dado o ID da peça */
/* retorna -1 caso contrário pecaID inexistente */
int fornecedor_peca(char pecaID[])
{
}

/* imprime a estrutura de endereco passada como parâmetro */
void imprime_endereco(struct tipo_endereco endereco)
{
}

/* esta função imprime todos os dados de uma peça e o endereço e ID do fornecedor*/
/* ela deve usar a função imprime_endereco() */
/* retorna 0 ou -1 conforme a peça exista ou não */

int imprime_dados_peca(char pecaID[])
{
}

/* testar as funções acima aqui */
main()
{
}
AULA 21 DIA 16/5/2014

AULA 21 DIA 16/5/2014

Objetivos

Referências

[4]

[5]

[6]

[7]


Ponteiros

A memória de um computador pode ser vista como um vetor de bytes.

Cada byte possui um endereço. O tamanho da memória é definido pelo tamanho do barramento de endereços usado para acessá-la.

Uma variável ocupa uma área da memória. Tipicamente uma variável to tipo char se utiliza de um byte. Já uma variável do tipo int pode (dependendo do sistema) usar 4 bytes contíguos.

 Uma variável possui um endereço e um conteúdo (dados).


Uma variável ponteiro tem como conteúdo um endereço. Portanto a variável ponteiro possui um endereço e contém um endereço como conteúdo.

Ponteiro para inteiro

Observe o programa abaixo. A variável p é um ponteiro para inteiro. Isto significa que ela pode armazenar um endereço de um inteiro.


#include <stdio.h>

main()
{
  int x;
  int *p;

  x=5;
  printf("Valor de x antes = %d\n", x);
  
  p = &x;
  *p=10;

  printf("Valor de x depois = %d\n", x);
  printf("Valor de p = %p\n", p);
}

Observe que para se referenciar o conteúdo da posição de memória apontada por p deve-se usar o asterisco: *p

EXERCÍCIO 1: Considere o programa:

main()
{
  int x=10;
  int y, *p, *w;

}

Faça um código para copiar o conteúdo de x para y, sem que estas variáveis apareçam no lado esquerdo de um sinal de atribuição.

EXERCÍCIO 2: Tente inferir qual seria o valor da variável y no final do programa abaixo.

main()
{
  int x,y,w,*p1,*p2;
  x = 20;
  w = 30;
  p1 = &x;
  p2 = &w;
  y = *p1 + *p2;
}

EXERCÍCIO 3: Tente inferir qual seria o valor da variável y no final do programa abaixo.

main()
{
  int x,y,w,*p1,*p2, *p3;
  x = 20;
  w = 30;
  p1 = &x;
  p2 = &w;
  y = *p1 + w;
  p3 = &y;
  *p3 = *p3 + 10;
  y = *p1 + *p2 + *p3;
}

Ponteiro para char

Os ponteiro para char são muito utilizados pois permitem apontar para strings. A ideia é que ele aponte para o primeiro caracter da string. Veja o exemplo abaixo.

#include <stdio.h>

main()
{
   char x[10]="ifsc";
   char *p;

   p = &x[2];

   printf("x[2] = %c\n", *p);

   p = x;

   printf("string %s\n", p);

   while (*p!=0) {
       printf("Endereco %p conteúdo %c\n", p,*p);
       p++;
   }	
}

Neste foi usado o incremento de um ponteiro, o que implica em adicionar ao endereço armazenado em p uma quantidade relativa ao tamanho do tipo apontado. No caso é 1 (tamanho de um char é um byte).

EXERCÍCIO: Sem executar o programa abaixo, determine o valor de y no final do programa:

main()
{
   char x[10]="ifsc";
   char *p, y;
   
   p = x + 2;
   y= *p;
}

Apontando para um vetor de inteiros

Da mesma forma que usamos um ponteiro para char para apontar uma string, podemos fazer um ponteiro para int apontar para para um elemento de um vetor de inteiros.

#include <stdio.h>

main()
{
   int x[10]= {0,1,2,3,4,5,6,7,8,9};
   int *p;
   int i;
   
   p = x;

   i=0;
   while (i<10) {
       printf(" endereco %p e conteudo %d\n", p, *p);
       p++;
       i++;       
   }	
}


OBSERVE que p++ incrementa em 4 unidades.

Usando ponteiro na passagem de parâmetros

Observe como podemos usar ponteiros na passagem de parâmetros.


#include <stdio.h>

void str_cpy(char *pdest, char *pfonte)
{
   while (*pfonte!=0) {
        *pdest++ = *pfonte++;
   }
   *pdest = 0;
}


int str_len (char *p)
{
   int i=0;
   while (*p++!=0)
		i++;
   return i;
}

main()
{
   char fonte[10]="ifsc";
   char destino[10];

   str_cpy(destino, fonte);
   printf("string destino = %s\n", destino);

   printf("tamanho de dest = %d\n", str_len(destino));
}

Um ponto interessante é que ponteiros permitem, na chamada de uma função, passar valores por referência:

void alfa(int *p)
{
  *p=10;
}

main()
{
  int x;
  x =5;
  printf("Valor de x antes da chamada de alfa = %d\n", x);
  alfa(&x);
  printf("Valor de x depois da chamada de alfa = %d\n", x);
}

EXERCíCIO 1: Implementar a função str_cat que concatena duas strings usando ponteiros.


Link Aula Ponteiros UFMG

Aula dia 22/05/2014

Viagem para Porto Alegre

Aula dia 23/05/2014

Viagem para Porto Alegre

Exercícios Adicionais ponteiros

1.Implementar um programa para ler dados para dentro das variáveis x e y e somar o conteúdo das mesmas colocando o resultado em x SEM referenciar estas variáveis no scanf ou na expressão de soma.

#include <stdio.h>
main()
{
  float x,y;
}

2.Implementar uma função que compara duas strings passadas como parâmetro. A função retorna 0 se as strings forem iguais e 1 se diferentes. Usar ponteiros.

3.Implementar uma função que recebe como parâmetro o endereço de duas variáveis float que contêm a parte real e imaginária de um número complexo no formato polar (ângulo em radianos). A função deve converter do formato polar retangular colocando a coordenada x no primeira variável cujo endereço foi fornecido como parâmetro e a coordenada y na segunda variável.

void converte_polar_retang(float *parte1, float parte2)
{
}

main()
{
  float num1=1.5, num2=10.6;

  /*chamar a função aqui */

  /* imprimir os valores de num1 e num2 aqui */
}

4.Implemantar uma funçao que recebe como parâmetro o endereço de duas variáveis do tipo char e após a chamada da função os valores das variáveis devem estar maiúsculos(caso elas contenham letras minúsculas).

main()
{
  char alfa='a', beta='b';

  capitaliza(&alfa, &beta);
  
  /* aqui os valores de alfa e beta deverão ser A e B */
}

5.Implementar uma função que recebe uma string contendo uma cadeia de caracteres com dígitos numéricos e retorna o valor inteiro da string. Usar ponteiros.

int a_toi(char *p)
{
}

main()
{
  char *p="123";
  int x;

  x = a_toi(p);
  
  /* neste ponto x deve conter 123 */
}


AULA 24 DIA 29/05/2014

Objetivos

  • vetor de ponteiros;
  • argc e argv
  • ponteiros para qualquer coisa
  • ponteiros para estruturas

Vetor de ponteiros

Como visto em aulas anteiriores, variáveis ponteiros possuem como conteúdo um endereço. É perfeitamente possível construir vetores e matrizes de ponteiros. Por exemplo:


#include <stdio.h>

int main()
{
  int i;

  char *vp[4];
  char alfa[5]="IFSC";
  char beta[5]="TELE";
  char delta[5]="RAC";
  char gamma[5]="CGER";

  vp[0] = alfa;
  vp[1] = beta;
  vp[2] = delta;
  vp[3] = gamma;  

  for(i=0;i<4;i++)
	printf("%s\n", vp[i]);
}

Fig1Aula24PrgITele.jpg

Observe que vp é um vetor de ponteiros para char e cada elemento aponta para uma cadeia de caracteres.

Argumentos de linha de comando

Um bom exemplo de vetor de ponteiros é a passagem de parâmetros na linha de comando. Cada parâmetro é tratado como uma cadeia de caracteres apontada por um elemento do vetor argv. O número de parâmetros é passado em argc. Note que argv[0] aponta para uma string que inidica o nome do programa.

Exemplo: Considere o programa abaixo:

#include <stdio.h>

main(int argc, char *argv[])
{
  int i;

  for (i=0;i<argc;i++) {
       printf("%s\n", argv[i]);
  }
  printf("Numero de parametros passados = %d\n", argc-1); /* o primeiro é o nome do arquivo executavél" */
}

EXERCÍCIO 2: Implementar um programa chamado cmpcadeia que testa se duas strings passadas na linha de comando são iguais. O programa deve imprimir uma mensagem indicando se são iguais ou diferentes. Usar a função strcmp da biblioteca. Caso sejam passados mais ou menos que dois parâmetros o programa deve se encerrar mostrando uma indicão do tipo:

 cmpcadeia: dois parametros devem ser passados

EXERCÍCIO 3: Renomeie o executável e veja seja a mensagem de erro mostra o nome correto do programa.

Ponteiros para qualquer coisa

Podemos criar ponteiros para apontar para qualquer objeto na memória. Por exemplo, podemos apontar para variáveis do tipo float, double etc.

main()
{
  float a, *p;
  
  p=&a;

  *p= 5.5;
 
}

Exercício 4

Implememtar um programa que recebe 3 parâmetros na linha de comando: dois números reais e um operador (char). Operador pode ser + ou menos. O programa deve mostrar o resultado da operação. Exemplo:

 calcula 3.5 + 2.6
OBS: usar a função atof para converter string em float.  


Apontando para estruturas

Ponteiros podem apontar para qualquer "objeto" de qualquer tipo. Vamos verificar como é possível apontar para uma estrutura:

#include <stdio.h>
#include <stdio.h>
struct TRegistro {
   char nome[20];
   int idade;
} Tabela[4] = {
          {"joao",18,},
          {"maria",18,},
          {"jose",19,},
          {"lara",17,},
}
;

struct TRegistro *p;

main()
{
  p = &Tabela[3]; /*p aponta para o registro 3 da tabela */
  printf("O nome na posição 3 é %s e idade = %d\n", p->nome,p->idade);
}
Note que o uso de p->nome é uma alternativa ao uso de (*p).nome

No primeiro caso pode-se ler: o campo nome do objeto que é apontado por p.

Retornando uma estrutura em uma função

No exemplo a abaixo a função RetornarStruct() retorna um ponteiro para uma estrutura. O cuidadado que se deve ter é que a função não deveria apontar para uma estrutura que foi criada localmente na função!

#include <stdio.h>
struct TRegistro {
   char nome[20];
   int idade;
} Tabela[4] = {
          {"joao",18,},
          {"maria",18,},
          {"jose",19,},
          {"lara",17,},
}
;

struct TRegistro *p;

struct TRegistro * RetornarStruct(int indice)
{
  return &Tabela[indice];
}

main()
{
  p = RetornarStruct(2); /*p aponta para o registro 3 da tabela */
  printf("O nome na posição 2 é %s e idade = %d\n", p->nome,p->idade);
}

Passando uma estrutura como parâmetro

#include <stdio.h>
struct TRegistro {
   char nome[20];
   int idade;
} Tabela[4] = {
          {"joao",18,},
          {"maria",18,},
          {"jose",19,},
          {"lara",17,},
};

struct TRegistro *p;

void MudarStruct(struct TRegistro *p1, int indice)
{
  Tabela[indice] = *p1;
}

main()
{
  struct TRegistro aux = {"luisa",16};

  MudarStruct(&aux,2);
  p = &Tabela[2];
  printf("O nome na posição 2 é %s e idade = %d\n", p->nome,p->idade);
}

Exercício: No programa acima construir uma função que imprime a Tabela usando ponteiros. A função deve receber como parâmetro um ponteiro para o início da tabela e o tamanho da tabela.

Múltiplas indireções

#include  <stdio.h>

void main()
{
  int a, *b, **c, ***d;

  a =  3;
  b = &a;
  c = &b;
  d = &c;

  printf("Valor de a = %d\n",***d);
}
Soluções

Exercício 1

Implementação feita pela monitora de programação
#include <stdio.h>

main () {

  char opcao;
  int opr1;
  int opr2;
  int result;
  printf("Entre com a operação desejada\n");
  opcao=getchar();

  printf("Entre com o operando\n");
  scanf("%d",&opr1);

  printf("Entre com outro operando\n");
  scanf("%d",&opr2);

  switch(opcao) {
  case '+':

	  	  result=opr1+opr2;
          printf("Soma: %d\n",result);
          break; /* o break força o encerramento da instrução*/
  case '-':
	  	  result=opr1-opr2;
	      printf("Subtração: %d\n",result);
          break;
  case '*':
	  	  result=opr1*opr2;
	  	  printf("Multiplicação: %d\n",result);
          break;
  case '/':
	  	  result=opr1/opr2;
	  	  printf("Divisão: %d\n",result);
          break;

  default:
          printf("Nenhuma das operações é válida!\n");
          break;    
  }
}
Soluções

Exercício 1

Implementação feita pela monitora de programação

#include <stdio.h>

void str_cpy(char *pdest, char *pfonte)
{
   while (*pfonte!=0) {
        *pdest++ = *pfonte++;
   }
   *pdest = 0;
}

void str_cat(char *destino, char *origem){
	while(*destino!=0){
		destino++;
	}
	while(*origem!=0){
		*destino++=*origem++;
	}
	*destino=0;
}


int str_len (char *p)
{
   int i=0;
   while (*p++!=0)
      i++;
   return i;
}


main()
{
   char fonte[10]="ifsc";
   char destino[10];

   str_cpy(destino, fonte);

   printf("string destino = %s\n", destino);

   str_cat(destino, "alunos");

   printf("string destino = %s\n", destino);
   printf("tamanho de dest = %d\n", str_len(destino));
}

EXERCÍCIO 2

Código implementado pela monitora de programação

#include <stdio.h>

main(int argc, char *argv[])
  {
        int comp;
          if((argc-1)>2){
                  printf("cmpcadeia: dois parametros devem ser passados\n");
           }else{
                comp=strcmp(argv[1],argv[2]);
                if(comp==0){
                        printf("palavras iguais\n");
                }else{
                        printf("palavras diferentes\n");
                }
          }
}


Conteúdo extendido

Exercícios

Exercício 1

Implementar uma função que recebe dois números complexos no formato retangular e retorna a soma dos mesmos no formato polar. Os parâmetros são passados por referência (usar ponteiro). Demonstre o funcionamento no programa main.

struct TComplexoRet {
  float x;
  float y;
};

struct TComplexoPolar {
  float mod;
  float ang;
};

struct TComplexoPolar conv_polar(struct TComplexoRet *p1, struct TComplexoRet *p2)
{
}
obs: é possível retornar um ponteiro para uma estrutura??

Exercício 2

Implemente uma função usando ponteiros que recebe duas strings como parâmetro e retorna o número de vezes que a segunda string está contida na primeira. Use a função da biblioteca strcmp() como apoio.


#include <string.h>

int conta_sub_strings(char *p1, char *p2)
{
}

Exercício 3

Seja um vetor de inteiros x definido globalmente. Implemente uma função para ler dados para este vetor, dado o endereço inicial do mesmo e o tamanho. Imprima na função main o vetor. Usar ponteiros no acesso ao vetor.

int x[10];

void ler_vetor(int *p, int tamanho)
{
}

Exercício 4

Implemente uma função que recebe uma string como parâmetro. Esta string contém um número inteiro. A função deve retornar um inteiro no formato int. Obs: é uma reimplementação do atoi da biblioteca.

AULA 26 DIA 5/6/2014

AULA 26 DIA 5/6/2014

Objetivos

  • anatomia de um programa em execução;
  • alocação dinâmica de memória.

A área de heap e o layout de memória de um programa C

Neste link podemos ter uma ideia da anatomia de um programa na memória do computador.

http://shivacherukuri.blogspot.com.br/2011/03/memory-layout-in-cdata-segmentbss-code.html

Podemos observar que existe as seguintes áreas:

  • TEXT: área onde está o código;
  • BSS: dados estaticamente alocados e não inicializados;
  • DATA: dados estaticamente alocados e inicializados;
  • STACK: área de pilha (variáveis locais);
  • HEAP: área de dados alocados dinamicamente.

Quando declaramos uma variável global da forma:

 int x;

a variável x é alocada em uma área chamada BSS (dados não incializados). Note que x possui uma área de memória reservada a ela (4 bytes) e cuja existência é o tempo de vida do programa em execução.

Da mesma forma, uma variável global da forma:

 int y=10;

é alocada na área de DATA. A inicialização é definida normalmente na carga do programa. Os valores de inicialização são copiados para a área de DATA na carga do programa, a partir do arquivo executável.

Por vezes, o tamanho dos dados não são conhecidos antes da execução do programa. Neste caso, pode ser interessante criá-los dinamicamente e é neste ponto que entra a área de HEAP. Trata-se de uma área de memória, gerenciada a partir de funções da biblioteca do C.

As funções mais conhecidas são (http://en.wikipedia.org/wiki/C_dynamic_memory_allocation):

http://www.linuxjournal.com/article/4681 http://www.cs.cmu.edu/~guna/15-123S11/Lectures/Lecture08.pdf

Exemplo 1: Alocação dinâmica de números inteiros (exercício puramente didático):

#include <stlib.h>

main()
{
  int *px, *py;
  int resultado;
  px = (int *) malloc(sizeof(int));
  *px = 5;
  py = (int *) malloc(sizeof(int));
  *py = 2;
  resultado = *px + *py;

  free (px);
  px = NULL;
  free (py);
  py = NULL;
}

Alocando uma estrutura

#include <stdio.h>
#include <stdlib.h>
 
void main()
{
  struct TTeste{
     int x;
     int y;
  };
  
  struct TTeste *teste;
  

  
  teste = (struct TTeste *) malloc (sizeof(struct TTeste));
  if (teste==NULL) {
      printf("erro de alocação");
      exit(1);
  }
  
  teste->x=10;
  
  free(teste);
  
  teste=NULL;
  
}

Usando o typedef para ajudar na definição e declaração de estruturas

#include <stdio.h>
#include <stdlib.h>
 
void main()
{
  typedef struct {
     int x;
     int y;
  } TTeste;
  
  TTeste *teste;
  

  
  teste = (TTeste *) malloc (sizeof(TTeste));
  if (teste==NULL) {
      printf("erro de alocação");
      exit(1);
  }
  
  teste->x=10;
  
  free(teste);
  
  teste=NULL;
  
}

Alocando dinamicamente uma tabela de estruturas

#include <stdio.h>
#include <stdlib.h>

void main()
{
  struct TTeste{
     int x;
     int y;
  } *teste;

  if ((teste = (struct TTeste *) malloc (100*sizeof(struct TTeste)))==NULL) {
      printf("erro de alocação");
      exit(1);
  }



  teste[10].x= 5;

  if ((teste = realloc(teste, 10000*sizeof(struct TTeste)))==NULL) {
      printf("erro de alocação");
      exit(1);
  }

  teste[9000].x=20;
  free(teste);

}

Exercício:

Refazer o exemplo anterior para que a quantidade de memória a ser alocada pela tabela seja passada na linha de comando.

AULA 27 DIA 6/6/2014

AULA 27 DIA 6/6/2014

Listas Ligadas

Por vezes não se conhece o tamanho dos dados que se vai manipular e o uso de uma lista pode ser conveniente para armazená-los. Um sistema de estoque de produtos, por exemplo, poderia ser armazenado na forma de uma lista. O exercício a seguir explora esta estrutura.

Exercício de lista ligada

#include <stdlib.h>
#include <stdio.h>

/*========================*/
/** OPERAÇÔES COM LISTA LIGADA ******/
/*========================*/

/*
   tipos e variáveis globais
*/

struct TProduto{
   int codigo;
  struct TProduto *next;
} *head, *tail;


/*
   adiciona item a cabeça da lista
   retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_head(int codigo)
{

}

/*
   adiciona item ao final  lista
   retorna 0 se tudo ok e -1 se erro
*/
int add_nodo_tail(int codigo)
{
   struct TProduto *p =  malloc (sizeof(struct TProduto));
   if (!p)
        return -1;

   p->codigo = codigo;
   p->next = NULL;

   if (tail==NULL) {
      /* lista vazia */
      tail = head = p;
   }else {
     /*lista não vazia */
       tail->next = p;
       tail = p;
   }
   return 0;
}

/*
   imprimir lista 
*/

void print_list()
{

}
 
main()
{
  int i;

  head = tail = NULL;
  print_list ();
  for (i=0;i<5;i++)
     add_nodo_tail(i);

  print_list ();
}

Lição para casa

  • Implementar a função add_node_head()
  • Implementar a função print_list
  • Implementar a função delete_node(int codigo)
AULA 28 DIA 13/6/2014

AULA 27 DIA 13/6/2014

Exercícios

Exercício 1

Considere um sistema de estoque de uma livraria representado por uma tabela conforme abaixo. Elabore as funções para adicionar, remover e listar um livro na/da tabela. Considere que uma entrada livre possui o ponteiro titulo igual a NULL.

#include <stdio.h>
#define TAM 10
 
 
struct tLivro {
  char *titulo;
  char *autor;
  char *isbn;
  float *preco;
  int  estoque;
};
 
 
typedef struct tLivro TLivro;
 
TLivro Livros[10]; /* iniciar a tabela com NULL */
 
 
 
TLivro *retornar_entrada_livre()
{
}
 
int adicionar_livro()
{
 char aux_isbn[20];
 TLivro *p;

 /* Ler ISBN */
 if(verificar_livro_existe(aux_isbn)==1)
    return 0;
 if((p=retornar_entrada_livre())==NULL)
    return -1;
 
 /* Ler os dados do livro pelo teclado e colocar na estrutura 
    apontada por p*/
 
}
 
/* retorna 0 se removido com sucesso e -1 caso contrário */
int remover_livro(char *isbn)
{
}
 
void imprimir_dados_livro(char *isbn)
{
}
 
main()
{
 /* testar as funções aqui */
}

Exercício 2

Refazer o exercício anterior usando filas.

Mais exercícios

Exercício 1

Seja a seguinte estrutura:

struct tipo_carro {
   char *marca;
   char *modelo;
   int  potencia;
};

typedef tipo_carro tcarro;


Implpementar as funções abaixo:

/* cria dinamicamente uma estrutura,
   preenche os dados dos campos
   e retorna um ponteiro para a estrutura criada
   Retorna NULL caso não consiga alocar área
 */
tcarro *ler_carro()
{
}

/*
  recebe dois ponteiros para estruturas do tipo carro e
  retorna -1 caso pelo menos um dos ponteiros seja NULL,
  retorna 0 se os modelos forem iguais
  e retorna 1 se os modelos forem diferentes */
int compara_modeloa(tcarro *p1, tcarro *p2)
{
}

/* libera a área da estrutura passada como parâmetro */
void deleta_estrutura(tcarro *p)
{
}

main()
{
  /*testar as funções aqui */
  /* criar dois carros */
  /* comparar o modelo dos dois carros. Testar o retorno */
  /* liberar a área das estruturas */
}


AULA X DIA 26/06/2014

AULA XX DIA 26/06/2014

Objetivos

  • Tratamento de arquivos no C
  • O sistema de arquivos no Linux
  • O acesso com funções de alto nível

O sistema de arquivos no Linux

O Arquivo

Um arquivo é um conjunto de dados que pode ser referenciado por um nome e pode ter outros atributos tais como: permissão para leitura e escrita, data da criação, data da última modificação etc.

Note que um arquivo pode conter dados (um relatório, por exemplo), um programa C, um programa executável, música, fotos etc. Seja qual for a natureza dos dados o armazenamento será na forma de bits.

Normalmente, arquivos são armazenados em memórias secundárias, tais como CD, hard disk etc, mas eles podem se armazenados na memória principal também (RAM, FLASH).

Quanto a forma como os dados são armazenados, podemos dizer que os arquivos são binários ou texto. Qualquer um deles armazena bits mas os bytes de um arquivo texto representam códigos ASCII.

Sistema de Arquivos

Um sistema tal como o Linux possui milhares de arquivos. Para que arquivos possam ser acessados e armazenados de forma consistente, eles são organizados em um sistema de arquivos.

Tipicamente, um sistema de arquivos ocupa uma área de um disco (ou mídia de armazenamento). Nesta área ficam armazenados blocos de armazenamento dos dados dos arquivos e também as estruturas chamadas de inodes.

Um inode é um estrutura que possui as propriedades do arquivo e ponteiros para os blocos que contém os dados do arquivo. Tipicamente um sistema de arquivos possui uma lista de inodes que permite "indexar" cada um dos arquivos do sistema de arquivos.

Existem vários formatos de sistema de arquivos, dependendo do sistema operacional. No linux os formatos mais conhecidos são: ext2, ext3, ext4 etc.

Um sistema de arquivos normalmente possui uma estrutura de dados inicial chamada de superbloco. O superbloco traz informações sobre o tamanho de blocos do sistema, o início da lista de inodes (/), etc.

+-------------+-----------------+------------------------+

lista de inodes | blocos dos arquivos |

+-------------+-----------------+------------------------+ </syntaxhighlight>


Diretórios

São arquivos especiais que contém basicamente uma lista contendo nome e inode correspondente dos arquivos que o diretório contém.

Em um sistema de arquivos, o diretório / é o diretório raiz do sistema, a partir do qual pode-se encontrar todos os demais arquivos.

Referência a um arquivo

A localização de um arquivo pode ser realizada pela referência absoluta, ou seja, desde o diretório / do sistema:

cat /etc/passwd

O comando cat tem por objetivo mostrar no terminal o conteúdo do arquivo passwd. Para que este arquivo seja encontrado na árvore de diretórios, deve-se fornecer a referência absoluta, desde o diretório /

Uma alternativa de acesso, é o uso da referência relativa ao diretório de trabalho. O conceito de diretório de trabalho é criado pelo interpretador de comandos (shell). Desta forma pode-se por exemplo fazer o comando:

cat passwd

O sistema procurará o arquivo passwd dentro do diretório de trabalho, que é referenciado armazenado pelo shell. Neste caso, o diretório de trabalho deveria ser /etc

cd /etc
cat passwd
No Linux/Unix tudo é arquivo

No Linux, qualquer referência/acesso ao hardware/dispositivos é realizada na forma de acesso a arquivo. Ver arquivos no diretório de dispositivos:

 ls -l /dev

Como consequência, a partir de um programa em C, é possível abrir e escrever/ler em um dispositivo (desde que se tenha autorização).

Acessando arquivos a partir de programas C

Acesso a arquivos: funções de baixo e alto nível

Em sistemas do porte do Linux e Windows, por questões de segurança e controle, todo acesso a arquivo é realizado através de código do sistema operacional. Desta forma, um programa que deseja acessar um arquivo deve gerar uma CHAMADA AO SISTEMA. O Linux (assim como outros sistemas) possui uma API (Application Programming Interface) bem definida, na forma de um conjunto de chamadas que permitem realizar uma série de funcionalidades (serviços) para os processos(programas em execução).

Um programa em C realiza uma CHAMADA AO SISTEMA com auxílio de funções da biblioteca C (a glib no caso do Linux). Duas categorias de funções para acesso a arquivo são disponibilizadas (ver detalhes aqui):

  • Funções de baixo nível: acessam diretamente o sistema;
  • Funções de alto nível: as funções intermediam o acesso, criando buffers no espaço de endereçamento do processo. As funções de baixo nível são invocadas para ler e escrever dados no buffer.

Acesso a arquivo em MODO TEXTO através de funções de alto nível

O acesso em alto nível é realizado usando uma estrutura do tipo FILE definida no stdio.h. Todo acesso passa inicialmente por abrir o arquivo (função fopen), ler/escrever (várias funções, tipo fread(), fwrite()) e fechar o arquivo (fclose()).


Exemplo 1: Escrevendo e lendo um arquivo texto de forma formatada

Nos exemplos que se seguem, serão usadas as funções fopen e fclose, para abrir e fechar arquivo e fprintf() e fscanf() para leitura e escrita. A forma é similar ao printf e scanf(ver http://diuf.unifr.ch/pai/ip/tutorials/c/TC02_scanf.pdf), a não ser pelo fato de que a escrita e leitura é realizada no arquivo indicado por p_arq

#include <stdio.h>

void main()
{
  FILE *p_arq;
  int i;
  int res;

  if ((p_arq=fopen("IFSC.txt", "w")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     return;
  }

  for (i = 0; i<10;i++) {
  /* A funcao fprintf devolve o número de bytes gravados  ou EOF se houve erro na gravação */
      if((res = fprintf(p_arq,"Linha %d\n",i))==EOF) {  					  	    
	         printf("Erro\n");
			   break;
      }
  }
  fclose(p_arq);
}
Note que se o arquivo IFSC.txt não existir, ele será criado.

Para ver o que fois escrito faça:

cat IFSC.txt
#include <stdio.h>

void main()
{
  FILE *p_arq;
  int i,j;
  int res;
  char buff[100];

  if ((p_arq=fopen("IFSC.txt", "r")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     return;
  }

  for (i = 0; i<10;i++) {
      if((res = fscanf(p_arq,"%s %d",buff,&j))==EOF) {  					  	    
	         printf("Fim de leitura\n");
			   break;
      }
      printf("%s %d\n",buff,j);
  }
  fclose(p_arq);
}

Note que o fscanf se comporta de forma similar ao scanf. A função retorna o caracter EOF (end-of-file) quando não existe mais dados a serem lidos.

  • Exercícios
  1. Implementar uma função que soma duas matrizes fornecidas em dois arquivos texto separados: MatA.dat e MatB.dat. Colocar o resultado em um arquivo chamado MatC.dat.
#include <stdio.h>
 
void main()
{
  FILE *p_arq;
  int i,j,res;
  float MatA[5][5], MatB[5][5], MatR[5][5];
  
  /* Ler a matriz MatA do arquivo */
  if ((p_arq=fopen("MatA.dat", "r")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     return;
  }
  
  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
      	if((res = fscanf(p_arq,"%f",&MatA[i][j]))==EOF){  					    
	         printf("Fim de leitura\n");
			 break;
      	}
      	printf("%f ",MatA[i][j]);
      }
      printf("\n");
  }
  fclose(p_arq);
  
  /* Ler a matriz MatB do arquivo */

  printf("\n\n");
      
  /* Ler a matriz MatB do arquivo */
  if ((p_arq=fopen("MatB.dat", "r")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     return;
  }
  
  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
      	if((res = fscanf(p_arq,"%f",&MatB[i][j]))==EOF){  					    
	         printf("Fim de leitura\n");
			 break;
      	}
      	printf("%f ",MatB[i][j]);
      }
      printf("\n");
  }
  fclose(p_arq);
    
  /* Calcular a soma das matrizes e colocar resultado em MatR */

  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
      	MatR[i][j]=MatA[i][j]+MatB[i][j];
      }
  } 
  printf("Resultado da Adição\n"); 
  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
          printf("%f ", MatR[i][j]);  
      }
      printf("\n");      
  }  
  /* Armazenar MatR em arquivo */

  if ((p_arq=fopen("MatR.dat", "w")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     return;
  } 
  
  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
         if((res = fprintf(p_arq,"%f ",MatR[i][j]))==EOF) {  					    
	         printf("erro\n");
			 break;
      	 }
      }
      fprintf(p_arq,"\n");
  }
  fclose(p_arq);       
}

Exemplo2

Neste exemplo usaremos as funções fgetc e fputc para ler e cescrever caracteres ASCII nos arquivos. Seja um programa que conta o número de ocorrências do caracter 'a' em um arquivo e reescreve o arquivo sem os "as":

#include <stdio.h>
#include <stdlib.h>
main()
{
   FILE *fp_fonte,*fp_destino;
   int x,cont=0;
                   
   if((fp_fonte=fopen("teste.dat","r")) == NULL) {
		puts("Não conseguiu abrir o arquivo\n");
		exit(1);
   }
   if((fp_destino=fopen("dest.dat","w")) == NULL){
		puts("Não conseguiu abrir o arquivo\n");
		exit(1);
   }

   /* note que fgetc retorna um inteiro contendo o ASCII lido */
   while ((x=fgetc(fp_fonte)) != EOF){
      if(x=='a')
         cont++;
      else
	 if((x=fputc(x,fp_destino))==EOF) {
		puts("Não conseguiu abrir o arquivo\n");
		exit(1);
	 }	
   }	
   printf("ocorrências de a = %d\n", cont);
   fclose(fp_fonte);
   fclose(fp_destino);
}
Note que fputc recebe o caracter como um inteiro mas realiza um cast para
unsigned char com fins de escrevê-lo no arquivo.

Exemplo 3

Neste exemplo vamos explorar o modo de abertura do arquivo para fazer um append (escrever no final do arquivo).

#include <time.h>
#include <stdio.h>
 
int main(void)
{
   time_t ltime;
   FILE *fp;
   int num;

   time(&ltime); 

   if ((fp=fopen("DATA.txt", "a")) == NULL) {
       printf("Problemas na abertura do arquivo\n");
       return;
   }
   if ((num = fputs( ctime(&ltime), fp )) != EOF ) {
       fclose(fp);
   } else {
       printf("Erro na escrita do arquivo!\n");
   }
}

Execute o programa da forma (suponha que se chame LOG_tempo:

 log_tempo
 cat DATA.txt
 log_tempo
 cat DATA.txt
 log_tempo
 cat DATA.txt  
 
  • Exercício: Substitua o modo de append por uma simples escrita (w). Reexecute o programa conforme especificado anteriormente.

Ainda funções de acesso a arquivos

A localização corrente do acesso a um arquivo pode ser modificada antes de uma leitura ou escrita. Tipicamente, quando se abre uma arquivo para leitura/escrita, o "cursor" de acesso é 0, ou seja início do arquivo. Se o arquivo for aberto em modo append, o "cursor" é posicionado no final. A cada acesso (leitura ou esrita), este cursor é incrementado conforme o número de dados lidos ou escritos.

É possível entretanto modificar a posição deste cursor, tipicamente com as funções fseek() e rewind(). (ver http://www.gnu.org/software/libc/manual/html_node/File-Positioning.html#File-Positioning)

Considere o programa abaixo que escreve um vetor de 100 inteiros em um arquivo.

#include <stdio.h>

int x[100];

void main()
{
  FILE *fp;

  fp = fopen("teste.dat","w");
  x[0]=32;
  x[90]=11;
  fwrite(x, sizeof(int),100,fp);
  fclose(fp);
}

Note que o vetor, sendo uma variável global não inicialiazada, será zerado pelo procedimento de startup do programa. Entretanto, a posição 90 recebe um valor (11).

Agora observe o programa seguinte que lê especificamente a posição 90 e na sequência restabelece o cursor no início. Note que o fread lê somente um inteiro na posição corrente do arquivo. A posição corrente foi determinada por fseek e depois retornada para o início com rewind.


#include <stdio.h>

int y;

void main()
{
  FILE *fp;

  fp = fopen("teste.dat","r");
  fseek(fp, 90*sizeof(int), SEEK_CUR);
  fread(&y, sizeof(int),1,fp);
  printf("y=%d\n", y);
  rewind(fp);
  fread(&y, sizeof(int),1,fp);
  printf("y=%d\n", y);
  fclose(fp);
}

Execício

Considero o programa abaixo. Ele deve acessar uma tabela que se encontra em um arquivo binário. Cada item da tabela se apresenta conforme o registro TRegistro. Implemente a função LerTab e crie um programa para escrever uma tabela iniciada com um tabela de 5 registros a fim de testar a função implementada.

#include <stdio.h>

struct TRegistro {
  char nome[30];
  int idade; 
} Registro, *pAux;

struct Tregistro *LerTab()
{
}

void main()
{
  pAux=LerTab(3);
  if (pAux!=0) {
      printf("Nome lido %s\n", pAux->nome);
  }
}
Conteúdo extendido

Exercício: Considere o sistema abaixo para controle de estoque de peças. Implementar as funções indicadas abaixo.

#define FIM 5

typedef struct ttipo tipo_peca;

struct ttipo{
  int codigo;
  char descricao[100];
  int estoque;
  float preco;
  tipo_peca *proximo;
};

tipo_peca *inicio=NULL;

/* prototipos de funções */
void listar();
void inserir_nova_peca();
void remover_peca();
void apresentar_menu();

main()
{
  int opcao;  
  do {
    apresentar_menu();
    scanf("%d", &opcao);
    switch(opcao) {
    case 1: listar();
            break;
    case 2:
            inserir_nova_peca();
            break;
    case 3:
            remover_peca();
            break;
    case 4:
            //listar_peca_especifica();
            break;
    case 5: //atualizar_estoque_peca();
            break;
    default:
            break;
    } 
  } while(opcao!=FIM);
}
 
void listar()
{
 tipo_peca *p;
 
 p=inicio;
 while(p!=NULL){
    printf("Peca de Codigo %d\n", p->codigo);
    p=p->proximo;
 }
}

void inserir_nova_peca()
{
 tipo_peca *p;

 if ((p=malloc(sizeof(tipo_peca)))==NULL) {
    printf("Não é possível criar peça\n");
    return;
 }
 printf("Entre com o codigo");
 scanf("%d", &p->codigo);
 printf("Descrição");
 scanf("%s", p->descricao);
 
 
 /* inserir no topo da fila */
 p->proximo = inicio;
 inicio = p; 

}

void remover_peca()
{
 int codigo;
tipo_peca *p,*aux_p;


 printf("Entre com o código da peça a ser removida\n");
 scanf("%d", &codigo);
 p=aux_p=inicio;
 while(p!=NULL) {
    if (p->codigo == codigo) {
       if (p==inicio) {
           inicio=inicio->proximo;
       } else {
           aux_p->proximo=p->proximo;
       }
       free(p);
       break;   
    } else {
       if (p!=inicio) {
          aux_p=aux_p->proximo; 
       }
       p=p->proximo;
    }    
 } 
}

void apresentar_menu()
{
  printf("1-Listar 2-Inserir 3-Remover 5-FIM\n");
}

2-Melhorar a implementação anterior fazendo a descrição da peça ser um ponteiro para caracter.

3-Melhorar a função de inserção de nova peça para evitar acrescentar um peça cujo código já esteja sendo usado.

4-Ampliar o sistema acrescentando uma lista de fornecedores. Um fornecedor deve ter um identificador. Uma peça possui um único identificador.

5-Implemente um programa que recebe dois parâmetros na linha de comando. Um caracter e uma string. O programa deve mostrar a quantidade de vezes que o caracter aparece na string. Exemplo:

conta A ALFA
A -> 2 vezes

Note o primeiro argumento é recebido como string, Testar se esta string possui um único caracter.


Conteúdo extendido

Questão 1

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIM 5

typedef struct t_visitante tipo_visitante;

struct t_visitante {
  char *nome;
  int  apto;
  char *data_hora;
  tipo_visitante *proximo;
};





/* protótipos de funções */
void listar_visitantes_apto();
void listar_visitantes();
void retirar_visitante_fila();
void inserir_visitante_fila();
char *data_hora();

 
main()
{
  int opcao;  
  do {
    printf("1-Listar por apto 2-Retirar 3-Inserir 4-Listar todos 5-FIM\n");
    scanf("%d", &opcao);
    switch(opcao) {
    case 1: listar_visitantes_apto();
            break;
    case 2:
            retirar_visitante_fila();
            break;
    case 3:
            inserir_visitante_fila();
            break;
    case 4:
            listar_visitantes();
            break;
    default:
            break;
    } 
    printf("Data e hora: %s\n", data_hora());
  } while(opcao!=FIM);
}


void listar_visitantes_apto()
{
}
 
void listar_visitantes()
{
}

void retirar_visitante_fila()
{
}

void inserir_visitante_fila()
{
}

/*retorna ponteiro para uma string alocada com malloc contendo data e hora */
/* função já  implementada retorna NULL se não conseguir alocar área para a string*/
char *data_hora()
{
  char *p,*p1;
  time_t ltime;
  time(&ltime);
  p1=ctime(&ltime);
  if ((p=(char *)malloc(strlen(p1)+1))!=NULL)
      strcpy(p,p1);
  return (p);
}

Questão 2

Implementar um programa que recebe na linha de comandos números inteiros e operadores da forma:

 operar 12  35  34  67 +

O programa de computar o resultado da operação indicada ao final. A operação pode ser '+', '-' ou 'x' É aceitável qualquer número de parâmetros.

Prova 2

Questão 1

Sistema de controle de estacionamento. Implementar funções associados a um sistema de controle de estacionamento.

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIM 5

typedef struct t_carro tipo_carro;

struct horas {
    int hora;
    int minuto;
  };
  
struct t_carro {
  char *dono;
  char *placa;
  struct horas *entrada;
  tipo_carro *proximo;
};


/* protótipos de funções */
void listar_carro_por_hora();
void listar_carros();
void retirar_carro_estac();
void inserir_carro_estac();
struct horas *hora_atual();

 
main()
{
  int opcao;
  struct horas *p;
  
  do {
    printf("1-Listar por placa 2-Retirar 3-Inserir 4-Listar todos 5-FIM\n");
    scanf("%d", &opcao);
    switch(opcao) {
    case 1: listar_carro_por_hora();
            break;
    case 2:
            retirar_carro_estac();
            break;
    case 3:
            inserir_carro_estac();
            break;
    case 4:
            listar_carros();
            break;
    default:
            break;
    } 
    /* exemplo de uso da função hora */
    p=hora_atual();
    printf("Hora %d minuto %d\n", p->hora, p->minuto);
    free(p);
  } while(opcao!=FIM);
}


/* lista carros que entraram entre uma dada hora de entrada e de saida */
void listar_carro_por_hora()
{
}
 
void retirar_carro_estac()
{
}

void inserir_carro_estac()
{
}

void listar_carros()
{
}

struct horas *hora_atual()
{
   time_t rawtime; 
   struct tm *tminfo; 
   struct horas *p;
   
   time ( &rawtime ); 
   tminfo = localtime ( &rawtime );
   
   if((p=(struct horas *)malloc(sizeof(struct horas)))==NULL)
      return NULL;
   p->hora = tminfo->tm_hour;
   p->minuto = tminfo->tm_min;
   
   return p;   
}

Questão 2

Implementar um programa que recebe na linha de comandos números inteiros e operadores da forma:

 operar 12 + 35 - 34 + 67

O programa deve computar o resultado da expressão passada como argumento na linha de comando. A operação pode ser '+' e '-'. É aceitável qualquer número de parâmetros. Suponha que o usuário sempre fornece os dados de forma correta.

Solução:

#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[])
{
  int i,numero,soma=0;
  char operador;
  
  operador = '+';
  for (i=1;i<argc;i++) {
     printf("%d %s\n",i,argv[i]);
     if (i%2==1) {
        numero = atoi(argv[i]);
        if (operador == '+')
        	soma = soma + numero;
        else
            soma = soma - numero;
     } else {
        operador = *(argv[i]);
     }
  }
  printf("Resultado = %d\n", soma);
}
Conteúdo extendido

Questão 1

Implemente as funções indicadas abaixo. Trata-se de um sistema de registro de notas bimestrais de alunos usando lista ligada. O sistema permite inserir e remover alunos.O sistema permite também inserir notas bimestrais e listar alunos abaixo da média em um boimestre

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIM 5



struct t_endereco {
  char rua[40];
  int numero;
};

typedef struct t_aluno tipo_aluno;


struct t_aluno {
 char *nome;
 struct t_endereco endereco;
 float bim1, bim2, bim3,bim4;
 tipo_aluno *proximo;
};

/* protótipos de funções */
void listar_alunos_abaixo_media()
void inserir_nota_bimestre();
void retirar_aluno_fila();
void inserir_aluno_fila();


main()
{
 int opcao;  
 do {
   printf("1-Listar abaixo media  2-Inserir Bim  3-Retirar 4-Inserir 5-FIM\n");
   scanf("%d", &opcao);
   switch(opcao) {
   case 1: listar_alunos_abaixo_media();
           break;
   case 2:
           inserir_nota_bimestre();
           break;
   case 3:
           retirar_aluno_fila();
           break;
   case 4:
           inserir_aluno_fila();
           break;
   default:
           break;
   } 
 } while(opcao!=FIM);
}

/* lista todos os alunos com media anual abaixo da m?dia da turma*/ 
void listar_alunos_abaixo_media()
{
}

/* permite inserir para cada aluno a sua nota bimestral - a fun??o deve solciitar o bimestre */
void inserir_nota_bimestre()
{
}

/* retira um aluno dado a matricula */
void retirar_aluno_fila()
{
}

/* inserir aluno - registra o aluno e seu endere?o*/
void inserir_aluno_fila()
{
}

Questão 2

Implementar um programa que recebe na linha de comandos números inteiros da forma:

operar 12  35  5  67 MAIOR 10

ou

operar 12  35  34  67 98 MENOR 30

O programa deve computar o número de números que são maiores ou menores que o último número - conforme a operação indicada.