Sistemas Operacionais e Introdução a Programação (diário 2009-2)

De IF-SC São José

Ir para: navegação, pesquisa

Tabela de conteúdo

Sistemas Operacionais

27/07: NÃO HOUVE

29/07: NÃO HOUVE

03/08: NÃO HOUVE

05/08: NÃO HOUVE

10/08: História dos Sistemas Operacionais e das Linguagens de Programação

12/08: Usuários e Grupos

Atividades

17/08: Processos

19/08: Sistemas de Arquivos

Atividades

24/08: Linguagens de Programação

26/08: Revisão de Sistemas Operacionais

Assumindo como cenário o sistema operacional GNU/Linux para auxiliar nas respostas.

Pelo fato de o sistema prover um ambiente multi-usuário, é preciso que haja limites para cada um dos usuários desse sistema, não só para controlar o acesso a arquivos pessoais mas também a informação referente ao próprio S.O. - acesso ao arquivo de senhas, por exemplo.

Comandos relacionados: ls.

As permissões a arquivos, sejam eles executáveis ou não, se dão por uma lista de controle de acesso: usuário (dono do arquivo), grupo e outros. Se o usuário possui a permissão por ele desejada (leitura, escrita ou execução), terá o respectivo acesso ao arquivo. Isso acontecerá para um executável (permissão de execução), por exemplo. E como um processo está sempre associado a um usuário (ou por padrão outorgados ao root), ainda assim tem-se a relação usuário-permissões, as quais serão utilizadas para abrir arquivos. Exemplo: o comando cat que lerá o arquivo /etc/passwd

Comandos relacionados: lsof, fuser.

Todo arquivo tem um dono, e todo processo também. Parte desta resposta já fora apresentada na questão anterior, mas cabe complementar: é preciso estabelecer limites para os usuários e seus processos e arquivos, a fim de que não haja abuso ou mesmo a inoperância do sistema como um todo por causa de falhas humanas e/ou má fé.

Comandos relacionados: ps, top.

São cinco os estados, conforme o material recomendado pelo Prof. Semprebom. No caso, processos que estão no estado executando podem fazer uso de I/O bound, o que significa que haverá mais E/S e menos processamento. Por este motivo, é interessante que este processo fique aguardando o seu recurso (via E/S), enquanto que outros processos, que fazem mais CPU bound, aproveitem melhor o recurso de processamento.

Comandos relacionados: ps, top.

Associado ao escalonamento preemptivo, faz-se o uso de prioridades para garantir que os processos sejam atendidos conforme a sua demanda: processos referentes a aplicações de tempo real, por exemplo, requerem mais processamento, portanto uma maior prioridade. Contudo, é preciso, ao longo do tempo, manipular tais prioridades, garantindo que os todos os processos rodem - caso contrário aqueles com maior prioridade sempre voltarão ao começo da fila. O envelhecimento de prioridades, portanto, é uma forma de equilibrar o uso do processador de forma mais eficiente e justa. Lembrando que no escalonamento preemptivo o processador pode parar um processo quando finda seu tempo (timeslice) - a figura da questão anterior ilustra o caso (interrupção por tempo).

Comandos relacionados: top.

Nada impede que haja vários sistemas de arquivos montados, desde que eles estejam em formato compreensível pelo kernel - para depois serem abstraídos às aplicações (veja o Virtual File System do Linux). Como o sistema de arquivos corrente, global, já é hierárquico (árvore de diretórios), a montagem sequencial dos vários sistemas se dará de forma natural.

Comandos relacionados: mount, umount.

Swap é um tipo de partição da memória secundária, formatada para servir como extensão da memória principal. Juntas, elas formam a memória virtual - que será utilizada pelas aplicações. Para manipular as partições de troca, ou swap, veja o Guia Foca Linux. Cabe destacar que este tipo de memória é mais barata e lenta.

Comandos relacionados: free.

O interpretador de comandos, ou shell, é uma das aplicações voltadas para o usuário. Esta, em particular, é um terminal em formato texto para interpretador ordens do usuários: os comandos. Há vários interpretadores, onde cada um deles implementa uma linguagem para facilitar a entrada de dados ao computador. O bash é talvez o interpretador mais utilizado nos Linux "de usuário": Ubuntu, Mandriva, etc.

Comandos relacionados: bash.

O kernel é nada mais que o núcleo do sistema operacional, sendo responsável pela maioria das funções ligadas ao S.O. Dentre as suas funções, podemos destacar: gerência de memória, gerência de processos, controle do sistema de arquivos (E/S).

O arquivo executável é um arquivo regular, cujo conteúdo é um programa - em código de máquina ou passível de interpretação por outro programa (Python, PHP, etc.). Já o processo é um programa carregado em memória, consumindo recursos da máquina (processamento, memória, E/S) para realizar as suas instruções. Portanto, um arquivo executável será carregado em memória para virar um processo (cuidado com código interpretado: o processo será, na verdade, o seu interpretador, e associado a ele o código a interpretar).

Comandos relacionados: ps, top, vmstat.

31/08: Preparativos para a prova

  1. # Etapa 1 - Entrar no diretório "/home/aluno":
  2. cd /
  3. cd home
  4. cd aluno
  5. echo "Estou no diretório /home/aluno."
  6. sleep 1
  7. # Etapa 2 - Criar o diretório "q2":
  8. mkdir q2
  9. echo "Criei o subdiretório q2."
  10. sleep 1
  11. # Etapa 3 - Criar os subdiretórios "a", "b", "c" e "d" sob "q2":
  12. cd q2
  13. mkdir a
  14. mkdir b
  15. mkdir c
  16. mkdir d
  17. echo "Criei os subdiretório a, b, c, e d."
  18. # Etapa 4 - Criar o arquivo "h" sob "q2" com o conteúdo "xyz":
  19. touch h
  20. echo "xyz" > h
  21. # Etapa 5 - Criar os diretórios "e" e "f" sob "a":
  22. cd a
  23. mkdir e
  24. mkdir f
  25. # Etapa 6 - Criar o arquivo "g" sob "d" com o conteúdo "123":
  26. cd ../
  27. cd d
  28. echo "123" > g

Nomenclatura:

  1. Círculo ou elipse: diretório
  2. Quadrado ou retângulo: arquivo
  3. Flecha com ponta escura: hard link
  4. Flecha com ponta vazada (clara): soft link

Perguntas referentes ao grafo anterior:

  1. Os arquivos "e" e "i" contêm o mesmo conteúdo?
  2. Os diretórios b e d contêm o mesmo conteúdo?
  3. Como criar esta estrutura de diretórios e arquivos? Apresente a sequência de passos ou operações; em seguida, a sequência de comandos de shell (interpretador de comandos).

02/09: Prova

1a. Aula: "Cola"

2a. e 3a. Aulas: Prova teórica

Lógica de Programação

09/09: Introdução

  1. Sequência de passos:
    1. Listar todos os arquivos.
    2. Verificar o tamanho de cada arquivo acima listado.
    3. Selecionar apenas os arquivos com tamanho zero.
  2. Proposta de solução em shell script - em 3 etapas conforme a sequência acima descrita:
# find / | xargs du | grep ^0

  1. Distribuir senhas sequencialmente.
  2. Atendimento por ordem sequencial das senhas. Se for preferencial, anteder; caso contrário, atender o próximo número.
  3. Recebimento dos documentos.
  4. Verifica se o assinante está presente. Se estiver, tudo bem; caso contrário, verifica se o documento pode ser reconhecido por semelhança.
  5. Verifica a existência de uma ficha relacionada ao nome do documento.
  6. Se existir,pegar a ficha; caso contrário, e se a pessoa estiver presente, cria uma ficha.
  7. Assinatura de um termo de comparecimento com data.
  8. Comparação das assinaturas dos documentos e do termo.
  9. Se forem iguais, reconhece, aplica o selo e leva ao tabelião assinar; caso contrário negar o reconhecimento.
  10. Recebimento do pagamento.
  11. Devolução dos documentos.
  12. Armazenamento da ficha - de volta ao fichário.
  13. Fim do reconhecimento.

14/09: Desenvolvendo algoritmos

  1. Leitura do enunciado
  2. Abstração do problema: o pentagrama é um processo repetitivo (5x):
    1. Desenhar uma linha representando um lado da figura
    2. Definir o ângulo interno para traçar a próxima linha
  3. Definição da sequência de passos:
    1. Desenhar uma linha de tamanho X
    2. Alterar para 144 graus para um lado, no caso direito
    3. Desenhar uma linha de tamanho X
    4. Alterar para 144 graus para um lado, no caso direito
    5. Desenhar uma linha de tamanho X
    6. Alterar para 144 graus para um lado, no caso direito
    7. Desenhar uma linha de tamanho X
  4. A proposta de solução utiliza a linguagem Logo para apresentação do resultado. Foi utilizado o programa Kturtle para esboçar a figura final.
