Mudanças entre as edições de "PRG29002 - Programação I - Eng.Telecom 2016-1"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Linha 1 119: Linha 1 119:
 
|'''Matrícula''' ||L1 || D1 || L2 || L3 || L4 || L5 || T7 || T8
 
|'''Matrícula''' ||L1 || D1 || L2 || L3 || L4 || L5 || T7 || T8
 
   |-
 
   |-
| 151002039-0 || 10 || 0 || 0 || 0 || 8 || 0 ||  ||  
+
| 151002039-0 || 10 || 6 || 0 || 0 || 8 || 0 ||  ||  
 
   |-
 
   |-
 
| 152000674-8 || 0 || 10 || 0 || 0 || 0 || 0 ||  ||  
 
| 152000674-8 || 0 || 10 || 0 || 0 || 0 || 0 ||  ||  
Linha 1 125: Linha 1 125:
 
| 151001400-4 || 0 || 0 || 0 || 0 || 0 || 0 || 0 || 0
 
| 151001400-4 || 0 || 0 || 0 || 0 || 0 || 0 || 0 || 0
 
   |-
 
   |-
| 152000542-3 || 10 || 0 || 8 || 10 || 10 || 9 ||  ||  
+
| 152000542-3 || 10 || 10 || 8 || 10 || 10 || 9 ||  ||  
 
   |-
 
   |-
 
| 152001576-3 || 6 || 10 || 3 || 0 || 10 || 10 ||  ||  
 
| 152001576-3 || 6 || 10 || 3 || 0 || 10 || 10 ||  ||  
Linha 1 131: Linha 1 131:
 
| 151006902-0 || 0 || 10 || 0 || 0 || 0 || 0 ||  ||  
 
| 151006902-0 || 0 || 10 || 0 || 0 || 0 || 0 ||  ||  
 
   |-
 
   |-
| 151005163-5 || 0 || 0 || 0 || 0 || 0 || 0 ||  ||  
+
| 151005163-5 || 0 || 6 || 0 || 0 || 0 || 0 ||  ||  
 
   |-
 
   |-
 
| 151005591-6 || 10 || 10 || 9 || 9 || 10 || 9 ||  ||  
 
| 151005591-6 || 10 || 10 || 9 || 9 || 10 || 9 ||  ||  
Linha 1 137: Linha 1 137:
 
| 151003419-6 || 8 || 0 || 3 || 10 || 6 || 0 ||  ||  
 
| 151003419-6 || 8 || 0 || 3 || 10 || 6 || 0 ||  ||  
 
   |-
 
   |-
| 152000616-0 || 10 || 0 || 0 || 0 || 8 || 0 ||  ||  
+
| 152000616-0 || 10 || 10 || 0 || 0 || 8 || 0 ||  ||  
 
   |-
 
   |-
 
| 152000226-2 || 6 || 10 || 0 || 0 || 0 || 0 ||  ||  
 
| 152000226-2 || 6 || 10 || 0 || 0 || 0 || 0 ||  ||  
Linha 1 151: Linha 1 151:
 
| 152000120-7 || 10 || 0 || 7 || 10 || 9 || 4 ||  ||  
 
| 152000120-7 || 10 || 0 || 7 || 10 || 9 || 4 ||  ||  
 
   |-
 
   |-
| 152006025-4 || 10 || 0 || 5 || 10 || 7 || 0 ||  ||  
+
| 152006025-4 || 10 || 10 || 5 || 10 || 7 || 0 ||  ||  
 
   |-
 
   |-
 
| 152000331-5 || 8 || 10 || 3 || 9 || 10 || 10 ||  ||  
 
| 152000331-5 || 8 || 10 || 3 || 9 || 10 || 10 ||  ||  

Edição das 12h18min de 9 de junho de 2016

Professor da Disciplina: Cleber Jorge Amaral
e-mail: cleber.amaral@ifsc.edu.br

Critérios e instrumentos de avaliação

  • Conceito => Somatório(Nota)/QtNotas
    • Esta é uma previsão, eventuais mudanças serão comunicadas no decorrer das atividades
    • Nota[1]: Nota da Avaliação 1 (a definir data e formato)
    • Nota[2]: Nota da Avaliação 2 (a definir data, formato e necessidade desta segunda avaliação)
    • Nota[3]: Média das notas das Listas de exercícios
    • Nota[4]: Nota do Projeto final
  • Frequência
    • Mínimo 75%

