Mudanças entre as edições de "Projeto final de SOP - turmas 2070114 e 2070115"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Linha 36: Linha 36:
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
int opcao, lidos;
+
  int main() {
 +
    int opcao, lidos;
  
do {
+
    do {
// aqui mostra as opções do menu
+
      // aqui mostra as opções do menu
 +
 
 +
      printf("Digite uma opção: ");
 +
      lidos = scanf("%d", &opcao);
 +
      printf("Opção escolhida=%d\n", opcao);
 +
 
 +
      // executa a ação correspondente à opção escolhida
 +
 
 +
    } while (opcao != 7); // neste exemplo, a opção 7 faz a saída do programa
 +
  }
 +
</syntaxhighlight>
 +
 
 +
Lembre que o ''scanf'' tenta ler o valor digitado de acordo com a especificação contida no formato (no exemplo, "%d" que corresponde a um número inteiro). Se ele conseguir, retorna a quantidade de valores lidos (no exemplo isto é guardado na variável ''lidos''). Assim, se ''scanf'' no exemplo acima não conseguir ler o valor digitado, irá retornar 0. O problema é que neste caso o valor que foi digitado fica pendente em memória, quer dizer, o ''scanf'' não descarta esse valor, apesar de não ter conseguido lê-lo. Na próxima vez que o ''scanf'' for chamado ele vai tentar novamente ler esse mesmo valor, e se der erro o valor vai continuar pendente. Isto só se reverterá quando o ''scanf'' especificar um tipo de dado compatível com o valor pendente, ou então se o formato especificar que se deve descartá-lo. Veja assim o exemplo abaixo:
 +
 
 +
<syntaxhighlight lang=c>
 +
  int main() {
 +
    int x, n;
 +
 
 +
    do {
 +
      // aqui mostra as opções do menu
  
printf("Digite uma opção: ");
+
      // o laço abaixo faz com que se repita a leitura pelo teclado até que se digite um
lidos = scanf("%d", &opcao);
+
      // número inteiro.
printf("Opção escolhida=%d\n", opcao);
+
      do {
 +
        printf("Digite uma opção: ");
 +
        n = scanf("%d", &x);
  
// executa a ação correspondente à opção escolhida
+
        // se n == 0, então scanf não conseguiu ler o valor, porque ele não é do tipo inteiro.
 +
        // Então o valor digitado deve ser descartado. Para descartar tudo o que foi digitado, deve-se
 +
        // chamar de novo o scanf, mas com o formato "%*[^\n]". Isto joga fora toda a linha digitada.
 +
        // Uma explicação sobre formatos do scanf está na sua página de manual (execute "man scanf").
 +
        if (n == 0) {
 +
          n = scanf("%*[^\n]");
 +
        }
 +
      } while (n == 0);
  
} while (opcao != 7); // neste exemplo, a opção 7 faz a saída do programa
+
      printf("Opção escolhida=%d\n", opcao);
  
 +
      // executa a ação correspondente à opção escolhida
 +
 +
    } while (opcao != 7); // neste exemplo, a opção 7 faz a saída do programa
 +
  }
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Lembre que o ''scanf'' tenta ler o valor digitado de acordo com a especificação contida no formato (no exemplo, "%d" que corresponde a um número inteiro). Se ele conseguir, retorna a quantidade de valores lidos (no exemplo isto é guardado na variável ''lidos''). Assim, se ''scanf'' no exemplo acima não conseguir ler o valor digitado, irá retornar 0. O problema é que neste caso o valor que foi digitado fica pendente em memória, quer dizer, o ''scanf'' não descarta esse valor, apesar de não ter conseguido lê-lo. Na próxima vez que o ''scanf'' for chamado ele vai tentar novamente ler esse mesmo valor, e se der erro o valor vai continuar pendente. Isto só se reverterá quando o ''scanf'' especificar um tipo de dado compatível com o valor pendente, ou então se o formato especificar que se deve descartá-lo. Veja assim o exemplo abaixo:
+
Esse problema da leitura de valores com ''scanf'' pode aparecer em outras partes da agenda. Então seria mais prático se o algoritmo contido no programa acima, que repete a leitura do teclado até que se consiga ler uma valor válido, pudesse ser reaproveitado. Isto é um bom exemplo do uso de funções da linguagem C. Uma função é um algoritmo a ser reutilizado. Como todo algoritmo, deve ter dados de entrada, uma sequência de instruções, e fornecer dados de saída como resultado. Veja o exemplo abaixo, que se baseia na leitura do teclado com ''scanf'':
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
   int x, n;