reset
turnleft 54
forward 100
turnright 144
forward 100
turnright 144
forward 100
turnright 144
forward 100
turnright 144
forward 100

16/09: Pseudocódigo e diagrama de blocos

  1. Abstração do problema: considere a lâmpada do tipo incandescente instalada no teto da sala.
  2. Pseudocódigo: ações imperativas em linguagem natural (Português).
    1. Pegue uma escada.
    2. Abra a escada embaixo da lâmpada velha.
    3. Suba na escada.
    4. Retire a lâmpada velha.
    5. Desça da escada.
    6. Descarte a lâmpada velha.
    7. Pegue uma lâmpada nova.
    8. Suba na escada.
    9. Inslate a lâmpada nova no bocal.
    10. Desça da escada.
    11. Feche a escada.
    12. Guarde a escada.

O diagrama de bloco do pseudocódigo anterior será bastante simples: uma sequência única de passos a serem executados.

Contudo, nem mesmo o processo de trocar uma lâmpada é tão linear. Em um cenário mais próximo da vida real, haverá dúvidas e decisões a serem tomadas durante o processo:


21/09: Atividades com pseudocódigo e diagrama de blocos

Obs.: este trabalho servirá como complemento de conceito na próxima avaliação.

23/09: Constantes e variáveis

28/09: Operadores

30/09: Estruturas

Problema 1

Proposta de Solução 1

  1. #!/bin/bash
  2.  
  3. # ENTRADA DE DADOS
  4. # Leia o número.
  5. echo "Digite um número inteiro:"
  6. read numero
  7.  
  8. # PROCESSAMENTO
  9. # Multiplique o número por ele mesmo e armazene o resultado em PotênciaDe2.
  10. potenciaDe2=`expr $numero \* $numero`
  11. #
  12. # Multiplique o número por PotênciaDe2 e armazene o resultado em PotênciaDe3.
  13. potenciaDe3=`expr $numero \* $potenciaDe2`
  14.  
  15. # SAÍDA DE DADOS
  16. # Escreva o número armazenado em PotênciaDe3.
  17. echo "O resultado é:"
  18. echo $potenciaDe3

Proposta de Solução 2

  1. #!/bin/bash
  2.  
  3. # ENTRADA DE DADOS
  4. #Leia o número.
  5. echo "Digite um número inteiro"
  6. read numero
  7. #
  8. #Armazene o número na variável Resultado.
  9. resultado=$numero
  10.  
  11. # PROCESSAMENTO
  12. #Armazene o número 1 na variável Potência.
  13. potencia=1
  14. #
  15. #Enquanto Potência < 3 faça
  16. # Multiplique o número e Resultado.
  17. # Adicione 1 a Potência
  18. #FimEnquanto
  19. while [ $potencia -lt '3' ]; do
  20. resultado=`expr $numero \* $resultado`
  21. potencia=`expr $potencia + 1`
  22. done
  23.  
  24. # SAíDA DE DADOS
  25. #Escreva o número armazenado em Resultado.
  26. echo "O resultado é:"
  27. echo $resultado

Proposta de Solução 3

  1. #!/bin/bash
  2.  
  3. # ENTRADA
  4. #Leia o número.
  5. echo "Digite um número inteiro:"
  6. read numero
  7. #Armazene o número na variável Potência.
  8. potencia=$numero
  9.  
  10. # PROCESSAMENTO
  11. #Para "2 3" faça
  12. # Multiplique número e Potência.
  13. #FimPara
  14. for lista in 2 3; do
  15. echo "Multiplicando pela $lista vez..."
  16. potencia=`expr $numero \* $potencia`
  17. done
  18.  
  19. # SAíDA
  20. #Escreva o número da variável Potência.
  21. echo "A potência de 3 de $numero é:"
  22. echo $potencia

Problema 2

Proposta de Solução 1

Problema 3

Problema 4

Problema 5

Problema 6

05/10: Atividades pré-prova

Problema 1

Problema 2

Problema 3

Problema 4

07/10: Prova de lógica

12/10: Feriado

Linguagem de Programação C

14/10: Ambiente de desenvolvimento

  1. #include <stdio.h>
  2.  
  3. int main(){
  4.  
  5. // Declaração de variáveis
  6. int x;
  7. int y;
  8. int soma;
  9.  
  10. // Entrada de dados
  11. scanf("%d",&x);
  12. scanf("%d",&y);
  13.  
  14. // Processamento
  15. soma = x + y;
  16.  
  17. // Saída de dados
  18. printf("x = %d\n",x);
  19. printf("y = %d\n",y);
  20. printf("x + y = %d\n",soma);
  21. }

19/10: Projeto final

Até o dia 11/12 será desenvolvido o projeto final da disciplina utilizando a linguagem C. O projeto está dividido em 4 etapas, a serem entregues conforme calendário estipulado no projeto.

Início da Etapa 1

Para realizar a primeira etapa, será necessário adquirir os conhecimentos básicos da linguagem, em especial tipos e variáveis. Para tanto, foi proposto em sala, hoje, um exercício envolvendo tipos, variáveis, estruturas de decisão e de repetição.

#include <stdio.h>
 
int main()
{
int a;
int b;
int b_original;
int limite;
 
a = 0;
b = 1;
 
printf("Informe o valor limite para a sequência de Fibonacci (número inteiro): ");
scanf("%d", &limite);
 
printf("A sequência de Fibonacci é:");
printf(" %d", a);
while ( b <= limite )
{
printf(" %d",b);
b_original = b; // Como Fibonacci utiliza *a* e *b* para somar o
b = a + b; // próximo, e *b* tem o seu valor modificado, é
a = b_original; // preciso guardar o seu "original" para *a*.
}
printf(".\n");
}

Compilando e, em seguida, executando o programa:

$ gcc fibonacci.c -o Fibonacci
$ ./Fibonacci
Informe o valor limite para a sequência de Fibonacci (número inteiro): 144
A sequência de Fibonacci é: 0 1 1 2 3 5 8 13 21 34 55 89 144.
int primo(int numero)
{
int divisor;
int resto;
int ehPrimo = 1;
 
for(divisor = numero - 1; divisor > 1; divisor--)
{
resto = numero % divisor;
if(resto == 0)
{
ehPrimo = 0;
}
}
return ehPrimo;
}

Ao final, o programa será modificado para chamar a função que testa a primalidade de cada um dos números:

#include <stdio.h>
 
int primo(int numero)
{
int divisor;
int resto;
int ehPrimo = 1;
 
for(divisor = numero - 1; divisor > 1; divisor--)
{
resto = numero % divisor;
if(resto == 0)
{
ehPrimo = 0;
}
}
return ehPrimo;
}
 
int main()
{
int a;
int b;
int b_original;
int limite;
 
a = 0;
b = 1;
 
printf("Informe o valor limite para a sequência de Fibonacci (número inteiro): ");
scanf("%d", &limite);
 
printf("A sequência de Fibonacci é:");
printf(" %dp", a);
while ( b <= limite )
{
if(primo(b) == 1)
{
printf(" %dp",b);
} else
{
printf(" %d",b);
}
b_original = b; // Como Fibonacci utiliza *a* e *b* para somar o
b = a + b; // próximo, e *b* tem o seu valor modificado, é
a = b_original; // preciso guardar o seu "original" para *a*.
}
printf(".\n");
}

Compilando pela segunda vez, chegamos ao resultado final do exercício:

$ gcc fibonacci.c -o Fibonacci
$ ./Fibonacci
Informe o valor limite para a sequência de Fibonacci (número inteiro): 144
A sequência de Fibonacci é: 0p 1p 1p 2p 3p 5p 8 13p 21 34 55 89p 144.

21/10: Estrutura de um Programa em C e Números