Datas importantes

  • 13/04/2016
    • Lista de exercícios 1: Entregar por e-mail ou manuscrito
    • Desafio 1 (projeto de cafeteira): Entregar por e-mail ou manuscrito a Narrativa, Fluxograma e Pseudocódigo
  • 20/04/2016
    • Lista de exercícios 2: Entregar por e-mail (seguir instruções) ou manuscrito
    • Lista de exercícios 3: Entregar por e-mail (seguir instruções) ou manuscrito
      • O estudante deve entregar na forma de fluxograma cada desafio que resolvemos na aula de 13/04 na forma de pseudocódigo, e devem ser entregues na forma de pseudocódigo os fluxogramas que fizemos em sala -
      • Os títulos dos algoritmos são citados na mídia 1.3 (link abaixo) mas os detalhes foram trabalhados em sala e fotografados pelos próprios alunos
  • 27/04/2016
    • Lista de exercícios 4: Entregar por e-mail (seguir instruções) ou manuscrito
  • 11/05/2016
    • Lista de exercícios 5: Entregar por e-mail (seguir instruções)
  • 17/05/2016
    • Prova 1: Algoritmos e lógica utilizando pseudocódigo e fluxogramas
  • 25/05/2016
    • Lista de exercícios 6: Entregar via moodle
  • 28/05/2016
    • Desafio 2 (jogo da velha): Entregar via moodle
  • 08/06/2016
    • Lista de exercícios 7: Entregar via moodle (atraso nos 6 primeiros dias contarão -1)
  • 14/06/2016
    • Apresentação das propostas de projeto final
  • 22/06/2016
    • Prova 2: Prática
  • 26 e 27/07/2016
    • Avaliação 3: Apresentação do projeto

Material de aula

Inauguração

Introdução aos Algoritmos e Pseudocódigo

Programação em C

Introdução

Controle de fluxo

Funções

Variáveis e operadores

Exercicios complementares - Vetores
  1. Implementar um programa em C para ler 10 números reais (float) para um vetor. Usar o comando while.
  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.
  4. Refazer os exercícios anteriores usando o comando for;
  5. 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.
  6. Sobre o exercício anterior, acrescente uma função para imprimir o número de 0s,1s,...6s do vetor.
  7. 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).