+
   // Função meu_scanf:
 +
  // Dados de entrada: parâmetro "char * mensagem" é o texto a ser mostrado antes de ler do teclado.
 +
  // Dado de saída: meu_scanf devolve (retorna) um número inteiro que corresponde ao valor lido.
  
   do {
+
   int meu_scanf(char * mensagem) {
     // aqui mostra as opções do menu
+
     int x, n;
  
    // o laço abaixo faz com que se repita a leitura pelo teclado até que se digite um
 
    // número inteiro.
 
 
     do {
 
     do {
       printf("Digite uma opção: ");
+
       printf(mensagem);
 
       n = scanf("%d", &x);
 
       n = scanf("%d", &x);
  
Linha 74: Linha 107:
 
     } while (n == 0);
 
     } while (n == 0);
  
     printf("Opção escolhida=%d\n", opcao);
+
     // aqui meu_scanf retorna o valor lido, que está contido na variável "x"
 +
    return x;
 +
  }
 +
 
 +
  int main() {
 +
    int opcao;
 +
 
 +
    do {
 +
      // aqui mostra as opções do menu
 +
 
 +
      // chama a função "meu_scanf" para ler um número inteiro do teclado.
 +
      opcao = meu_scanf("Digite uma opção: ");
 +
 
 +
      printf("Opção escolhida=%d\n", opcao);
  
    // executa a ação correspondente à opção escolhida
+
      // executa a ação correspondente à opção escolhida
  
  } while (opcao != 7); // neste exemplo, a opção 7 faz a saída do programa
+
    } while (opcao != 7); // neste exemplo, a opção 7 faz a saída do programa
 +
  }
  
 
</syntaxhighlight>
 
</syntaxhighlight>

Edição das 19h47min de 23 de outubro de 2009

Etapa 1

Interface com o usuário da agenda, modelagem de eventos e armazenamento da agenda em memória

Interface

A agenda deve apresentar uma interface de texto. Nessa interface o usuário pode escolher uma das seguintes opções, com as respectivas operações a serem desencadeadas:

  1. Criar agenda: criar uma nova agenda, que deve ter um nome único.
  2. Ler agenda: carregar para a memória uma agenda que reside em um arquivo.
  3. Gravar agenda: gravar em um arquivo a agenda que reside em mempória.
  4. Inserir evento: adicionar um novo evento à agenda, que não pode conflitar com o horário de outro evento que já exista.
  5. Mostrar eventos: mostrar em ordem cronológica todos os eventos da agenda.
  6. Remover evento: remover um evento específico.
  7. Sair: sair do programa.

Eventos

Os eventos devem ser modelados para que contenham as seguintes informações:

  • Título
  • Descrição
  • Data e horário de criação
  • Data e horário de início
  • Data e horário de término
  • Categoria
  • Local
  • Status
  • Recorrência

No programa um evento deve ser guardado em uma variável do tipo struct. Uma struct funciona como um registro, em que diferentes valores logicamente relacionados são agrupados e podem ser manipulados usando uma única variável.

23/10: início

Focou-se a criação da interface, que mostra as opções para o usuário e aguarda que ele digite o número da opção escolhida. Para que a interface repita até que o usuário escolha a opção correspodente a sair do programa, usou-se uma estrutura de repetição while. Para o processamento da opção escolhida discutiu-se que a forma mais conveniente é usar a estrutura de decisão switch ... case (equivalente ao Escolhe ... caso do Portugol). Um resumo sobre isto pode ser visto nas [1].