Atividades: construa um programa que apresenta na tela...

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. int inteiro;
  6.  
  7. inteiro = 0;
  8.  
  9. printf("Números inteiros em ordem ascendente:");
  10. while ( 1 == 1 ) // Condição sempre satisfeita
  11. {
  12. printf(" %d",inteiro);
  13. inteiro = inteiro + 1;
  14. }
  15. }
  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. int inteiro;
  6.  
  7. inteiro = 0;
  8.  
  9. printf("Números inteiros pares em ordem ascendente:");
  10. while ( 1 == 1 ) // Condição sempre satisfeita
  11. {
  12. printf(" %d",inteiro);
  13. inteiro = inteiro + 2;
  14. }
  15. }
  1. #include <stdio.h>
  2.  
  3. int adicioneDois(int numero)
  4. {
  5. numero = numero + 2;
  6. return numero;
  7. }
  8.  
  9. int main()
  10. {
  11. int inteiro;
  12.  
  13. inteiro = 0;
  14.  
  15. printf("Números inteiros pares em ordem ascendente:");
  16. while ( 1 == 1 ) // Condição sempre satisfeita
  17. {
  18. printf(" %d",inteiro);
  19. inteiro = adicioneDois(inteiro);
  20. }
  21. }

É a função das linhas 3 a 7 que, em tempo de execução, é chamada na linha 19. O mesmo raciocínio também se aplica ao exercício anterior (para somar 1).

  1. #include <stdio.h>
  2.  
  3. int adicioneDois(int numero)
  4. {
  5. numero = numero + 2;
  6. return numero;
  7. }
  8.  
  9. int main()
  10. {
  11. int inteiro;
  12.  
  13. inteiro = 1;
  14.  
  15. printf("Números inteiros ímpares em ordem ascendente:");
  16. while ( 1 == 1 ) // Condição sempre satisfeita
  17. {
  18. printf(" %d",inteiro);
  19. inteiro = adicioneDois(inteiro);
  20. }
  21. }
  1. #include <stdio.h>
  2.  
  3. int adicioneDois(int numero)
  4. {
  5. numero = numero + 2;
  6. return numero;
  7. }
  8.  
  9. int main()
  10. {
  11. int inteiro;
  12. char escolha;
  13.  
  14. printf("Digite P para números pares ou I para números ímpares: ");
  15. scanf("%c", &escolha);
  16. if ( escolha == 'P' )
  17. {
  18. inteiro = 0;
  19. }
  20. else
  21. {
  22. if ( escolha == 'I' )
  23. {
  24. inteiro = 1;
  25. }
  26. else
  27. {
  28. printf("Escolha errada!\n");
  29. return;
  30. }
  31. }
  32.  
  33. printf("Números inteiros em ordem ascendente:");
  34. while ( 1 == 1 ) // Condição sempre satisfeita
  35. {
  36. printf(" %d",inteiro);
  37. inteiro = adicioneDois(inteiro);
  38. }
  39. }
  1. Coloque aqui o código-fonte em C.

Recuperação da Prova

A recuperação da prova de lógica consiste em um trabalho a ser entregue dia 28/10, quarta-feira, durante a aula.

O problema é o seguinte: construa uma calculadora baseada notação polonesa inversa. Para facilitar o desenvolvimento da aplicação, considere que é possível armazenar até 3 valores na pilha de números, além de utilizar apenas as quatro operações matemáticas: +, -, * e /. A resposta deve ser dada quando houver apenas um número na pilha.

O conceito de pilha é interessante: os primeiros valores adicionados serão os últimos escolhidos, como uma pilha de objetos:

No exemplo ao lado: o número 2 foi o primeiro adicionado e, portanto, o último a ser escolhido.

Exemplos de operações utilizando notação polonesa inversa:

2 3 +
= 5
2 3 * 4 +
= 10
7 6 3 + -
= -2
2 3 4 * +
= 14

Os números são armazenados para uso posterior. Para cada operação matemática, são "escolhidos" os últimos números inseridos, aplicada a operação e o resultado retorna à pilha de números. Portanto, a ordem dos elementos faz diferença na execução.

Neste último exemplo, seguem os passos da solução:

  1. A pilha está com os valores 2 (base) 3 4 (topo).
  2. Aparece a operação de multiplicação. São utilizados os valores mais próximos do topo: 3 e 4. O resultado é 12.
  3. Os valores 3 e 4 são retirados da pilha e retorna apenas o valor 12. A pilha fica assim: 2 (base) 12 (topo).
  4. Aparece a operação de soma. São utilizados os valores mais próximos do topo: 2 e 12. O resultado é 14.
  5. Os valores 2 e 12 são retirados da pilha e retorna apenas o valor 14.
  6. Como há apenas um número na pilha, o resultado final é apresentado: 14

Outro exemplo:

8 8 6 4 3 + - + *
= 56

A sequência das operações, com a pilha resultante, é:

4 3 +
  Pilha = 8 8 6 7 - + *
6 7 -
  Pilha = 8 8 -1 + *
8 -1 +
  Pilha = 8 7 *
8 7 *
  Pilha = 56
= 56 

Dica: o programa dc utiliza este tipo de notação. A calculadoraHP12C, muito utilizada para Contabilidade e Economia, também se baseia nos mesmos princípios.

O trabalho deve ser entregue em papel ou mídia digital, durante a aula, contendo pseudocódigo e diagrama de blocos da solução do problema. Lembre-se: até 3 números armazenados e as quatro operações básicas.

26/10: Etapa 1 - Tipos e Funções

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. char nome[50];
  6. int idade;
  7.  
  8. printf("Digite o nome da pessoa: ");
  9. fgets(nome,sizeof(nome),stdin);
  10. printf("Digite a idade da pessoa: ");
  11. scanf("%d", &idade);
  12.  
  13. printf("%s tem %d anos.", nome, idade);
  14. }
  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. struct pessoa
  6. {
  7. char nome[50];
  8. int idade;
  9. };
  10. struct pessoa Aluno;
  11.  
  12. printf("Digite o nome da pessoa: ");
  13. fgets(Aluno.nome,sizeof(Aluno.nome),stdin);
  14. printf("Digite a idade da pessoa: ");
  15. scanf("%d", &Aluno.idade);
  16.  
  17. printf("%s tem %d anos.", Aluno.nome, Aluno.idade);
  18. }

28/10: Etapa 1 - Pseudocódigo

Pseudocódigo da primeira etapa:

  1. Enquanto opção for diferente de "Sair do programa" faça
    1. Apresente as opções para o usuário
      1. Primeira opção: criar um evento
      2. Segunda opção: mostrar um evento já cadastrado
      3. Terceira opção: Sair do programa
    2. Leia a opção do usuário
    3. Se a opção é de criação de um evento então
      1. Leia título
      2. Leia horários de início e fim
      3. Leia data e horário de criação
      4. Leia descrição
      5. Leia local de realização
      6. Leia outros participantes.
      7. Leia estado.
      8. Leia categoria: pessoal, trabalho, etc.
      9. Leia recorrência: com que regularidade ocorre e prazo.
    4. Fim Se
    5. Se a opção é mostrar um evento então
      1. Se já existe um evento cadastrado
        1. Apresente o evento, um item por linha
      2. Fim Se
    6. Sim Se
  2. Fim Enquanto
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. int main()
  5. {
  6. int contador = 0;
  7. int tamanhoDaString;
  8.  
  9. struct pessoa
  10. {
  11. char nome[50];
  12. };
  13. struct pessoa Aluno;
  14.  
  15. printf("Inicie a contagem com: ");
  16. scanf("%d",&contador);
  17. while(contador < 50)
  18. {
  19. printf("Digite o nome da pessoa: ");
  20. fgets(Aluno.nome,50,stdin);
  21. if(Aluno.nome[0] == '\n')
  22. {
  23. fgets(Aluno.nome,50,stdin);
  24. }
  25. tamanhoDaString = strlen(Aluno.nome);
  26. if( Aluno.nome[tamanhoDaString-1] == '\n' )
  27. Aluno.nome[tamanhoDaString-1] = 0;
  28.  
  29. printf("Nome = %s\n",Aluno.nome);
  30. contador++;
  31. }
  32. }

02/11: Etapa 2 - O uso de funções para organizar código

O interessante, quando o programa adquire complexidade, é organizar o código em funções.