Variáveis locais e Globais
  • Se variáveis são declaradas dentro de uma função, então a visibilidade (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.
    • 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.
         #include <stdio.h>
         float media; /* Variável GLOBAL */
        
         void media_nums(float num1, float num2)
         {
           media = (num1 + num2)/2;
           return;
         }
        
         main()
         {
           float aux1, aux2; /* Variáveis LOCAIS */
        
           printf("\nEntre com numero 1: ");  
           scanf ("%f",&aux1);
        
           printf("\nEntre com numero 2: ");  
           scanf ("%f",&aux2);
        
           media_nums(aux1, aux2);
           printf ("\nmedia dos 2 numeros é %f\n", media);
         }
        
  • 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:
    • NOTE agora que a função media_nums() retorna um float, podemos utilizar este retorno no contexto em que a função foi chamada que é o que ocorre dentro do printf abaixo
    • NOTE também que MESMO que a função retorne um valor, não é obrigatório que este valor este sendo recebido por alguma variável, uma função que possui retorno e este retorno não está sendo recebido se comportará como um procedimento (sem retorno).
    • OBS.: Variáveis LOCAIS e GLOBAIS podem ter o mesmo nome. A variável LOCAL terá preferência no uso.
      #include <stdio.h>
       
      float media_nums(float num1, float num2)
      {
         float media_local;
       
         media_local = (num1 + num2)/2;
         return media_local;
      }
       
      int main()
      {
         float media, aux1, aux2;
         printf("\nEntre com numero 1: ");  
         scanf ("%f",&aux1);
       
         printf("\nEntre com numero 2: ");  
         scanf ("%f",&aux2);
       
         media = media_nums(aux1, aux2);
         printf ("\nmedia dos 2 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2));
      }
      
Gerando números pseudo-aleatórios
  • Computadores executam instruções, portanto, não são realmente capazes de criar números aleatoriamente. Porém existem artifícios de se criar números que variam conforme determinadas condições como sequencias variáveis associadas a data e hora atual por exemplo, a isso chamamos de números pseudo aleatórios. Para conseguir este recurso em C podemos utilizar a função rand() da stblib associada a função srand que configura uma semente de aleatoriedade a função rand, o resultado pode ser conferido no código a seguir:
    #include <stdlib.h>
    #include <time.h>
    #include <stdio.h>
    
    int main(void) {
    
        srand( (unsigned)time(NULL) );
        printf("Numero gerado: %d\n", rand() % 10); //Gera números que variam de 0 a 9
    
        return 0;
    }
    
Tabela ASCII
  • Os computadores armazenam todos os tipos de dados na forma numérica, incluindo letras. Para apresentar textos em tela neste caso o programa em C precisa conhecer o tipo de dado que está escrito em memória, sendo um dado do tipo caractere (ou string) ele será então tratado como uma letra. O conjunto de letras, números e símbolos imprimíveis está sintetizado na tabela ASCII.
    • Para ver a tabela, acesse o link Tabela ASCII
    • Observe que as letras maiúsculas variam de 65 ('A') até 90 ('Z')
    • Observe também que as letras minúsculas estão em outra faixa, variam de 97 ('a') até 122 ('z')
    • Os números imprimíveis também tem seus representantes, variam de 48 ('0') a 57 ('9')
    • Caracteres especiais como '$', '%', '*', '+' também estão relacionados na tabela
    • A tabela também apresenta códigos de caracteres não imprimíveis como o 9 (TAB), 13 ('\r' presente no ENTER)
    • Para representações de outros caracteres pode ser necessário acessar a extensão da tabela ASCII, podendo-se obter 'Ç' e caracteres acentuados
    • A tabela que está sendo apresentada esta em acordo com o padrão ISO 8859-1 e Microsoft® Windows Latin-1, outros caracteres podem ainda ser obtidos se alterado o padrão de codificação
Dicas para resolução dos exercícios da lista 7
  • Dicas para resolução dos exercícios da lista
    1. Uma forma de resolver é criando dois vetores de inteiros (ex.: l1[26] e l2[26]). Então, recebidas as palavras 1 e 2, inicia-se a decomposição da palavra 1. Em um laço, para cada 'A' ou 'a' encontrado incrementamos uma vez o l1[0], para cada 'B' ou 'b' incrementamos l1[1] e assim por diante. O mesmo será feito com a palavra 2 em outro laço. Na prática, se a letra que está sendo analisada for maiúscula (pela tabela ASCII de 65 a 90, o índice de "lx" que deve ser incrementado é letra-65, e se form minúscula é letra-97). O resultado será dois vetores contendo a quantidade de vezes que a letra se repetiu. Um terceiro laço compara l1[0] com l2[0] e assim por diante. Havendo qualquer divergência, NÃO é um anagrama. Para simplificar solicite ao usuário para digitar palavras sem acentos (algoritmos com tratamento de palavras acentuadas terão bônus).
    2. Para resolver basta criar um laço para checar cada caractere, se o usuário solicitou converter para maiúsculas, por exemplo, e a letra que está sendo indicada no laço está entre 97 e 122, então basta subtrair de 32 o valor da letra que esta será convertida para maiúscula. Se a letra já está entre 65 e 90, não precisa alterar. Para criar as funções faça antes a prototipagem, facilitará a codificação.
    3. A solução deste é muito parecida com o primeiro exercício, porém este pede que o programa seja capaz de tratar maiúsculas e minúsculas juntas. Então, basta fazer uma "normalização" primeiro, que é o processo do exercício 2, por exemplo, converta tudo para maiúscula primeiro e depois faça a contagem, isso garante que maiúsculas e minúsculas sejam tratadas da mesma forma.
    4. Para este exercício é sugerido criar um vetor char nomes[n][10], sendo 10 o tamanho máximo de um nome e 'n' a quantidade de alunos que é variável. Crie então um outro vetor de float notas [n][5] onde 5 são as notas. O programa então começa solicitando a quantidade de alunos gravando em 'n'. Depois recebe nomes e notas. Pode-se utilizar uma variável de apoio para computar o índice do aluno com a maior nota que será no final do processo impresso. Durante o calculo das médias já pode-se imprimir os alunos que ficaram em recuperação.
    5. Para resolver este, utilize as instruções presentes nesta página da wiki. Atente-se que para se obter um número de 1 a 60, um jeito fácil é pegar o resto da divisão por 60 do resultado de rand(), porém o resultado desta matemática será um número de 0 a 59, então no final basta somar com 1 para se obter entre 1 e 60. Para garantir que os 6 números sejam distintos pode-se criar um laço while que dentro está a geração do randômico e teste se este número já está presente no vetor de int numeros[6], se sim, basta não incrementar a variável de apoio e retornar ao início do laço para que um novo número seja gerado.
Obtendo o código de um caractere UTF-8
Para obter o código UTF-8 de um caracter especial (retorno 0xC3) é necessário executar um segundo scanf, conforme exemplo:
#include <stdio.h>

int main()
{   
  unsigned char c;
  printf("Digite um caracter especial ou não:\n");
  //Primeiro scanf
  scanf("%c", &c);
  //Se for um caracter especial
  if(0xC3 == c)
  {
    //Segundo scanf para obter segunda codificação deste char UTF8
    scanf("%c", &c);
    printf("Digitado um caracter especial: 0x%x\n",c);
  }
  else
  {
    printf("Digitado um caracter convencional: 0x%x\n",c);
  }  
  return 0;
}
Estruturas
Estruturas

Assim como o vetor a estrutura é um conjunto de dados, mas traz uma vantagem: a possibilidade de possuir "campos" de diferentes tipos de variáveis. Por exemplo, a struct TPessoa poderia ter os campos nome (char[40]) e idade (int).

A declaração genérica da estrutura é:

struct TNome_do_tipo {
  //variável 1
  //variável 2
  //variável N
} nome_instancia;
  • Convencionalmente damos ao tipo da estrutura um nome "TNome_do_tipo", onde "T" representa Tipo e a letra seguinte também vem em maiúscula
  • nome_instancia representa a instancia de variável (do tipo struct) que será alocada em memória, esta declaração também pode ser um vetor "nome_instancia[10]", por exemplo
  • Em uma declaração é necessário ao menos definir um dos parâmetros "TNome_do_tipo" ou "nome_instancia são opcionais"


#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.
  2. Alterar o programa para que ele calcule e imprima a média de cada aluno.
#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]); 
  }      
}
Copiando Estruturas

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);
}
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);
  
}
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];
     int numero;
};
 