Algumas equipes identificaram um problema na leitura da opção pelo teclado. Se o usuário digitar algo que não seja um número inteiro, a interface entra em loop, sempre mostrando o menu de opções. Para exemplificar, veja abaixo a leitura de um número inteiro feita com scanf:

  int main() {
    int opcao, lidos;

    do {
      // aqui mostra as opções do menu

      printf("Digite uma opção: ");
      lidos = scanf("%d", &opcao);
      printf("Opção escolhida=%d\n", opcao);

      // executa a ação correspondente à opção escolhida

    } while (opcao != 7); // neste exemplo, a opção 7 faz a saída do programa
  }

Lembre que o scanf tenta ler o valor digitado de acordo com a especificação contida no formato (no exemplo, "%d" que corresponde a um número inteiro). Se ele conseguir, retorna a quantidade de valores lidos (no exemplo isto é guardado na variável lidos). Assim, se scanf no exemplo acima não conseguir ler o valor digitado, irá retornar 0. O problema é que neste caso o valor que foi digitado fica pendente em memória, quer dizer, o scanf não descarta esse valor, apesar de não ter conseguido lê-lo. Na próxima vez que o scanf for chamado ele vai tentar novamente ler esse mesmo valor, e se der erro o valor vai continuar pendente. Isto só se reverterá quando o scanf especificar um tipo de dado compatível com o valor pendente, ou então se o formato especificar que se deve descartá-lo. Veja assim o exemplo abaixo:

  int main() {
    int x, n;

    do {
      // aqui mostra as opções do menu

      // o laço abaixo faz com que se repita a leitura pelo teclado até que se digite um
      // número inteiro.
      do {
        printf("Digite uma opção: ");
        n = scanf("%d", &x);

        // se n == 0, então scanf não conseguiu ler o valor, porque ele não é do tipo inteiro.
        // Então o valor digitado deve ser descartado. Para descartar tudo o que foi digitado, deve-se
        // chamar de novo o scanf, mas com o formato "%*[^\n]". Isto joga fora toda a linha digitada.
        // Uma explicação sobre formatos do scanf está na sua página de manual (execute "man scanf").
        if (n == 0) {
          n = scanf("%*[^\n]");
        }
      } while (n == 0);

      printf("Opção escolhida=%d\n", opcao);

      // executa a ação correspondente à opção escolhida

    } while (opcao != 7); // neste exemplo, a opção 7 faz a saída do programa
  }

Esse problema da leitura de valores com scanf pode aparecer em outras partes da agenda. Então seria mais prático se o algoritmo contido no programa acima, que repete a leitura do teclado até que se consiga ler uma valor válido, pudesse ser reaproveitado. Isto é um bom exemplo do uso de funções da linguagem C. Uma função é um algoritmo a ser reutilizado. Como todo algoritmo, deve ter dados de entrada, uma sequência de instruções, e fornecer dados de saída como resultado. Veja o exemplo abaixo, que se baseia na leitura do teclado com scanf:

  // Função meu_scanf:
  // Dados de entrada: parâmetro "char * mensagem" é o texto a ser mostrado antes de ler do teclado.
  // Dado de saída: meu_scanf devolve (retorna) um número inteiro que corresponde ao valor lido.

  int meu_scanf(char * mensagem) {
    int x, n;

    do {
      printf(mensagem);
      n = scanf("%d", &x);

      // se n == 0, então scanf não conseguiu ler o valor, porque ele não é do tipo inteiro.
      // Então o valor digitado deve ser descartado. Para descartar tudo o que foi digitado, deve-se
      // chamar de novo o scanf, mas com o formato "%*[^\n]". Isto joga fora toda a linha digitada.
      // Uma explicação sobre formatos do scanf está na sua página de manual (execute "man scanf").
      if (n == 0) {
        n = scanf("%*[^\n]");
      }
    } while (n == 0);

    // aqui meu_scanf retorna o valor lido, que está contido na variável "x"
    return x;
  }

  int main() {
    int opcao;

    do {
      // aqui mostra as opções do menu

      // chama a função "meu_scanf" para ler um número inteiro do teclado.
      opcao = meu_scanf("Digite uma opção: ");

      printf("Opção escolhida=%d\n", opcao);

      // executa a ação correspondente à opção escolhida

    } while (opcao != 7); // neste exemplo, a opção 7 faz a saída do programa
  }