Leitura de uma linha inteira a partir da entrada de dados do usuário:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4.  
  5. // Estruturas de Dados
  6. struct pessoa
  7. {
  8. char nome[50];
  9. int idade;
  10. };
  11.  
  12.  
  13. // Funções de entrada de dados
  14. int lerNumero()
  15. {
  16. int numero;
  17. int leuNumero = 1;
  18. do
  19. {
  20. if (leuNumero == 0)
  21. {
  22. printf("Ops! Problemas ao ler o número. Digite-o novamente: ");
  23. }
  24. leuNumero = scanf("%d", &numero);
  25. if (leuNumero == 0)
  26. {
  27. leuNumero = scanf("%*[^\n]");
  28. }
  29. } while (leuNumero == 0);
  30. return numero;
  31. }
  32.  
  33. void lerLinha(char * linha) {
  34. scanf(" %[^\n]", linha);
  35. }
  36.  
  37. struct pessoa lerValores()
  38. {
  39. int tamanhoDaString;
  40. struct pessoa qualquerPessoa;
  41. printf("Nome da pessoa: ");
  42. // Como a leitura de string é diferente das outras variáveis,
  43. // isso é feito dentro da própria função.
  44. fgets(qualquerPessoa.nome,50,stdin);
  45. if(qualquerPessoa.nome[0] == '\n')
  46. {
  47. fgets(qualquerPessoa.nome,50,stdin);
  48. }
  49. tamanhoDaString = strlen(qualquerPessoa.nome);
  50. if(qualquerPessoa.nome[tamanhoDaString-1] == '\n')
  51. {
  52. qualquerPessoa.nome[tamanhoDaString-1] = 0;
  53. }
  54. printf("Idade da pessoa: ");
  55. qualquerPessoa.idade = lerNumero();
  56. return qualquerPessoa;
  57. }
  58.  
  59. int mostrarValores(struct pessoa qualquerPessoa)
  60. {
  61. printf("Nome da pessoa: %s\n", qualquerPessoa.nome);
  62. printf("Idade da pessoa: %d\n", qualquerPessoa.idade);
  63. }
  64.  
  65.  
  66. // Função principal: o programa
  67. int main()
  68. {
  69. int opcao = 0;
  70. int valoresJaLidos = 0;
  71. struct pessoa umaPessoa;
  72. do
  73. {
  74. printf("\nOpção 1 - Ler valores do usuário.\n");
  75. printf("Opção 2 - Mostrar valores já lidos do usuário.\n");
  76. printf("Opção 3 - Sair do programa.\n");
  77. printf("Digite a sua opção: ");
  78. opcao = lerNumero();
  79. switch(opcao)
  80. {
  81. case 1:
  82. umaPessoa = lerValores();
  83. valoresJaLidos = 1;
  84. break;
  85. case 2:
  86. if (valoresJaLidos == 1)
  87. {
  88. mostrarValores(umaPessoa);
  89. }
  90. else
  91. {
  92. printf("Ainda não há valores lidos do usuário. ");
  93. printf("Escolha a opção 1 para lê-los.\n");
  94. }
  95. break;
  96. case 3:
  97. printf("Fim do programa. Adeus!\n");
  98. break;
  99. default:
  100. printf("Opção inválida! Escolha um número entre 1 e 3.\n");
  101. break;
  102. }
  103. } while (opcao != 3);
  104. }

04/11: Etapa 2 - Continuação da etapa anterior

Estruturando a primeira etapa do programa:

  1. //Inclusão de outros arquivos e bibliotecas
  2. #include <stdio.h>
  3. #include <time.h>
  4.  
  5. //Estruturas de dados
  6. // Estrutura de um evento:
  7. // - Título
  8. // - Data de início e de fim
  9. // - Horário de início e de fim
  10. // - Data e horário de criação
  11. // - descrição
  12. // - local
  13. // - estado: confirmado ou não?
  14. // - categoria: pessoal, trabalho, etc.
  15. // - recorrência: regularidade.
  16. struct evento
  17. {
  18. char titulo[50];
  19. char dataDeInicio[10];
  20. char dataDeTermino[10];
  21. char horarioDeInicio[5];
  22. char horarioDeTermino[5];
  23. char dataDeCriacao[10];
  24. char horaDeCriacao[5];
  25. char descricao[100];
  26. char local[100];
  27. char estado[20];
  28. char categoria[10];
  29. char recorrencia[20];
  30. };
  31.  
  32.  
  33. //Funções auxiliares
  34. char* agora()
  35. {
  36. time_t hora;
  37. time(&hora);
  38. return(ctime(&hora));
  39. }
  40.  
  41.  
  42. //Função principal
  43. int main()
  44. {
  45. int opcao;
  46. struct evento meuPrimeiroEvento;
  47. do
  48. {
  49. printf("\nOpção 1: criar um evento.\n");
  50. printf("Opção 2: mostar um evento já criado.\n");
  51. printf("Opção 3: Sair do programa.\n");
  52. printf("Digite a sua opção: ");
  53. scanf("%d", &opcao);
  54. switch(opcao)
  55. {
  56. case 1:
  57. printf("Digite o título do evento: ");
  58. scanf("%s", meuPrimeiroEvento.titulo);
  59. break;
  60. case 2:
  61. printf("Apenas um evento cadastrado!\n");
  62. printf("Título: %s\n", meuPrimeiroEvento.titulo);
  63. printf("Hora de criação: %s", agora());
  64. break;
  65. case 3:
  66. printf("Fim do programa. Adeus!\n");
  67. break;
  68. }
  69. } while (opcao != 3);
  70. }


Exemplo de uso de vetores para utilizar, em um mesmo programa, várias estruturas de dados:

  1. #include <stdio.h>
  2.  
  3. struct ponto
  4. {
  5. int x;
  6. int y;
  7. int z;
  8. };
  9.  
  10. int main()
  11. {
  12. int indice;
  13. struct ponto Vertices[3];
  14.  
  15. for(indice=0; indice <=2; indice++)
  16. {
  17. printf("\nPonto %d\n", indice);
  18. printf("Informe x: ");
  19. scanf("%d", &Vertices[indice].x);
  20. printf("Informe y: ");
  21. scanf("%d", &Vertices[indice].y);
  22. printf("Informe z: ");
  23. scanf("%d", &Vertices[indice].z);
  24. }
  25.  
  26. printf("\nResultados:\n");
  27. for(indice=0; indice<=2; indice++)
  28. {
  29. printf("Figura %d:", indice);
  30. printf(" %d", Vertices[indice].x);
  31. printf(" %d", Vertices[indice].y);
  32. printf(" %d\n", Vertices[indice].z);
  33. }
  34. }

09/11: Etapa 2 - Desenvolvimento em etapas

Programação requer dedicação, disciplina e, antes de tudo, perseverança :-)

O núcleo

Um programa simples, como este:

  1. void main()
  2. {
  3. }

é o início de praticamente qualquer programa em C, uma vez que contém a função principal, main(). Neste caso, definida com um conjunto vazio de instruções - limitado pelas chaves nas linhas 2 e 3.

O (clássico) primeiro programa

A partir daí, pode-se construir qualquer programa. Contudo, em C o conhecimento prévio de sua estrutura mínima: bibliotecas, tipos, funções e outros, auxilia bastante a programação. Ao invés de criar todo um código para escrever uma simples linha na tela, pode-se utilizar código pronto para tal: a biblioteca stdio.h, por exemplo, ajuda na entrada e saída de dados (standard input and output). Ali há, dentre outras, a função printf, que mostra uma informação na tela: a velah frase "Olá mundo!".

  1. #include <stdio.h>
  2.  
  3. void main()
  4. {
  5. printf("Olá mundo!\n");
  6. }

Reutilizar para não reinventar a roda...

Entrada e saída de dados

Mas interação acontece mesmo quando os dados são transmitidos nas duas direções: ler e escrever dados do usuário. Mais uma vez, a stdio.h possui outra função, a de ler dados: scanf - a mais simples de muitas. No caso abaixo, há a leitura e a repetição dos dados inseridos para garantir que a leitura ocorreu sem problemas:

  1. #include <stdio.h>
  2.  
  3. void main()
  4. {
  5. char nome[10];
  6.  
  7. printf("Olá!\nDigite o seu primeiro nome: ");
  8. scanf("%s", nome);
  9. printf("Repetindo: %s\n", nome);
  10. }

Nota-se, na linha 5, a inclusão de uma variável: uma área de memória para armazenar, mesmo que temporariamente, o valor inserido pelo usuário. No caso, um vetor de até 10 caracteres (10 bytes): uma string. Mas cuidado com o último byte...

Mais dados

Isso significa que a interação pode se assemelhar a um "diálogo": escrever e ler sequencialmente vários valores. No exemplo abaixo, o nome de uma pessoa e sua idade.

  1. #include <stdio.h>
  2.  
  3. void main()
  4. {
  5. char nome[10];
  6. int idade;
  7.  
  8. printf("Olá!\nDigite o seu primeiro nome: ");
  9. scanf("%s", nome);
  10. printf("Sua idade: ");
  11. scanf("%d", &idade);
  12. printf("Repetindo: %s tem %d anos.\n", nome, idade);
  13. }

As variáveis das linhas 5 e 6 têm seus valores alterados nas linhas 9 e 11, respectivamente - e reapresentados na linha 12.