struct TCidadao{
  char nome[50];
  char cpf[20];
  struct TEndereco endereco;
};
 
int main(void)
{
  //Inicializando com parâmetros em sequencia (ordem tem que ser respeitada)
  struct TCidadao CidadaoMaria = {"Maria","42342342234",{"Rua AlfaBeta",145}};
  //Inicializando com parâmetros via campo (não é necessário respeitar qualquer ordem)
  struct TCidadao CidadaoJose = {.cpf = "1234567890", .endereco.numero = 541,.nome = "Jose",.endereco.rua = "Rua GamaDelta"};

  printf("Rua do cidadao %s = %s\n", CidadaoMaria.nome, CidadaoMaria.endereco.rua);
  printf("Rua do cidadao %s = %s\n", CidadaoJose.nome, CidadaoJose.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);
}
Exercícios
  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.
Unions
Union é um recurso do C que permite declarar um conjunto de dados que irá ocupar um mesmo espaço. É bastante empregado quando se deseja economizar espaço ou não se tem certeza sobre qual tipo de dado deve ser armazenado para determinada instancia. No exemplo a seguir é criada uma struct chamada TProduto e dentro destra estrutura há uma área de detalhamento do produto que é de uso genérico, para alguns produtos há campos específicos para preenchimento e outros não se tem ao certo os detalhes, portanto fica um campo de uso geral.
 
#include <stdio.h>

struct TRoupeiro{
  char cor[20];
  int volume;
  float peso;
};

struct TProduto{
  int id;
  char nome[20];
  union {
    struct TRoupeiro roupeiro;
    char descricao_generica[sizeof(int)+sizeof(float)+20];
  };
};
 
int main(void)
{
  struct TProduto vaso_decorativo = {
      .id = 2,.nome = "Vaso decorativo 1",
      .descricao_generica = "em vidro - peça única"
  };
  
  struct TProduto guarda_roupas_solteiro = {
      .id = 1,.nome = "Roupeiro 3 portas",
      .roupeiro.cor = "CZ", .roupeiro.volume = 304,.roupeiro.peso = 50.0
      
  };
  printf("nome=%s, descrição=%s, cor=%s, volume=%d, peso=%f\n", 
        guarda_roupas_solteiro.nome, 
        guarda_roupas_solteiro.descricao_generica,
        guarda_roupas_solteiro.roupeiro.cor,
        guarda_roupas_solteiro.roupeiro.volume,
        guarda_roupas_solteiro.roupeiro.peso
  );
  printf("nome=%s, descrição=%s, cor=%s, volume=%d, peso=%f\n", 
        vaso_decorativo.nome, 
        vaso_decorativo.descricao_generica,
        vaso_decorativo.roupeiro.cor,
        vaso_decorativo.roupeiro.volume,
        vaso_decorativo.roupeiro.peso
  );
}
  • Observe que a union é feita de duas entre uma struct e um vetor de caracteres. O autor neste código criou este vetor baseado no tamanho que ocupa a struct aproveitando todo o espaço já alocado, porém o C não exige que os dados ocupem o mesmo espaço, neste caso a alocação ocorrerá em relação a maior estrutura.
  • Observe que ao imprimir os valores da instancia "guarda_roupas" o "descricao_generica" apesar de não ter sido formalmente preenchido, foi indiretamente preenchido quando no caso "roupeiro.cor" recebeu um valor. Como este valor foi "Cinza" o C escreveu um "\0" no final da string "roupeiro.cor" que acabou também servindo como final da string "descricao_generica", por isso neste print ambos os campos apresentam o mesmo valor. Porém observe também que os valores de "volume" e "peso" estão perfeitamente preservados.
  • Agora foi interessante o cado da instancia "vaso_decorativo", ela foi descrita pelo campo "descricao_generica" e apenas para fins didáticos o autor imprimiu o que teria dentro de "roupeiro.cor", "roupeiro.volume" e "roupeiro.peso". Neste caso cairam valores oriundos da constante "em vidro - peça única" que não passam de sujeira neste contexto.

Ponteiros

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 abaixo:
main()
{
  int x=10;
  int y, *p;

}

Complete o código para copiar o conteúdo de x para y, sem que qualquer variável apareçam no lado esquerdo de um sinal de atribuição. Ou seja, sem envolver diretamente x e y.

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;
}
EXERCÍCIO 4
Qual seria o valor das variáveis y e x no final do programa abaixo:
#include <stdio.h>

void main()
{
	int x,y;
	int *p;
	y=0;
	p=&y;
	x=*p; 	
	x=4; 	
	(*p)++;	
	x--;	
	(*p) += x; 
	printf("\ny=%d x=%d\n",y,x);
}
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 (char) 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);
}


Ponteiros para ponteiros

Um ponteiro para um ponteiro é como se você anotasse o endereço de um ponteiro na agenda que tem o endereço da casa do seu amigo. Pode-se declarar um ponteiro para ponteiro com a seguinte notação:


tipo_da_variavel **nome_da_variavel_ponteiro;


Sendo que o **nome_da_variavel_ponteiro é o conteúdo final da variável apontada, e *nome_da_variavel_ponteiro é o conteúdo do ponteiro intermediário.

NOTE: Na linguagem C pode-se declarar ponteiros para ponteiros para ponteiros para ponteiros... e assim por diante.

#include <stdio.h>

void main()
{
	float fpi=3.1415, *pf, **ppf;
	pf=&fpi;		// pf armazena o endereco de fpi
	ppf=&pf;		// ppf armazena o endereco de pf
	printf("\n%f", **ppf);	// imprime o valor de fpi por ppf
	printf("\n%f", *pf);	// imprime o valor de fpi por pf
}