Organizando os dados

Se as variáveis têm alguma relação entre si, pode-se organizá-las em blocos, facilitando a sua manipulação. Esses blocos são as estruturas de dados:

struct pessoa
{
char nome[10];
int idade;
};

mudando um pouco a forma de usar essas áreas de memória:

  1. #include <stdio.h>
  2.  
  3. struct pessoa
  4. {
  5. char nome[10];
  6. int idade;
  7. };
  8.  
  9.  
  10. void main()
  11. {
  12. struct pessoa umaPessoa;
  13.  
  14. printf("Olá!\nDigite o seu primeiro nome: ");
  15. scanf("%s", umaPessoa.nome);
  16. printf("Sua idade: ");
  17. scanf("%d", &umaPessoa.idade);
  18. printf("Repetindo: %s tem %d anos.\n", umaPessoa.nome, umaPessoa.idade);
  19. }

Ou seja, ao invés de usar diretamente a variável é preciso informar, agora, o seu nome composto: a variável do tipo estrutura e a variável interna dessa estrutura. Nas linhas 3 a 7, foi definida a estrutura. Na linha 12, foi declarada uma variável do tipo composto (struct pessoa) de nome umaPessoa.

Integrando os conceitos

Assim como não existem palavras ou frases em C, mas vetores de caracteres (strings), o mesmo pode se aplicar a outros tipos de variáveis:

int numero;
int numeros[10];
char letra;
char letras[10];

inclusive tipos compostos:

struct pessoa
{
char nome[10];
int idade;
};
 
struct pessoa umaPessoa;
struct pessoa pessoas[10];

Para o programa anterior, pode-se expandir para utilizar não apenas um tipo por vez, mas vários:

  1. #include <stdio.h>
  2.  
  3. struct pessoa
  4. {
  5. char nome[10];
  6. int idade;
  7. };
  8.  
  9.  
  10. void main()
  11. {
  12. struct pessoa pessoas[2];
  13.  
  14. printf("Olá!\nPrimeira pessoa, digite o seu primeiro nome: ");
  15. scanf("%s", pessoas[0].nome);
  16. printf("Sua idade: ");
  17. scanf("%d", &pessoas[0].idade);
  18.  
  19. printf("Outra pessoa, digite o seu primeiro nome: ");
  20. scanf("%s", pessoas[1].nome);
  21. printf("Sua idade: ");
  22. scanf("%d", &pessoas[1].idade);
  23.  
  24.  
  25. printf("Repetindo: a primeira pessoa de chama %s e tem %d anos.\n", pessoas[0].nome, pessoas[0].idade);
  26. printf("Já a segunda pessoa, de nome %s, tem %d anos.\n", pessoas[1].nome, pessoas[1].idade);
  27. }

Estruturas de repetição

Associado a n variáveis, nada mais adequado que uma estrutura de repetição adequada à quantidade de variáveis utilizadas. Para tanto, faz-se uso de um contador ou índice para controle de quantas variáveis, já declaradas, estão de fato em uso:

  1. #include <stdio.h>
  2.  
  3. struct pessoa
  4. {
  5. char nome[10];
  6. int idade;
  7. };
  8.  
  9.  
  10. void main()
  11. {
  12. struct pessoa pessoas[2];
  13. int indice = 0;
  14.  
  15. printf("Olá!\n");
  16. do
  17. {
  18. printf("Pessoa número %d, digite seu primeiro nome: ", indice + 1);
  19. scanf("%s", pessoas[indice].nome);
  20. printf("Sua idade: ");
  21. scanf("%d", &pessoas[indice].idade);
  22. indice = indice + 1;
  23. } while (indice < 2);
  24.  
  25. printf("Repetindo:\n");
  26. do
  27. {
  28. printf("A pessoa número %d, %s, tem %d ano(s).\n", indice, pessoas[indice-1].nome,
  29. pessoas[indice-1].idade);
  30. indice = indice - 1;
  31. } while (indice > 0);
  32. }

Diminuindo complexidade com funções

Até agora, o programa não se preocupou caso o usuário digitasse erroneamente, podendo causar falhas críticas. E como o programa começa a ganhar complexidade, envolvendo vetores, estruturas de repetição e outros, é extremamente interessante organizar o código.

Por isso, as entradas do usuário serão devidamente tratadas e padronizadas em funções auxiliares podendo, com isso, ser reutilizadas quantas vezes forem necessárias. Veja as funções lerNumero() (linhas 9 a 26) e lerLinha() (linha 28 a 30).

  1. #include <stdio.h>
  2.  
  3. struct pessoa
  4. {
  5. char nome[30];
  6. int idade;
  7. };
  8.  
  9. int lerNumero()
  10. {
  11. int numero;
  12. int leuNumero = 1;
  13. do
  14. {
  15. if (leuNumero == 0)
  16. {
  17. printf("Ops! Problemas ao ler o número. Digite-o novamente: ");
  18. }
  19. leuNumero = scanf("%d", &numero);
  20. if (leuNumero == 0)
  21. {
  22. leuNumero = scanf("%*[^\n]");
  23. }
  24. } while (leuNumero == 0);
  25. return numero;
  26. }
  27.  
  28. void lerLinha(char * linha) {
  29. scanf(" %[^\n]", linha);
  30. }
  31.  
  32. void main()
  33. {
  34. struct pessoa pessoas[2];
  35. int indice = 0;
  36.  
  37. printf("Olá!\n");
  38. do
  39. {
  40. printf("Pessoa número %d, digite seu nome completo: ", indice + 1);
  41. lerLinha(pessoas[indice].nome);
  42. printf("Sua idade: ");
  43. pessoas[indice].idade = lerNumero();
  44. indice = indice + 1;
  45. } while (indice < 2);
  46.  
  47. printf("Repetindo:\n");
  48. do
  49. {
  50. printf("A pessoa número %d, %s, tem %d ano(s).\n", indice, pessoas[indice-1].nome,
  51. pessoas[indice-1].idade);
  52. indice = indice - 1;
  53. } while (indice > 0);
  54. }

Operando sobre índices

Agora já é possível incrementar o programa: cadastro e apresentação de várias pessoas.

  1. #include <stdio.h>
  2.  
  3. struct pessoa
  4. {
  5. char nome[30];
  6. int idade;
  7. };
  8.  
  9. int lerNumero()
  10. {
  11. int numero;
  12. int leuNumero = 1;
  13. do
  14. {
  15. if (leuNumero == 0)
  16. {
  17. printf("Ops! Problemas ao ler o número. Digite-o novamente: ");
  18. }
  19. leuNumero = scanf("%d", &numero);
  20. if (leuNumero == 0)
  21. {
  22. leuNumero = scanf("%*[^\n]");
  23. }
  24. } while (leuNumero == 0);
  25. return numero;
  26. }
  27.  
  28. void lerLinha(char * linha) {
  29. scanf(" %[^\n]", linha);
  30. }
  31.  
  32. void main()
  33. {
  34. struct pessoa pessoas[10];
  35. int indice = 0;
  36. int indiceTemporario;
  37. int opcao;
  38.  
  39. do
  40. {
  41. printf("\n:: Menu interativo ::\n");
  42. printf("Opção 1: Cadastrar uma pessoa.\n");
  43. printf("Opção 2: Mostrar as pessoas já cadastradas.\n");
  44. printf("Opção 3: Sair do programas.\n");
  45. printf("Digite o número da sua opção: ");
  46. opcao = lerNumero();
  47.  
  48. switch(opcao)
  49. {
  50. case 1:
  51. printf("Nome completo: ");
  52. lerLinha(pessoas[indice].nome);
  53. printf("Idade: ");
  54. pessoas[indice].idade = lerNumero();
  55. printf("Registro número %d concluído.\n", indice);
  56. indice = indice + 1;
  57. break;
  58. case 2:
  59. indiceTemporario = indice;
  60. while(indiceTemporario > 0)
  61. {
  62. indiceTemporario = indiceTemporario - 1;
  63. printf("Registro número %d:\n", indiceTemporario);
  64. printf("Nome: %s.\n", pessoas[indiceTemporario].nome);
  65. printf("Idade: %d.\n", pessoas[indiceTemporario].idade);
  66. }
  67. break;
  68. case 3:
  69. printf("Fim do programa.\n");
  70. break;
  71. default:
  72. printf("Digite um número entre 1 e 3.\n");
  73. }
  74. } while (opcao != 3);
  75. }

É comum o uso de índices ou contadores cópias/auxiliares (indiceTemporario) - para não modificar o valor original das variáveis "originais".