NOTE: Para acessar o valor apontado por um ponteiro para ponteiro, o operador asterisco deve ser aplicado duas vezes.


Vetor de ponteiros

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

EXEMPLO
Veja o programa abaixo:
#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 indica o nome do programa.

EXEMPLO
Teste 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" */
}
Apontando para estruturas

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

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

Exercícios

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

EXERCÍCIO 2: Ordenar valores de um vetor de inteiros passando por referencia o ponteiro para esse vetor.

EXERCÍCIO 3: 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
para usar a função atof para converter string em float.

EXERCÍCIO 4: 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 5: Renomeie o executável e veja seja a mensagem de erro mostra o nome correto do programa.

Referências Complementares

http://pw1.netcom.com/~tjensen/ptr/ch1x.htm http://eternallyconfuzzled.com/tuts/languages/jsw_tut_pointers.aspx http://duramecho.com/ComputerInformation/WhyCPointers.html http://boredzo.org/pointers/ Link Aula Ponteiros UFMG

Os argumentos argc e argv

Os argumentos argc e argv

Os argumentos argc e argv

A função main() pode ter parâmetros formais, mas o programador não pode escolhores quais serão eles. A declaração que se pode ter para a função main() é: int main (int argc, char *argv[]); Exemplo Escreva um programa que faça uso dos parâmentros argv e argc. O programa deverá receber da linha de comando o dia, mês e ano correntes (dd/mm/aaaa), e imprimir a data em formato apropriado. Veja o exemplo, supondo que o executável se chame data: $ data 07 06 2016 O programa deverá imprimir: $ 07 de junho de 2016

  1. include <stdio.h>
  2. include <stdlib.h>

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

int mes;

 char *nomemes [] = {"janeiro","fevereiro","março","abril","maio","junho","julho","agosto","setembro","outubro","novembro","dezembro"};

 if(argc == 4) /* Testa se o numero de parametros fornecidos esta' correto o primeiro parametro e' o nome do programa, o  segundo o dia  o terceiro o mes e o quarto os dois ultimos algarismos do ano */
 {

mes = atoi(argv[2]); /* argv contem strings. A string referente ao mes deve ser transformada em um numero inteiro. A funcao atoi esta sendo usada para isto: recebe a string e transforma no inteiro equivalente */

 	if (mes<1 || mes>12) /* Testa se o mes e' valido */

printf("Erro!\nUso mes: mm, deve ser de 1 a 12.\n");

 	else

printf("\n%s de %s de %s\n\n", argv[1], nomemes[mes-1],argv[3]);

 }
 else 

printf("Erro!\nUso: dd/mm/aaaa, devem ser inteiros, ou estão faltando.\n"); }

Referências importantes

Ferramentas úteis

  • VisualG3: Uma IDE para desenvolvimento de programas em pseudocódigo (freeware), permite editar e compilar programas utilizando uma sintaxe própria de pseudocódigo muito parecida com a que trabalhamos em sala. Muito útil para verificar o funcionamento real dos algoritmos.
  • LibreOffice: O LibreOffice é um programa gratuito (freeware) e de código aberto (opensource). Além de editor de textos, planilhas e apresentações tem a ferramenta Draw que permite a criação de fluxogramas.
  • VirtualBox: O Oracle VirtualBox é um programa gratuito (freeware) que permite criar e instanciar máquinas virtuais. O uso de máquinas virtuais é bastante interessante quando desejamos ter diferentes sistemas operacionais em um computador bem como quando se está realizando ensaios e deseja-se isolar estes experimentos do sistema principal.
  • Ubuntu: O Ubuntu é uma distribuição linux (freeware e opensource) bastante estável e com uma comunidade bastante ativa que está sempre atualizando o sistema e presente nos foruns e redes sociais para dirimir dúvidas.
  • LinuxMint: O LinuxMint é uma distribuição linux (freeware e opensource) bastante estável e confortável aos usuários windows, pois traz um gerenciador de janelas configurado de uma forma mais natural para estes usuários e vem com um conjunto de programas pré-instalados que consegue atender a maior parte das demandas inicias.