Estendendo o programa: relógio do sistema

Mais uma vez: é preciso entender que funções de C já estão disponíveis no sistema. Por que perguntar a hora corrente ao usuário, se o sistema já pode fornecê-lo?

  1. #include <stdio.h>
  2. #include <time.h>
  3.  
  4. struct pessoa
  5. {
  6. char nome[30];
  7. int idade;
  8. char dataDeCriacao[11];
  9. char horaDeCriacao[6];
  10. };
  11.  
  12. char* dia_mes_ano(char * data)
  13. {
  14. time_t agora;
  15. struct tm ts;
  16.  
  17. agora = time(NULL);
  18. ts = *localtime(&agora);
  19. strftime(data, 11, "%d/%m/%Y", &ts);
  20. }
  21.  
  22. char* hora_minuto(char * data)
  23. {
  24. time_t agora;
  25. struct tm ts;
  26.  
  27. agora = time(NULL);
  28. ts = *localtime(&agora);
  29. strftime(data, 6, "%H:%M", &ts);
  30. }
  31.  
  32. int lerNumero()
  33. {
  34. int numero;
  35. int leuNumero = 1;
  36. do
  37. {
  38. if (leuNumero == 0)
  39. {
  40. printf("Ops! Problemas ao ler o número. Digite-o novamente: ");
  41. }
  42. leuNumero = scanf("%d", &numero);
  43. if (leuNumero == 0)
  44. {
  45. leuNumero = scanf("%*[^\n]");
  46. }
  47. } while (leuNumero == 0);
  48. return numero;
  49. }
  50.  
  51. void lerLinha(char * linha) {
  52. scanf(" %[^\n]", linha);
  53. }
  54.  
  55. void main()
  56. {
  57. struct pessoa pessoas[10];
  58. int indice = 0;
  59. int indiceTemporario;
  60. int opcao;
  61.  
  62. do
  63. {
  64. printf("\n:: Menu interativo ::\n");
  65. printf("Opção 1: Cadastrar uma pessoa.\n");
  66. printf("Opção 2: Mostrar as pessoas já cadastradas.\n");
  67. printf("Opção 3: Sair do programas.\n");
  68. printf("Digite o número da sua opção: ");
  69. opcao = lerNumero();
  70.  
  71. switch(opcao)
  72. {
  73. case 1:
  74. printf("Nome completo: ");
  75. lerLinha(pessoas[indice].nome);
  76. printf("Idade: ");
  77. pessoas[indice].idade = lerNumero();
  78. printf("Registro número %d concluído.\n", indice);
  79. dia_mes_ano(pessoas[indice].dataDeCriacao);
  80. hora_minuto(pessoas[indice].horaDeCriacao);
  81. indice = indice + 1;
  82. break;
  83. case 2:
  84. indiceTemporario = indice;
  85. while(indiceTemporario > 0)
  86. {
  87. indiceTemporario = indiceTemporario - 1;
  88. printf("Registro número %d: criado em %s às %s.\n", indiceTemporario,
  89. pessoas[indiceTemporario].dataDeCriacao,
  90. pessoas[indiceTemporario].horaDeCriacao);
  91. printf("Nome: %s.\n", pessoas[indiceTemporario].nome);
  92. printf("Idade: %d.\n", pessoas[indiceTemporario].idade);
  93. }
  94. break;
  95. case 3:
  96. printf("Fim do programa.\n");
  97. break;
  98. default:
  99. printf("Digite um número entre 1 e 3.\n");
  100. }
  101. } while (opcao != 3);
  102. }

Promessa é dívida :-)

Mas a pergunta é: será que funciona? Talvez haja alguns "probleminhas" a serem resolvidos:

  1. // Bibliotecas de C
  2. #include <stdio.h> // entrada e saída padrão
  3. #include <time.h> // relógio do sistema
  4.  
  5.  
  6. // Estruturas de dados
  7. struct evento
  8. {
  9. char titulo[50]; // Título do evento
  10. char dataDeInicio[10]; // Data de início
  11. char horarioDeInicio[5]; // Horário de início
  12. char dataDeTermino[10]; // Data de término
  13. char horarioDeTermino[5]; // Horário de término
  14. char dataDeCriacao[11]; // Data de criação do evento (1 byte a mais para \0)
  15. char horarioDeCriacao[6]; // Hora de criação do evento (1 byte a mais para \0)
  16. char descricao[100]; // Um texto explicativo do evento
  17. char local[100]; // Local de realização
  18. char estado[20]; // Estados: confirmado, a confirmar, etc.
  19. char categoria[10]; // Categoria: pessoal, trabalho, etc.
  20. char recorrencia[20]; // Quantas vezes se repete?
  21. };
  22.  
  23.  
  24. // Funções auxiliares
  25. //
  26. // função dia_mes_ano(): mostra a data atual do relógio do sistema
  27. char* dia_mes_ano(char * data)
  28. {
  29. time_t agora;
  30. struct tm ts;
  31.  
  32. agora = time(NULL);
  33. ts = *localtime(&agora);
  34. strftime(data, 11, "%d/%m/%Y", &ts);
  35. }
  36. //
  37. // função hora_minuto(): mostra a hora atual do relógio do sistema
  38. char* hora_minuto(char * data)
  39. {
  40. time_t agora;
  41. struct tm ts;
  42.  
  43. agora = time(NULL);
  44. ts = *localtime(&agora);
  45. strftime(data, 6, "%H:%M", &ts);
  46. }
  47. //
  48. // função lerNumero(): lê um número via teclado do usuário
  49. int lerNumero()
  50. {
  51. int numero;
  52. int leuNumero = 1;
  53. do
  54. {
  55. if (leuNumero == 0)
  56. {
  57. printf("Ops! Problemas ao ler o número. Digite-o novamente: ");
  58. }
  59. leuNumero = scanf("%d", &numero); // Se aparecer algo diferente de número
  60. if (leuNumero == 0) // A função retornará zero.
  61. {
  62. leuNumero = scanf("%*[^\n]"); // Ou seja, "sujeira" como uma vogal.
  63. }
  64. } while (leuNumero == 0); // E a função não encerrará até que
  65. return numero; // se digite um número.
  66. }
  67. //
  68. // função lerLinha(): lê uma linha inteira até o usuário digitar <ENTER>
  69. void lerLinha(char* linha)
  70. {
  71. scanf(" %[^\n]", linha); // Com isso, lê-se uma linha inteira.
  72. }
  73.  
  74.  
  75.  
  76. // Função principal. É aqui em que se define, de fato, o programa.
  77. int main()
  78. {
  79. // Variáveis do programa
  80. int opcao; // opção do usuário: criar evento, ler, etc.
  81. int indice = 0; // quantidade de eventos já cadastrados; ou seja, nenhum (0).
  82. struct evento eventos[100]; // até 100 eventos possíveis.
  83.  
  84. // O programa vai mostrar o menu indefinidamente.
  85. // O usuário escolherá quando parar.
  86. do
  87. {
  88. // Menu de opções
  89. printf("\n\nOpção 1: criar um evento.\n");
  90. printf("Opção 2: mostrar um evento já criado.\n");
  91. printf("Opção 3: Sair do programa.\n");
  92. printf("Digite a sua opção: ")
  93. //
  94. // O usuário escolhe a opção.
  95. opcao = lerNumero();
  96. //
  97. // Para cada opção, um conjunto de instruções a executar.
  98. switch{opcao}
  99. {
  100. // Opção 1: criar um evento.
  101. case 1:
  102. printf("\nSobre o evento, informe:\n");
  103. printf("Título: ");
  104. lerLinha(eventos[indice].titulo);
  105. printf("Data de início (dia/mês/ano): ");
  106. lerLinha(eventos[indice].dataDeInicio);
  107. printf("Hora de início (hora:minuto): ");
  108. lerLinha(eventos[indice].horarioDeInicio);
  109. printf("Data de término (dia/mês/ano): ");
  110. lerLinha(eventos[imdice].dataDeTermino);
  111. printf("Hora de término (hora:minuto): ");
  112. lerLinha(eventos[indice].horarioDeTermino);
  113. dia_mes_ano(eventos[indice].dataDeCriacao); // automático: data do sistema
  114. hora_minuto(eventos[indice].horarioDeCriacao); // automático: hora do sistema
  115. printf("Descrição: ");
  116. lerLinha(eventos[indice].descricao);
  117. printf("Local de realização: ");
  118. lerLinha(eventos[indice].local);
  119. printf("Estado (confirmado, a confirmar, etc): ");
  120. lerLinha(eventos[indice].estado);
  121. printf("Categoria (pessoal, estudos, trabalho, etc): ");
  122. lerLinha(eventos[indice].categoria);
  123. printf("Recorrência (taxa de repetição): ");
  124. lerLinha(eventos[indice].recorrencia);
  125. indice = indice + 1; // Um evento foi adicionado. Incrementa o indice.
  126. break;
  127. // Opção 2: mostrar um evento já cadastrado.
  128. case 2:
  129. if(indice == 0)
  130. {
  131. printf("Não há eventos cadastrados.\n");
  132. }
  133. else
  134. {
  135. printf("Há %d eventos cadastrados.\n", indice);
  136. printf("Escolha um evento entre 0 e %d: ",indice-1);
  137. opcao = lerNumero();
  138. if (opcao < 0 || opcao > indice)
  139. {
  140. print("Número fora dos limites.\n");
  141. }
  142. else
  143. {
  144. printf("\nEvento número: %d\n", opcao);
  145. printf("Título: %s\n", eventos[opcao].titulo);
  146. printf("Data de início: %s\n",
  147. eventos[opcao].dataDeInicio);
  148. printf("Hora de início: %s\n",
  149. eventos[opcao].horaDeInicio);
  150. printf("Data de término: %s\n",
  151. eventos[opcao].dataDeTermino);
  152. printf("Hora de término: %s\n",
  153. eventos[opcao].horaDeTermino);
  154. printf("Data de criação: %s\n",
  155. eventos[opcao].dataDeCriacao);
  156. printf("Hora de criação: %s\n",
  157. eventos[opcao].horarioDeCriacao);
  158. printf("Descrição: %s\n", eventos[opcao].descricao);
  159. printf("Local de realização: %s\n", evento[opcao].local);
  160. printf("Estado: %s\n", eventos[opcao].estado);
  161. printf("Categoria: %s\n", eventos[opcao].categoria);
  162. printf("Recorrência: %s\n", eventos[opcao].recorrencia);
  163. }
  164. }
  165. break;
  166. // Opção 3: sair do programa.
  167. case 3:
  168. printf("Fim do programa. Adeus!\n");
  169. break;
  170. // Opção padrão: é interessante criar uma opção padrão para
  171. // informar o usuário quando ele digita um número fora da lista
  172. // de opções. Neste caso, 1 > número > 3.
  173. default:
  174. printf("Por favor, escolha um número entre 1 e 3.\n");
  175. }
  176. // Essa estrutura de repetição (do..while) rodará enquanto a opção
  177. // for diferente de 3.
  178. } while (opcao != 3);
  179. }