Orientações para entrega dos trabalhos

  • Para listas a serem entregues via moodle:
    • Nome do arquivo: "seu nome completo/ demais colegas do grupo" - "lista de exercícios 1", "desafio 1", etc.
    • Formato do arquivo em anexo: PDF (cada lista num único arquivo feito em editor de texto, exportado para PDF).
  • Para listas a serem entregues por email (para cleber.amaral@ifsc.edu.br), período válido até a meia noite do prazo:
    • Assunto do e-mail: "PRG29002 - xxx" onde xxx é "lista de exercicios 1", "desafio 1", etc.
    • Nome do arquivo anexo: "seu nome completo/ demais colegas do grupo" - "lista de exercícios 1", "desafio 1", etc.
    • Formato do arquivo em anexo: PDF (cada lista num único arquivo feito em editor de texto, exportado para PDF).
      • Regra válida a partir de 14/04 (isento apenas trabalhos "lista 1")

Trabalhos entregues com atraso

  • Para os trabalhos não entregues no prazo (não justificados) temos a penalidade de 1 ponto por dia de atraso
    • Excepcionalmente para as lista1 e lista7 com até 6 dias de atraso terá desconto de 1 ponto apenas, seguindo a regra acima para entregas deste trabalho após este prazo
    • Desafios não tem extensão de prazo, não adianta enviar se o prazo se esgotou
      • Para o desafio1 o sistema de desconto por dia de atraso foi utilizado, este ficou como exceção

Eventos da área de desenvolvimento

Horário de Monitoria

Sites úteis

  • cplusplus.com: Traz tutoriais, artigos e descrições de funções C e C++
  • codechef.com: Permite a edição, compilação e testes online de códigos em várias linguagens inclusive ANSI C
  • codecademy.com: Tem cursos gratuitos de programação, bastante didáticos em inclusive em português. Porém não tem curso de C, uma alternativa interessante para quem quiser aprender uma outra linguagem que tem boa aceitação inclusive para desenvolvimento de sistemas embarcados é o Python
  • kaggle.com: Site tem publicado centenas de algoritmos em diversas linguagens para resolver os mais variados problemas. Tem também competições de algoritmos

Projeto

O aluno deve propor ao professor um projeto de sua preferência que respeite os requisitos mínimos. Sendo aceito deverá desenvolver o projeto e apresentá-lo.

Requisitos mínimos

  • Realizar acesso a arquivo, lendo e escrevendo informações
  • Utilizar funções (ao menos duas sendo ao menos uma com argumentos)
  • Apresentar menu utilizando switch case e conter laço infinito
  • Aceitar argumento de entrada no programa
  • Utilizar comentários
  • Utilizar alguma biblioteca (além da stdio.h)
  • Utilizar ao menos 3 dos seguintes recursos
    • Utilizar diretivas de pré-compilação
    • Utilizar Ponteiros
    • Utilizar Structs ou Unions
    • Utilizar alocação dinâmica de memória

Modelo

  • Trabalho individual

Metodologia

  1. Apresentar a proposta de projeto ao professor
  2. Documentar o escopo do projeto utilizando descrição narrativa (descrição simples)
    1. Cenário
    2. Problema
    3. Dados de entrada e saída
    • O planejamento do cronograma não será cobrado porém cabe ao aluno se organizar quanto ao tempo para entrega no prazo
  3. Desenvolver o projeto
  4. Apresentar individualmente ao professor
    • Serão realizados testes diversos, arguido sobre o funcionamento, possibilidades de alterações, etc

Algumas ideias de projetos

  • Sugestão geral: veja em outras disciplinas que processos podem ser automatizados e proponha um projeto que realiza esta tarefa como de cálculos diversos de eletrônica, de rádio transmissão, etc.
  • Implementar o jogo Pedra, papel ou tesoura. Neste jogo dois ou mais jogadores em diferentes computadores devem rodar um aplicativo que fará a leitura de um arquivo compartilhado. O algoritmo deve tratar as etapas do jogo (Setup do aplicativo, entrada na sala, escolha da figura e apresentação do resultado)
  • Implementar o jogo da velha escrevendo em arquivo. Neste jogo dois jogadores em diferentes computadores devem rodar um aplicativo que fará a leitura de um arquivo compartilhado. O algoritmo deve tratar as etapas do jogo (Setup do aplicativo, entrada na sala, seleção das casas e apresentação do resultado)
  • Implementar controle de empréstimo de objetos. Neste software o usuário poderá digitar nomes de objetos que emprestou, a pessoa a quem emprestou e automaticamente o software guarda a data. Deve haver uma opção para gerar relatório dos itens emprestados e opção para marcar a devolução (podendo manter o registro em histórico ou apagando o registro).
  • Implementar software gerador de lista de compras. Neste software o usuário poderá digitar itens de supermercado com nome e quantidade. O software escreve num arquivo que poderá depois ser impresso. O software também pode ter função de numa segunda execução já trazer a antiga listagem digitada e permitir que o usuário apenas selecione novas quantidades ou inclua novos itens.
  • Implementar software para realização de cálculos de eletrônica. Neste software um menu apresenta várias opções de cálculo como de potencia através de tensão e corrente, como obtenção do valor de um resistor, como solução de equivalência de paralelo de vários resistores e outras. Num arquivo texto pode ser armazenado um histórico de operações realizadas.
  • Implementação de software para apostas na mega sena. Neste software são dadas sugestões de números para apostas de acordo com o número do sorteio da mega sena. Com este histórico armazenado é possível então entrar com um número de sorteio e digitar quais foram os números verdadeiramente sorteados na loteria federal checagem os acertos.

Turma Conceitos Numéricos

Conceitos Individuais - Avaliações principais

Conceitos
Matrícula A1
151002039-0 6
152000674-8 0
151001400-4 0
152000542-3 8
152001576-3 9
151006902-0 3
151005163-5 10
151005591-6 4
151003419-6 0
152000616-0 0
152000226-2 8
152000502-4 4
152001502-0 5
151001656-2 4
152000293-9 7
152000120-7 6
152006025-4 8
152000331-5 5

Consolidação - Avaliações principais

Consolidação
Conceito A1
10 5%
9 5%
8 16%
7 5%
6 11%
<=5 / Ausentes 55%


Conceitos Individuais - Avaliações secundárias

Conceitos
Matrícula L1 D1 L2 L3 L4 L5 T7 T8
151002039-0 10 6 0 0 8 0
152000674-8 0 10 0 0 0 0
151001400-4 0 0 0 0 0 0 0 0
152000542-3 10 10 8 10 10 9
152001576-3 6 10 3 0 10 10
151006902-0 0 10 0 0 0 0
151005163-5 0 6 0 0 0 0
151005591-6 10 10 9 9 10 9
151003419-6 8 0 3 10 6 0
152000616-0 10 10 0 0 8 0
152000226-2 6 10 0 0 0 0
152000502-4 10 10 7 4 9 5
152001502-0 10 10 10 10 8 8
151001656-2 10 10 6 9 9 9
152000293-9 10 10 4 0 9 10
152000120-7 10 0 7 10 9 4
152006025-4 10 10 5 10 7 0
152000331-5 8 10 3 9 10 10

Turma Conceitos por Letras

Conceitos Individuais - Avaliações principais

Conceitos
Matrícula A1
142003344-1 D
141005012-2 0
142001814-0 D
142001213-4 D
142002143-5 B
142001834-5 0
142003393-0 0
142001425-0 0
132005743-8 D
121003322-4 X

Consolidação - Avaliações principais

Consolidação
Conceito A1
A 0%
B 10%
C 0%
D 40%
Ausentes 50%

Conceitos Individuais - Avaliações secundárias

Conceitos
Matrícula L1 D1 L2 L3 L4 L5 T7 T8
142003344-1 C A D X X X
141005012-2 X X X X X X
142001814-0 A X C C C X
142001213-4 C A X D X B
142002143-5 C A X X B C
142001834-5 X X X X X X
142003393-0 X X X X X X
142001425-0 X X X X X X
132005743-8 X X X X X X
121003322-4 X C X X X X

Critério de conversão Numérico x Letra

  • A: 9,0 a 10,0
  • B: 7,5 a 8,9
  • C: 6,0 a 7,4
  • D: 0,0 a 5,9