16-18/11: Leitura e escrita em arquivos

A seguir, um código-exemplo para ler e escrever em arquivos tipo texto:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. int lerNumero()
  5. {
  6. int numero;
  7. int leuNumero = 1;
  8.  
  9. do
  10. {
  11. if (leuNumero == 0)
  12. {
  13. printf("Ops! Problemas ao ler o número. Digite-o novamente: ");
  14. }
  15. leuNumero = scanf("%d", &numero);
  16. if (leuNumero == 0)
  17. {
  18. leuNumero = scanf("%*[^\n]");
  19. }
  20. } while (leuNumero == 0);
  21. return numero;
  22. }
  23.  
  24. void lerLinha(char* linha)
  25. {
  26. scanf(" %[^\n]", linha);
  27. }
  28.  
  29. int main()
  30. {
  31. FILE *arq1;
  32. char nomeDoArquivo[100];
  33. char linha[500];
  34. char *leu;
  35. int opcao;
  36.  
  37. do
  38. {
  39. printf("\n----------------------------------------");
  40. printf("----------------------------------------\n");
  41. printf("Etapa Dois - Manipulação de Arquivos\n");
  42. printf("1 - Interação direta com o usuário.\n");
  43. printf("2 - Leitura e escrita em arquivo.\n");
  44. printf("3 - Sair do programa.\n");
  45. printf("Digite a sua opção: ");
  46.  
  47. opcao = lerNumero();
  48.  
  49. switch(opcao)
  50. {
  51. case 1:
  52. printf("Digite uma frase: ");
  53. lerLinha(linha);
  54. printf("A frase é: %s\n", linha);
  55. break;
  56. case 2:
  57. printf("Informe o nome completo do arquivo: ");
  58. lerLinha(nomeDoArquivo);
  59. arq1 = fopen(nomeDoArquivo, "r");
  60. if(arq1)
  61. {
  62. printf("\nA seguir, o seu conteúdo original: \n");
  63. printf("--- Início do arquivo %s ---\n", nomeDoArquivo);
  64. do
  65. {
  66. leu = fgets(linha, sizeof(linha), arq1);
  67. if (leu)
  68. {
  69. printf("%s", linha);
  70. }
  71. } while (! feof(arq1));
  72. printf("--- Fim do arquivo %s ---\n", nomeDoArquivo);
  73. fclose(arq1);
  74. }
  75. else
  76. {
  77. printf("ATENÇÃO! Não é possível abrir o arquivo");
  78. printf(" %s para escrita.\n", nomeDoArquivo);
  79. }
  80. printf("\nDeseja mudar o seu conteúdo?\n");
  81. printf("1 - Sim\n");
  82. printf("2 - Não\n");
  83. opcao = lerNumero();
  84. switch(opcao)
  85. {
  86. case 1:
  87. arq1 = fopen(nomeDoArquivo, "w");
  88. if(arq1)
  89. {
  90. printf("Digite quantas frases quiser.\n");
  91. printf("Para terminar, digite uma linha");
  92. printf(" contendo apenas a expressão \"EOF\":\n");
  93. do
  94. {
  95. lerLinha(linha);
  96. if(strcmp(linha,"EOF") != 0) // as string são diferentes
  97. {
  98. fprintf(arq1, "%s\n", linha);
  99. }
  100. } while (strcmp(linha,"EOF"));
  101. fclose(arq1);
  102. }
  103. else
  104. {
  105. printf("ATENÇÃO! Não é possível abrir o arquivo");
  106. printf(" %s para escrita.\n", nomeDoArquivo);
  107. }
  108. break;
  109. case 2:
  110. printf("Preservando o conteúdo original...\n");
  111. break;
  112. default:
  113. printf("Número inválido.\n");
  114. }
  115. break;
  116. case 3:
  117. printf("Fim do programa.\n");
  118. break;
  119. default:
  120. printf("Digite um número entre 1 e 3, por favor.\n");
  121. }
  122. } while (opcao != 3);
  123. }

23/11: Estabelecimento de Metas

A partir de hoje, cada dia de aula será baseado em metas a cumprir.

Para hoje:

25/11: Dicionário de comandos e funções em C

  1. // Aqui, duas bibliotecas:
  2. // - A já conhecida stdio.h
  3. // - A nova string.h, que manipula strings.
  4. #include <stdio.h>
  5. #include <string.h>
  6.  
  7.  
  8. // A já conhecida função auxiliar lerLinha, que lê uma linha inteira do usuário
  9. // até aparecer o primeiro ENTER digitado.
  10. void lerLinha(char* linha)
  11. {
  12. scanf(" %[^\n]", linha);
  13. }
  14.  
  15.  
  16. // Todo programa em C precisa de pelo menos uma função, a função principal.
  17. int main()
  18. {
  19. char frase[50];
  20. char fraseTratada[50];
  21. char * auxiliar;
  22. int indice;
  23. FILE *arquivo;
  24.  
  25. // Pedindo para o usuário digitar um frase. Lendo a frase em seguida:
  26. printf("Digite uma frase (até 50 caracteres): ");
  27. lerLinha(frase);
  28.  
  29. // Repetindo a frase tal e tal. No jargão do Direito, 'ipsis verbis' :-)
  30. printf("Repetindo 'ipsis verbis': ");
  31. printf("%s", frase);
  32. printf("\n");
  33.  
  34. // Agora, uma forma diferente de mostrar a mesma informação.
  35. // Como uma string é uma sequência de caracteres, a estrutura de repetição
  36. // abaixo fará exatamente isso: mostrar na tela caractere a caractere, um do
  37. // lado do outro enquanto não for encontrado o caractere 0 (tabela ASCII),
  38. // que significa final da string.
  39. // Letra por letra, 'ipsis literis' :-)
  40. // Por uma questão didática, após cada letra impressa na tela, haverá uma
  41. // pausa de 1/4 de segundo para mostrar que, de fato, a impressão se dá
  42. // caractere, um a um.
  43. printf("Repetindo 'ipsis literis': ", frase);
  44. indice = 0;
  45. while(frase[indice] != 0)
  46. {
  47. printf("%c", frase[indice]);
  48. indice = indice + 1;
  49. // Aguarda 250ms
  50. usleep(250000);
  51. // Força a impressão de apenas um caractere na tela.
  52. // Caso contrário o sistema achará melhor aguardar para imprimir um
  53. // "lote" maior de caracteres - atrapalhando o efeito visual...
  54. fflush(stdout);
  55. }
  56. printf("\n");
  57.  
  58. // Para facilitar a vida do programador, há diversas bilbiotecas prontas com
  59. // funções bastantes úteis. A biblioteca string.h, por exemplo, foi incluída
  60. // na linha 2 deste programa. Com ela, é possível fazer manipulação de
  61. // strings ou sequências de caracteres. A função strrchr, usada abaixo, vai
  62. // identificar o índice (posição) onde aparece pela última vez um dado
  63. // caractere. Para testar, digite uma frase contendo várias palavras.
  64. // Apenas a última aparecerá. Somente ela estará depois do último espaço.
  65. printf("\n");
  66. printf("Repetindo apenas a última palavra: ");
  67. auxiliar = strrchr(frase,' ');
  68. auxiliar = auxiliar + 1;
  69. printf("%s", auxiliar);
  70. printf("\n");
  71.  
  72. // Agora, o programa irá gravar, no arquivo chamado
  73. // /tmp/arquivoTemporario.txt, a frase com o prefixo: "Frase: ":
  74. arquivo = fopen("/tmp/arquivoTemporario.txt", "w");
  75. if(arquivo)
  76. {
  77. printf("\n");
  78. fprintf(arquivo,"Frase: %s", frase);
  79. fclose(arquivo);
  80. }
  81.  
  82. // O caminho de volta, ler o arquivo, é mais complicado, uma vez que é
  83. // preciso remover o prefixo antes adicionado, "Frase: ".
  84. // Uma forma de resolver o problema é utilizar um vetor auxiliar,
  85. // fraseTratada, cujo conteúdo será parte da primeira variável, frase.
  86. // O processo parece, mas não é complexo, desde que se entenda que tratar de
  87. // strings estamos falando, na verdade, de uma cadeia de caracteres
  88. // indexadas por uma variável. A variável frase, na verdade, é um apontador
  89. // para a área de memória cujo conteúdo é:
  90. // "Frase: <a frase digitada pelo usuário no começo do programa".
  91. // O comando strchr varre o vetor, procurando pela primeira ocorrência de um
  92. // caractere em particular, no caso abaixo o espaço (' '). Ao encontrar,
  93. // associa este endereço de memória a outra variável, chamada auxiliar.
  94. // Detalhe importante: não há, até este momento, duas frases armazenadas em
  95. // memória, mas sim dois apontadores para locais diferentes de uma área de
  96. // memória. Somente depois é que há uma cópia de um vetor para outro,
  97. // criando duas áreas de memória, na função strcpy. No caso abaixo, uma
  98. // substring, ou parte da frase original, foi copiada para a nova área.
  99. // Na prática, significa que o trecho "iniciando" em auxiliar
  100. // (ponto do vetor) até o final (caractere zero) foi copiado para uma nova
  101. // área e atribuindo à variável fraseTratada este endereço.
  102. arquivo = fopen("/tmp/arquivoTemporario.txt", "r");
  103. if(arquivo)
  104. {
  105. fgets(frase, sizeof(frase), arquivo);
  106. printf("Frase retirada do arquivo: %s", frase);
  107. printf("\n");
  108. }
  109. auxiliar = strchr(frase,' ');
  110. strcpy(fraseTratada,auxiliar+1);
  111. printf("Frase retirada do arquivo e 'tratada': %s",
  112. fraseTratada);
  113. printf("\n");
  114. }

No programa acima, mais especificamente nas linhas 66 a 69, há duas variáveis apontando para uma mesma área de memória, porém em pontos distintos dessa área. Mais: é possível "movimentar-se" sobre o vetor somando ou subtraindo o valor destas variáveis. Assim funciona porque o conteúdo das variáveis do tipo string são, de fato, endereços de memória: cadeia de caracteres ou bytes. Abaixo, um exemplo de uso com a frase: Aula de SOP é muito... intrigante!:

30/11: Atividades para revisão dos conceitos de C

Construa um programa que resolva os seguintes problemas abaixo. As respostas estão em página a parte.

Manipulação de String

Abracadabra

retornará à tela

Abracadaba
Manipulação de palavras ou frases.

o programa deverá mostrar

Manipulação de palavras ou.

Interpretação da Entrada de Dados

./conversor 12

o qual deverá retornar

O número é doze.

Para tanto, leia números inteiro de 0 a 29. Para os demais números, informe que o número está fora dos limites estipulados.

Aplicação de Funções

02/12: Guia Básico de C: Funções

07/12: Guia Básico de C: Strings

09/12: Revisão de C

14/12: Prova de C

16/12: Recuperação

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. int pegaUID(char * linha)
  5. {
  6. char * token;
  7. char uid[10];
  8. int indice;
  9.  
  10. // Primeiro "corte": token apontará para o primeiro ":" da linha,
  11. // entre o nome do usuário e a letra "x" (senha oculta)
  12. token = strchr(linha, ':');
  13. if (token != NULL)
  14. {
  15. // Segundo "corte": token apontará para o segundo ":" da linha,
  16. // entre a letra "x" (senha oculta) e o UID do usuário.
  17. token = strchr(token+1, ':');
  18. if (token != NULL)
  19. {
  20. // O número está, portanto, entre posição token+1 em diante até o próximo ":"
  21. token = token + 1;
  22. // É feita uma cópia dos algarismos para uma variável nova: "uid".
  23. indice = 0;
  24. while(token[indice] != ':')
  25. {
  26. uid[indice] = token[indice];
  27. indice++;
  28. }
  29. // "Termina" a string uid com o zero:
  30. uid[indice] = '\000';
  31. // Retorna o número do UID e encerra a função neste ponto.
  32. // Lembrando que uid é uma string, tornando obrigatória a conversão de tipo:
  33. return atoi(uid);
  34. }
  35. else
  36. {
  37. // Se falhar (a linha não se refere a um usuário), retorna zero
  38. // para não atrapalhar a soma dos UIDs de todos os usuários.
  39. return 0;
  40. }
  41. }
  42. else
  43. {
  44. // Se falhar (a linha não se refere a um usuário), retorna zero
  45. // para não atrapalhar a soma dos UIDs de todos os usuários.
  46. return 0;
  47. }
  48. }
  49.  
  50. int main()
  51. {
  52. float a = 0;
  53. float b = 1;
  54. float b_original;
  55. float limite = 1000000000;
  56. FILE *etc_passwd;
  57. char linha[255];
  58. int somaUIDs = 0;
  59.  
  60. // Abre o arquivo. Se a operação de abertura retornou sucesso,
  61. if(etc_passwd = fopen("/etc/passwd", "r"))
  62. {
  63. do
  64. {
  65. // Lê do arquivo enquanto houver linhas.
  66. fgets(linha, sizeof(linha), etc_passwd);
  67. // A cada linha, soma-se o UID.
  68. somaUIDs = somaUIDs + pegaUID(linha);
  69. } while(!feof(etc_passwd));
  70. fclose(etc_passwd);
  71. }
  72. else
  73. {
  74. printf("Erro: não foi possível abrir o arquivo de usuários para leitura.\n");
  75. // Encerra a aplicação com valor de retorno negativo
  76. return -1;
  77. }
  78.  
  79. // Aqui há uma preocupação na apresentação dos dados.
  80. // Como os números são do tipo "float", por causa do limite máximo (1 bi),
  81. // é preciso ignorar a parte decimal e apresentar apenas a parte inteira,
  82. // usando neste caso o formato %.0f
  83. printf("A soma dos UIDs de todos os usuários mais a sequência de Fibonacci é:\n");
  84. printf("%d + %.0f = %.0f\n", somaUIDs, a, a + somaUIDs);
  85. while ( b + somaUIDs <= limite )
  86. {
  87. printf("%d + %.0f = %.0f\n", somaUIDs, b, b + somaUIDs);
  88. b_original = b;
  89. b = a + b;
  90. a = b_original;
  91. }
  92. }



Voltar para página principal da disciplina

Ferramentas pessoais
Espaços nominais
Variantes
Ações
Navegação
Ensino
Pesquisa
Extensão
Serviços
Imprimir/exportar
Ferramentas