SOP-2010-1-sobral

De MediaWiki do Campus São José
Revisão de 12h14min de 9 de julho de 2010 por Msobral (discussão | contribs) (→‎09/07: recuperação)
(dif) ← Edição anterior | Revisão atual (dif) | Versão posterior → (dif)
Ir para navegação Ir para pesquisar

Sistemas Operacionais e Introdução à Programação - 2010-1

Informações gerais

Professor: Marcelo Maia Sobral
Email: msobral@gmail.com
Skype: mm-sobral
Lista de email (forum): sop-ifsc@googlegroups.com
Atendimento paralelo: 2a feira 10h - 12 h, 4a feira 10h - 12 h ou 16h - 17 h (no Laboratório de Desenvolvimento de Tele)
Reavaliação (recuperação): no final do semestre

Softwares

Será usado como plataforma de estudo o sistema operacional Ubuntu Linux 9.10. Para obtê-lo há essas opções:

  1. Trazer um CD-R virgem para que eu faça a cópia aqui no IFSC
  2. Fazer o download por conta própria (aprox. 700 MB)
  3. Usar uma máquina virtual do VirtualBox já preparada por mim (menos recomendado, pois o Linux roda mais lento)
    • Trazer um DVD-R ou pendrive com ao menos 4 GB livres.
    • Instalar o VirtualBox em seu computador para executar a máquina virtual

ATENÇÃO: é muito importante que se providencie o quanto antes a instalação do Ubuntu em seu computador. Sem ele você não poderá fazer os exercícios sugeridos, o que atrapalhará seu aproveitamento na disciplina ! O bom andamento do estudo depende muito de não deixar acumular o conteúdo e os exercícios. Acostume a criar uma rotina de estudo, procurando resolver os problemas apresentados e procurando o professor (ou contatando-o por email) para tirar dúvidas.

Referências adicionais

Sistemas operacionais

19/02: Apresentação

Apresentação da disciplina: plano de ensino, avaliação, abordagem pedagógica.

24/02: Introdução a sistemas computacionais

Sistemas computacionais; visão geral de sistemas operacionais; histórico de sistemas operacionais (resumo).

Videos ilustrativos:


Alguns textos interessantes sobre história dos sistemas operacionais:

26/02: Introdução ao Linux

Uso básico da interface gráfica e de texto. Apostila Gerência de Redes (prof. Odilson), capítulos 3 a 5, e capítulos 6 e 7 do Guia Foca Linux Iniciante.

Objetivos:

  1. Conhecer o sistema operacional Linux
  2. Usar a interface de linha de comando (shell)
  3. Usar comandos básicos para visualização e manipulação de processos
  4. Usar comandos básicos para manipulação de arquivos e diretórios
  5. Conhecer a estrutura de diretórios do Linux

03/03: Processos e memória

Processos e multiprogramação: uma visão geral sobre programas, processos, ciclos de um processo, multiprogramação e escalonamento. Ver apostila do prof. Odilson, capítulo 3, e capítulo 5 do Guia Foca Linux Iniciante.

Gerência de memória: visão geral sobre o uso de memória no sistema operacional e pelos processos Uso do laboratório para ilustrar conceitos.

Vários utilitários (programas auxiliares) existem para obter informações do sistema operacional sobre processos e memória. Alguns trabalham em modo texto, como:

  • ps: lista os processos existentes
  • pstree: lista os processos existentes mas de forma hierárquica
  • top: lista os processos mais ativos, junto com informações globais sobre uso dos recursos no sistema operacional (memória, processador, memória virtual, quantidade de processos, carga de trabalho)
  • atop: o mesmo que top, mas com maior detalhamento do uso de recursos mantidos pelo sistema operacional
  • mpstat: mostra estatísticas de uso do processador
  • free: mostra o uso de memória
  • vmstat: mostra o uso de memória, discos e processador no último intervalo de tempo.

Existem também utilitários no modo gráfico. Por exemplo, no Ubuntu há o "Monitor do sistema":

Monitor1.png
Para executar o Monitor do Sistema




Monitor2.png Monitor3.png

Telas do monitor do Sistema

05/03: Sistemas de arquivos

Visão geral sobre sistemas de arquivos: definição de arquivo e diretório, formas de armazenamento em media (discos, DVD, ...), segurança (controle de acesso). Uso do laboratório para ilustrar conceitos.

Houve aula somente até 14:00 h, quando a turma foi encaminhada ao auditório para assistir às apresentações dos pré-projetos do Tecnólogo.

10/03: Localização de arquivos, redirecionamentos e pipes

Localização de arquivos e diretórios: comando find:

A procura de arquivos e diretórios pode ser automatizada com o comando find. Por exemplo, para localizar todos os arquivos ou diretórios chamados default, e que estejam abaixo de /etc:

aluno@D1:~$ find /etc -name default -print
/etc/default
/etc/calendar/default
/etc/X11/xinit/xinput.d/default
aluno@D1:~$

Uso do find :

find pathname [opões]

... sendo pathname o diretório abaixo de que se deseja fazer a busca. As opções servem para selecionar arquivos e diretórios durante a busca, e também para executar ações para cada um deles que for encontrado. Algumas opções mais comuns:

  • -name nome: seleciona arquivos ou diretórios cujos nomes sejam nome' . Essa opção aceita wildcards (* e ?)
  • -type tipo: seleciona apenas o tipo' indicado, que pode ser:
    • d: diretório
    • f: arquivo
    • l: link simbólico (ou atalho)
  • -perm modo: seleciona apenas arquivos ou diretórios que possuam as permissões indicadas em modo
  • -size tamanho: seleciona apenas arquivos com tamanho de acordo com o especificado (em bytes)
  • -mtime n: seleciona apenas arquivos ou diretórios modificados a n * 24 horas atrás
  • -atime n: seleciona apenas arquivos ou diretórios acessados a n * 24 horas atrás
  • -user usuario: seleciona apenas arquivos ou diretórios pertencentes a usuario
  • -exec comando \;: executa comando para cada arquivo ou diretório encontrado. Ex:
    • find /tmp -type f -mtime +7 -exec rm -f {} \; : remove todos os arquivos dentro de /tmp que estejam há 7 dias sem serem modificados. A sequência {} é substituída pelo nome do arquivo encontrado.

... e muitas outras (consulte o manual do find).

Atividade

  1. Encontre o arquivo lsusb', que se encontra em algum subdiretório dentro de /usr
  2. Encontre os arquivos dentro de /usr cujos tamanhos sejam maiores que 20 MB
  3. Encontre os subdiretórios lib, que estão dentro de /usr
  4. Localize todos os arquivos executáveis (i.e., os programas) que existem abaixo de /lib
  5. Localize todos os arquivos pertencentes ao usuário aluno e que estejam dentro de /tmp

Redirecionamento de saída padrão

Todo processo possui uma saída padrão, que corresponde a um arquivo ou dispositivo onde os dados de saída do processo (ex: mensagens de texto) serão mostrados. Normalmente a saída padrão de um processo é a tela do terminal, mas ela pode ser redirecionada para um arquivo ou para outro dispositivo. Assim, as mensagens de texto que um processo gera podem ser guardadas em um arquivo para posterior utilização. No exemplo abaixo, a listagem dos processos foi guardada no arquivo processos.txt:

aluno@D1:~$ ps ax > processos.txt
aluno@D1:~$

O redirecionamento de saída padrão se faz com o símbolo > seguido do nome do arquivo. Note que nada aparece na tela, uma vez que a saída se tornou o arquivo processos.txt. Após executar o comando acima, veja o conteúdo de processos.txt:

aluno@D1:~$ less processos.txt
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:03 /sbin/init
    2 ?        S<     0:00 [kthreadd]
    3 ?        S<     0:00 [migration/0]
    4 ?        S<     0:00 [ksoftirqd/0]
    5 ?        S<     0:00 [watchdog/0]
    6 ?        S<     0:00 [migration/1]
    7 ?        S<     0:00 [ksoftirqd/1]
    8 ?        S<     0:00 [watchdog/1]
    9 ?        S<     0:00 [events/0]
   10 ?        S<     0:00 [events/1]
   11 ?        S<     0:00 [khelper]
   12 ?        S<     0:00 [kstop/0]
   13 ?        S<     0:00 [kstop/1]
   14 ?        S<     0:00 [kintegrityd/0]
   15 ?        S<     0:00 [kintegrityd/1]
   16 ?        S<     0:00 [kblockd/0]
   17 ?        S<     0:00 [kblockd/1]
   18 ?        S<     0:00 [kacpid]
   19 ?        S<     0:00 [kacpi_notify]
   20 ?        S<     0:00 [cqueue]
   21 ?        S<     0:00 [ata/0]
   22 ?        S<     0:00 [ata/1]
processos.txt

Como se pode ver, o texto que apareceria na tela foi guardado em processos.txt. Experimente executar novamente o comando ps ax > processos.txt e veja o resultado. O que aconteceu com o arquivo processos.txt ?

Quando se deseja redirecionar a saída de um processo para um arquivo, porém preservando o conteúdo original desse arquivo, deve-se executar o comando da seguinte forma:

aluno@D1:~$ ps ax >> processos.txt
aluno@D1:~$

... quer dizer, em vez de usar > usa-se >>.

Redirecionamento de entrada padrão

Assim como existe uma saída padrão, todo processo possui uma entrada padrão que corresponde ao arquivo ou dispositivo de onde por default são obtidos os dados de entrada. Normalmente a entrada padrão corresponde ao teclado do terminal, mas pode ser redirecionada para outro arquivo ou dispositivo. No exemplo abaixo, usa-se o programa wc para contar as linhas, palavras e caracteres contidos no arquivo processos.txt:

aluno@D1:~$ ps ax > processos.txt
aluno@D1:~$ wc < processos.txt
 137  810 7807 processos.txt
aluno@D1:~$

No exemplo acima, gravou-se em processos.txt o resultado do comando ps ax' , e depois usou-se wc para contar linhas, palavras e caracteres desse arquivo. O efeito combinado é a contagem de quantos processos existem no sistema nesse momento (representado pelo número de linhas contidas em processos.txt).

Ao contrário do caso da saída padrão, não é tão comum se usar redirecionamento de entrada padrão. No entanto há um recurso adicional provido pelo sistema operacional que explora a combinação de ambas, e que possibilita combinar as funcionalidades de diferentes programas.

Pipes

Em sistemas operacionais Unix, é possível conectar a saída padrão de um processo à entrada padrão de outro processo, e a isto se chama pipe (que pode ser traduzido como duto ou tubo). Com isto, os dados de saída de um processo serão os dados de entrada de outro processo, o que pode ser explorado para realizar diferentes tarefas. Por exemplo, retomando a contagem de processos vista na seção anterior:

aluno@D1:~$ ps ax | wc
 137  810 7807 processos.txt
aluno@D1:~$

O símbolo de pipe é a barra vertical |. Ao se executarem os comandos acima unidos pelo pipe, a listagem de processos gerada pelo ps ax é automaticamente enviada para a entrada padrão do comando wc. O resultado é a contagem de processos existentes no sistema.

Podem-se ligar mais de dois processos usando pipes. Assim, cria-se um encadeamento de processos, em que a saída padrão de um processo alimenta a entrada padrão do próximo processo. Por exemplo, para se contarem os processos do usuário aluno:

aluno@D1:~$ ps aux | grep aluno | wc
     47     568    5195
aluno@D1:~$

02/03: Redirecionamentos, pipes, usuários e grupos

Uso de redirecionamentos e pipes. Para entender a utilidade desses recursos, alguns comandos adicionais serão vistos:

  • cut: divide as linhas dos arquivos em colunas, e mostra colunas específicas
  • grep: mostra linhas de arquivos que contenham determinada palavra ou padrão de caracteres
  • sort: ordena as linhas de um arquivo
  • paste: combina linhas de arquivos
  • wc: conta linhas, palavras e caracteres
  • tail: mostra as últimas linhas de um arquivo
  • head: mostra as primeiras linhas de um arquivo
  • du: mostra a utilização de disco de um determinado arquivo ou diretório

Conceitos de usuários e grupos. Comandos relacionados:

  • whoami: mostra quem é o usuário dono do processo atual (que é o shell)
  • users: mostra os usuários logados no sistema
  • who: mostra os usuários logados no msistema, porém com mais informações sobre cada um deles
  • w: mostra o que os usuários logados estão fazendo agora
  • finger: mostra informações sobre um ou mais usuários
  • passwd: muda a senha de um usuário
  • last: mostra o histórico de usuários logados
  • chfn: muda diversas informações de um usuário (aquelas visíveis com finger)
  • groups: grupos a que um usuário pertence

As informações sobre os usuários estão guardadas no arquivo /etc/passwd. Mas podem estar armazenadas também na rede ... As informações sobre os grupos estão guardadas no arquivo /etc/group.

Atividade

  1. Mostre quais os usuários que existem, junto com seus nomes completos (essa informação está no arquivo /etc/passwd)
  2. Repita o item anterior, mas mostrando em ordem alfabética direta e reversa
  3. Repita o ítem anterior, mas mostrando apenas o último usuário em ordem alfabética, e depois o primeiro usuário
  4. Conte quantos usuários têm o nome completo iniciando com a letra 'A'
  5. Imagine que seu diretório de trabalho está muito cheio, e você quer identificar que arquivos ou subdiretórios estão ocupando mais espaço. Combine os comandos du e sort para descobrir isto.
  6. Conte quantos processos pertencem ao usuário aluno, e quantos pertencem a root.
  7. Descubra quantos arquivos existem em seu diretório pessoal (/home/aluno), incluindo os subdiretórios
  8. Sejam dois arquivos como mostrado abaixo. Combine suas linhas e mostre o resultado em ordem alfabética. Mostre também o resultado em ordem de quantidade.
    abacaxi
    laranja
    morango
    manga
    goiaba
    limão
    

    1 kg
    500 g
    100 g
    2 kg
    1 kg
    300 g
    

17/03: Editores de texto

Ver capítulo 9 da apostila do prof. Odilson.

Uso de editores de texto:

  • vi: um editor de programas com recursos avançados de edição. Mas usa uma interface textual com comandos que devem ser memorizados ... algo anacrônico, mas funciona. Como motivação para usá-lo, praticamente todo computador com Unix (não somente Linux) vem com esse editor previamente instalado.
  • nano: um outro editor mais simples, com menos funcionalidades que o vi, porém um pouco mais amigável.

vi

O editor vi é bastante simples e muito utilizado por ser encontrado em todas as distribuições Linux. Poderíamos optar por um editor um pouco mais avançado, mas com o inconveniente de encontrarmos uma distribuição/instalação onde não dispuséssemos deste editor. O editor vi não tem como objetivo formatar textos: negritos, indentações, justificação, etc. Na prática o vi é muito usado para editar textos que não necessitam de formatação em nenhum momento, como por exemplo códigos fonte de programas em alguma linguagem de programação, e que não carreguem o texto com caracteres especiais. Assim, esse editor também é chamado de editor de programas.

Modos de operação

O editor vi tem três modos de operação distintos: modo insert , modo escape (também chamado de modo comando), modo last line;

  • insert: usado para a digitação do texto. Neste modo o vi funciona como uma máquina de escrever, com a diferença de que você pode retroceder sobre o texto já digitado para corrigir eventuais erros. Cada caracter que for digitado aparecerá na tela exatamente como foi digitado.
  • escape: os caracteres comuns (letras, números e sinais de pontuação) têm um significado especial e quase todos os caracteres funcionam como comandos; portanto, existem muitos comandos. Alguns comandos servem para passar para o modo insert, outros para movimentar o cursor sobre as linhas do texto, alterar trechos do texto, buscar palavras, etc.
  • last line: os comandos são digitados em uma linha especial que aparece no final da tela quando se digita : (dois pontos) no modo escape. Parte dos comandos do modo escape possuem similares no modo last line, como por exemplo os comandos de edição, que veremos mais adiante. Os comandos no modo last line devem ser seguidos por ENTER, contrariamente ao que acontece no modo escape.

Criação e edição de arquivos

Guia rápido sobre vi

Para criarmos um arquivo simplesmente digitamos vi seguido do nome do arquivo. Por exemplo:

vi primeiro.arquivo

Após isto será aberto o editor com conteúdo vazio, no modo comando. Para podermos editar qualquer coisa devemos entrar no modo inserção, para isto basta teclarmos <i> (aparecerá -- INSERT -- na base da janela). Em seguida digitamos o texto propriamente dito, usando o teclado normalmente.

Para salvarmos o texto devemos teclar <Esc> (modo comando), <:> (modo last line> e <w> (write). Assim teremos o nosso texto salvo.

Agora vamos a alguns comandos úteis:

  • Copiar algumas linhas do texto: colocamos o cursor no início do texto a ser copiado e, no modo de comando, teclamos <n>+<y>+<y>, onde n é número de linhas que desejamos copiar. Por exemplo se digitarmos <5>+<y>+<y> copiaremos 5 linhas para o buffer.
  • Excluir algumas linhas do texto: colocamos o cursor no início do texto a ser excuído e, no modo de comando, teclamos <n>+<d>+<d>, onde n é número de linhas que desejamos copiar. Por exemplo se digitarmos <3>+<y>+<y> apagaremos 3 linhas do texto mas que serão armazenadas no buffer.
  • Colar o conteúdo do buffer para alguma parte do texto: colocamos o cursor no ponto onde pretendemos inserir o texto e, no modo de comando, teclamos

    (paste) para inserirmos o texto abaixo da linha do cursor e

    para inserir o texto acima da linha do cursor.

  • Encontrar alguma palavra: no modo de comando, teclamos </> <palavra> <Enter>. O vi mostrará a primeira ocorrência da mesma. Para ir para a próxima ocorrência teclamos <n> (next), e para a ocorrência anterior teclamos <p> (previous)
  • Substituir uma palavra por outra: no modo de comando, teclamos <:s/><palavra></><outra><Enter>. Por exemplo se quisermos substituir velha por nova: <:s/><velha></><nova><Enter>, assim teremos a troca da primeira ocorrência de velha por nova. Para substituirmos todas as ocorrências acrescentamos <%> entre <:> e <s> do caso anterior. Exemplo: <:%s/><velha></><nova><Enter>
  • Inserir o conteúdo de um texto externo em nosso texto: no modo de comando, teclamos <:r>+<caminho/arquivo>+<Enter>.
  • Salvar com outro nome: no modo de comando, teclamos <:w>+<novo.nome>+<Enter>.


Uma lista de comandos resumida segue abaixo:

  • 0: vai para o início da linha
  • $: vai para o final da linha
  • gg: vai para a primeira linha
  • G: vai para a última linha
  • n: vai para a linha n (n é um número)
  • w: vai para a próxima palavra
  • b: vai para a palavra anterior
  • x: apaga um caractere à direita do cursor
  • X: apaga um caractere à esquerda do cursor
  • dd: apaga-se uma linha inteira
  • D: apaga do cursor até o final da linha
  • dw: apaga até a próxima palavra
  • dfs: apaga até a próxima ocorrência do caractere s
  • a: entra-se em inserção uma posição à frente do cursor
  • i: entra-se em inserção uma posição antes do cursor
  • rc: substitui o caractere sob o cursor pelo caractere c
  • cwnova: substitui a palavra a partir do cursor pela palavra nova
  • :w: grava o arquivo
  • :w um_arquivo: grava o conteúdo no arquivo um_arquivo
  • :w! um_arquivo: grava o conteúdo no arquivo um_arquivo, sobrescrevendo-o caso exista
  • :r um_arquivo: lê um_arquivo e insere seu conteúdo a partir do cursor
  • :r!comando: executa comando no shell, e insere seu resultado a partir do cursor
  • :q: sai do vi (termina o editor)
  • :q!: sai do vi, descartando as modificações

Atividade

  1. Crie e edite um arquivo contendo seus dados pessoais, de forma que possam ser usados em sua assinatura de email. Salve-o com nome signature.txt.
  2. Edite o arquivo Leiame.txt. Logo após suas duas primeiras linhas (título de seu conteúdo), adicione uma linha com seu nome, matrícula e turma. Salve o arquivo modificado.
  3. Em Leiame.txt acrescente a data de hoje após a última linha.
  4. Em Leiame.txt remova a 2a questão. Apague também a linha em branco logo a seguir. Em seguida renumere as próximas questões, para que fiquem na sequência correta.
  5. Em Leiame.txt localize a 3a ocorrência das palavras "diretorio" ou "diretorios", e remova-a. Localize então a ocorrência imediatamente anterior, e substitua por maiúsculas.
  6. Em Leiame.txt localize as ocorrências da palavra “diretorio”, e substitua por “subdiretorio”, com exceção de quando se referir ao diretório raiz. Salve o arquivo modificado.
  7. Em Leiame.txt, acrescente o resultado da listagem do diretório /home logo após a questão 5.
  8. Salve o arquivo resultante com o nome Leiame2.txt. O arquivo resultante deve ter mais ou menos este conteúdo.

24/03: Compactadores de arquivos

Vários compactadores de arquivos existem no Linux:

  • compress: compactador mais antigo e comum nos Unix em geral. Gera arquivos compactados com extensão .Z. Precisa do pacote de software ncompress no Ubuntu. Exemplo de uso:
    msobral@dell-iron:~$ ls -l API-changes.txt 
    -rw-r--r-- 1 msobral professores 51759 2010-03-24 11:32 API-changes.txt
    msobral@dell-iron:~$ compress API-changes.txt
    msobral@dell-iron:~$ ls -l API* 
    -rw-r--r-- 1 msobral professores 22781 2010-03-24 11:32 API-changes.txt.Z
    msobral@dell-iron:~$ uncompress API-changes.txt.Z 
    msobral@dell-iron:~$ ls -l API*
    -rw-r--r-- 1 msobral professores 51759 2010-03-24 11:32 API-changes.txt
    msobral@dell-iron:~$
    
  • GNU zip: compactador bastante utilizado, com maior poder de compactação que compress. Gera arquivos compactados com extensão .gz. Já vem instalado no Ubuntu. Exemplo de uso:
    msobral@dell-iron:~$ gzip API-changes.txt
    msobral@dell-iron:~$ ls -l API* 
    -rw-r--r-- 1 msobral professores 17651 2010-03-24 11:32 API-changes.txt.gz
    msobral@dell-iron:~$ gunzip API-changes.txt.gz
    msobral@dell-iron:~$ ls -l API*
    -rw-r--r-- 1 msobral professores 51759 2010-03-24 11:32 API-changes.txt
    msobral@dell-iron:~$
    
  • bzip2: vem sendo bastante usado por ter um poder de compactação ainda maior, porém à custa de maior processamento (compactação fica mais lenta). Gera arquivos compactados com extensão .bz2. Também já vem instalado no Ubuntu.
    msobral@dell-iron:~$ bzip2 API-changes.txt
    msobral@dell-iron:~$ ls -l API* 
    -rw-r--r-- 1 msobral professores 15804 2010-03-24 11:32 API-changes.txt.bz2
    msobral@dell-iron:~$ bunzip2 API-changes.txt.gz
    msobral@dell-iron:~$ ls -l API*
    -rw-r--r-- 1 msobral professores 51759 2010-03-24 11:32 API-changes.txt
    msobral@dell-iron:~$
    
  • ... outros menos populares no mundo do Linux, tais como zip, rar e zoo.

Note que os compactadores compress, gzip, e bzip2 compactam um arquivo por vez. Assim, com eles não é possível juntar vários arquivos e diretórios dentro de um único arquivo compactado (o que se faz corriqueiramente com zip ou rar ...). Portanto, se for necessário compactar um diretório ou um conjunto de arquivos, o melhor é combinar um compactador com o programa tar.

O programa tar é um utilitário do mundo Unix originalmente criado para backups em fita (daí seu nome: TApe aRchiver, se bem que tar é também um trocadilho que pode significar piche, pois ele de certa forma gruda um arquivo ao outro). O resultado da execução do tar é um arquivo contendo todos os arquivos e diretórios que foram selecionados para inclusão. Esse arquivo tar pode ser então compactado, obtendo-se algo parecido com o que faz zip ou rar.

Mas porque não usar então zip e rar ? Afinal, eles existem também no Linux ... No entanto, esses compactadores nasceram no mundo do antigo MS-DOS, e assim não são capazes de armazenar todos os atributos de arquivos que existem em sistemas Unix (informações tais como usuário e grupo dono do arquivo, permissões de acesso, tipo do arquivo, datas de último acesso e modificação). O tar, pelo contrário, consegue preservar esses atributos, e por isto se torna mais adequado para uso no Unix em geral.

Uso do tar:

  • Criação de arquivo tar:
    tar cf nome_arquivo.tar arquivo_ou_diretorio1 [arquivo_ou_diretorio2 ...]
    
  • Mostrar o conteúdo de arquivo tar:
    tar tvf nome_arquivo.tar
    
  • Extrair conteúdo de arquivo tar:
    tar xf nome_arquivo.tar
    

Os usos acima não compactam os arquivos incluídos dentro do arquivo tar. Para compactá-los deve-se adicionar uma opção de compactação:

  • Criação de arquivo tar compactado:
    • Com compress:
      tar cZf nome_arquivo.tar.Z arquivo_ou_diretorio1 [arquivo_ou_diretorio2 ...]
      
    • Com gzip:
      tar czf nome_arquivo.tar.gz arquivo_ou_diretorio1 [arquivo_ou_diretorio2 ...]
      
    • Com bzip2:
      tar cjf nome_arquivo.tar.bz2 arquivo_ou_diretorio1 [arquivo_ou_diretorio2 ...]
      
  • Mostrar o conteúdo de arquivo tar:
    • Com compress:
      tar tvZf nome_arquivo.tar.Z
      
    • Com gzip:
      tar tvzf nome_arquivo.tar.gz
      
    • Com bzip2:
      tar tvjf nome_arquivo.tar.bz2
      
  • Extrair conteúdo de arquivo tar:
    • Com compress:
      tar xZf nome_arquivo.tar.Z
      
    • Com gzip:
      tar xzf nome_arquivo.tar.gz
      
    • Com bzip2:
      tar xjf nome_arquivo.tar.bz2
      

Atividade

  1. Procure um arquivo de texto (extensão .txt, .html, ou .doc) com ao menos 100 kB e compacte-o com compress, gzip e bzip2. Compare os tamanhos dos arquivos resultantes.
  2. Usando o programa tar, compacte todo o diretório home do usuário aluno. Experimente criar o arquivo tar sem compactação, e depois compactado com cada um dos compactadores vistos. Você terá portanto como resultado quatro arquivos tar diferentes ...
  3. Descompacte os arquivos tar gerados na questão anterior. Para evitar sobreposição, descompacte cada um deles em um diretório separado.
  4. Resolva a prova que foi aplicada no semestre 2009.2.

26/03: Avaliação

Avaliação teórica e prática

Lógica de Programação

31/03: Introdução

Apostila auxiliar, escrita pelo prof. Paulo Sérgio de Moraes.

Ver transparências.

Lógica de programação: instrução, sequência lógica, algoritmo.

Exemplificando com shell scripts:

#!/bin/bash

# Cada linha no script abaixo corresponde a uma instrução ...
# O conjunto de instruções na ordem apresentada forma uma sequência lógica ...

echo Iniciando o script ...
echo Vou procurar todos os arquivos de texto existentes neste diretório

find . -type f -name "*.doc" > .tmp
find . -type f -name "*.txt" >> .tmp
find . -type f -name "*.rtf" >> .tmp
find . -type f -name "*.odt" >> .tmp

echo Os arquivos são:

cat .tmp

rm -f .tmp

Problema da travessia

Um barqueiro precisa levar um saco de milho, uma galinha e uma raposa para o outro lado do rio. Porém o barco somente é capaz de levar uma coisa de cada vez (além do barqueiro). Qual a sequência de travessias necessário para atravessar o milho, a galinha e a raposa ?


Atividade extra

  • O jogo LightBot mostra de uma forma divertida como criar pequenos algoritmos. Até que fase desse jogo você consegue chegar ?

07/04: Algoritmos

Ver transparências.

Introdução a lógica de programação:

  • Algoritmos: sequência finita de passos que leva à execução de uma tarefa. Exemplos:
    1. Cálculo das raízes de uma equação de 2o grau (método de Baskara)
    2. Receita de pão
    3. Soma de dois números:
      Ler primeiro número
      Ler segundo número
      Somar os dois números lidos
      Mostrar o resultado
      
  • Programa: tradução de um algoritmo para uma linguagem de programação, para que possa ser executado por um computador.
    1. Soma de dois números em shell script:
      #!/bin/bash
      
      echo -n Entre com o primeiro numero:
      read x
      echo -n Entre com o segundo numero:
      read y
      z=$(($x + $y))
      
      echo A soma de $x e $y eh $z
      
      Para executar esse programa, grave-o em um arquivo chamado soma.sh e em seguida faça o seguinte:
      bash soma.sh
      
    2. Soma de dois números em Linguagem C:
      #include <stdio.h>
      
      int main() {
        int x, y, r;
      
      
        printf("Entre com o primeiro numero: ");
        scanf("%d", &x);
      
        printf("Entre com o segundo numero: ");
        scanf("%d", &y);
      
        r = x + y;
      
        printf("A soma de %d e %d eh %d\n", x, y, r);
      
        return 0;
      }
      
      Para executar esse programa, grave-o em um arquivo chamado soma.c e em seguida faça o seguinte:
      gcc -o soma soma.c
      ./soma
      
    3. Soma de dois números em Java:
      import java.util.Scanner;
      
      class Soma
      {  
              public static void main(String args[])
              {
      	   int  x, y, r;
      	   Scanner scanner = new Scanner(System.in);
      	
                 System.out.print("Entre com o primeiro numero: ");
      	   x = scanner.nextInt();
      
                 System.out.print("Entre com o segundo numero: ");
      	   y = scanner.nextInt();
      
      	   r = x + y;
      
      	   System.out.println("A soma de " + x + " e " + y + " eh " + r);
              }
      }
      
      Para executar esse programa, grave-o em um arquivo chamado Soma.java e em seguida faça o seguinte:
      javac Soma.java
      java Soma
      
    4. Soma de dois números em Python:
      #!/usr/bin/python
      
      import sys
      
      print "Entre com o primeiro numero: ",
      x = int(sys.stdin.readline())
      
      print "Entre com o segundo numero: ",
      y = int(sys.stdin.readline())
      
      r = x + y
      
      print "A soma de", x, "e", y, "eh", r
      
      sys.exit(0)
      
      Para executar esse programa, grave-o em um arquivo chamado soma.py e em seguida faça o seguinte:
      python soma.py
      

Como mostrado acima, o mesmo algoritmo foi traduzido para programas em diferentes linguagens de programação. Ao serem executados, geraram o mesmo resultado.

Exercícios: desenho de figuras geométricas

  • Usando apenas as instruções:
    limpa
    avança X
    giraDireita angulo
    giraEsquerda angulo
    
    escreva algoritmos para desenhar as seguintes figuras:
    • triângulo equilátero
    • triângulo isósceles
    • triângulo escaleno
    • quadrado
    • hexágono
    • octógono
    • 7 hexágonos interligados (um central e seis periféricos).
  • kturtle é um software educacional para ajudar no ensino de matemática, geometria e introdução à programação. Ele possibilita fazer desenhos facilmente, seguindo um programa com instruções de desenho. Usando as instruções:
    reset
    forward X
    turnright angulo
    turnleft angulo
    
    ... escreva programas para os algoritmos criados no ítem anterior.

Portugol

As aulas de Lógica de Programação usarão um software de auxílio ao ensino de algoritmos chamado Portugol, desenvolvido na Escola Superior de Engenharia do Instituto Politécnico de Tomar, em Portugal.

Guia rápido de instalação e utilização do Portugol

Abaixo segue uma breve ajuda de como obtê-lo, instalá-lo e usá-lo. Esse guia assume que você esteja usando o Ubuntu Linux 9.04 ou superior.

  1. Faça o download do Portugol.
  2. Descompacte-o com o seguinte comando:
    tar xzf portugol23.tar.gz
    
  3. Repare que existe agora um subdiretório portugol no diretório onde você o descompactou. Execute o Portugol com o seguinte comando:
    java -jar portugol/Portugol.jar
    
    Obs: você precisará ter Java instalado. Caso não o tenha, execute o comando:
    sudo apt-get install openjdk-6-jre
    
  4. Copie esse arquivo para poder ver fluxogramas coloridos, e grave-o no memso diretório onde está o Portugol.
  5. Veja a ajuda do Portugol, e use-a sempre que tiver dúvidas !


A tela inicial do Portugol segue abaixo, junto com um programa demonstrativo.

Editor-Portugol.png

Exemplos de programas iniciais em Portugol:

  1. Lendo um número e mostrando-o na tela em seguida:
    Inicio
      inteiro x
    
      Escrever "Digite um numero: ",
      Ler X
      Escrever "Numero digitado: ", x
    Fim
    
  2. Lendo dois números, somando-os e mostrando o resultado na tela:
    Inicio
      inteiro x, y
    
      Escrever "Digite um numero: ",
      Ler x
      Escrever "Digite outro numero: ",
      Ler y
      Escrever "Soma = ", x+y
    Fim
    
    O programa abaixo é equivalente:
    Inicio
      inteiro x, y, z
    
      Escrever "Digite um numero: ",
      Ler x
      Escrever "Digite outro numero: ",
      Ler y
      z <- x + y
      Escrever "Soma = ", z
    Fim
    

Atividades

  1. Média de três números: escreva um programa para calcular a média de três números.
    Inicio
      Inteiro n1, n2, n3, r
    
      Escrever "Primeiro numero: "
      ler n1
      Escrever "Segundo numero: "
      ler n2
      Escrever "Terceiro numero: "
      ler n3
    
      r <- (n1 + n2 + n3) /3
    
      Escrever "Media=", r
    Fim
    
  2. Sequência de Fibonacci: em matemática corresponde aos números:
    1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
    
    ... que pode ser descrita pela relação de recorrência



    ... com valores iniciais e .

    Numerosas formas na natureza apresentam essa sequência, como neste girassol (cujas flores se dispõem em uma espiral):

    Sunflower.jpg Espiral fibonacci.png FibonacciBlocks.png

    Usando o Portugol escreva um programa que mostre os 10 primeiros números dessa sequência.
  3. Distância até o horizonte: escreva um programa que calcule a distância dos seus olhos até o horizonte. Assuma que a Terra é perfeitamente esférica, e que seu raio tem 6.378 km. Considere que você esteja no nível do mar (seus pés tocando a água do mar ;-), e que o horizonte esteja num mar perfeitamente liso. Dica: faça um diagrama desse problema para visualizar sua geometria, e use trigonometria para resolvê-lo.

09/04: Algoritmos

  • Diagrama de blocos (fluxograma)
  • Variáveis e constantes

Fluxogramas

Diagramas de bloco para auxiliar a descrição de algoritmos. Ajudam na compreensão do algoritmo, por poder visualizar o fluxo de execução.


Fluxograma-soma.png Fluxograma para o algoritmo da média de trẽs números.


Blocos de uso mais comum

Bloco Descrição Exemplo
Inicio.png Inicio do fluxograma
Processamento.png Processamento
Entrada.png Entrada de dados (ler do teclado)
Saida.png Saída de dados (mostrar na tela)
Decisao.png Decisão (testar uma condição e bifurcar) Ex-decisao.png
Conector.png Conector (juntar dos ou mais ramos do fluxograma) Ex-conector.png
Fim.png Fim

Obs: Arquivo de configuração das cores do fluxograma do Portugol.

Variáveis e constantes

  • Variável: capaz de guardar um dado a ser usado no algoritmo. Pode ser entendida como uma caixa, onde se coloca um dado e se pode consultá-lo quantas vezes for necessário. O dado pode ser modificado (substituído por outro). Exemplo em Portugol:
    Inicio
      inteiro anos, dias
    
      Escrever "Quantos anos se passaram ? "
      Ler anos
      dias <- anos * 365
      Escrever "... então se passaram ", dias, " dias"
    Fim
    
    Nesse exemplo há duas variáveis: dias e anos
  • Constante: semelhante à variável, porém o dado armazenado não pode ser modificado. Exemplo em Portugol:
    Inicio
      constante inteiro diasPorAno <- 365
      inteiro anos, dias
    
      Escrever "Quantos anos se passaram ? "
      Ler anos
      dias <- anos * diasPorAno
      Escrever "... então se passaram ", dias, " dias"
    Fim
    
    Nesse exemplo há uma constante: diasPorAno


Variáveis e constantes devem ser declaradas antes de serem usadas (algumas poucas linguagens, como Python e Perl, não exigem isto). A declaração consiste do tipo e identificador da variável. O tipo corresponde ao tipo de valor que pode ser guardado, e o identificador é o nome da variável. No exemplo abaixo:

  constante inteiro diasPorAno <- 365
  inteiro anos, dias
Fim

Há duas variáveis do tipo inteiro, e seus identificadores são dias e anos. O tipo inteiro indica que essas variáveis podem guardar somente números inteiros.

Tipos de variáveis e constantes no Portugol:

Tipo Descrição Exemplo
Inteiro Número inteiro entre -2 147 483 648 e 2 147 483 647 Inteiro x <- 10
Real Número real entre -1.7 E 308 e 1.7 E 308 Real y <- 10.789
Lógico Valor booleano, com valores "Verdadeiro" e "Falso" Logico ok <- Falso
Caracter Um caractere da tabela ASCII Caracter letra <- "A"
Texto Uma sequência de caracteres (ou string) Texto palavra <- "um teste"

A declaração de constantes é semelhante à de variáveis, bastanto prefixá-las com a palavra-chave constante.

Atividade

Para os exercícios abaixo, desenhe o fluxograma e escreva o algoritmo no Portugol.

  1. Faça um algoritmo que calcule a média de quatro números, porém mostrando as casas decimais (caso existam).
  2. Escreva um algoritmo que calcule a raiz de uma equação de 1o grau.
  3. Escreva um algoritmo que leia o nome, sobrenome e idade de uma pessoa, e escreva na tela:
    sobrenome, nome
    idade anos
    
    Solução:
    inicio
      texto nome, sobrenome
      inteiro idade
      
      escrever "Nome: "
      ler nome     
      
      escrever "Sobrenome: "
      ler sobrenome
      
      escrever "Idade: "
      ler idade
      
      escrever sobrenome, ", ", nome, "\n", idade, " anos"
      
    fim
    

14/04: Expressões aritméticas

Fazer as atividades extraclasse desta semana.

Expressão aritmética: um conjunto de operações sobre variáveis, constantes e funções numéricas, e que gera um determinado resultado numérico.

Exemplos de expressões aritméticas:

# Uma expressão que calcula quantos segundos existem em um horário do tipo horas, minutos e segundos
3600*horas + 60*minutos + segundos

# Uma expressão que calcula a velocidade instantânea, segundo um MRV
vel_inicial + aceleracao*tempo;

# Uma expressão que calcula o módulo de um vetor bidimensional, que possui coordenadas x e y
raiz(x^2 + y^2)

Os resultados de expressões podem ser mostrados na tela, ou armazenados em variáveis:

# Uma expressão que calcula quantos segundos existem em um horário do tipo horas, minutos e segundos
segundos <- 3600*horas + 60*minutos + segundos

# Uma expressão que calcula a velocidade instantânea, segundo um MRV
escrever 'Velocidade no instante ', tempo, ' = ', vel_inicial + aceleracao*tempo;

# Uma expressão que calcula o módulo de um vetor bidimensional, que possui coordenadas x e y
modulo <- raiz(x^2 + y^2)

Repare que uma expressão fica sempre do lado direito, quando atribuída a uma variável. A expressão é primeiro calculada, e em seguida seu resultado é armazenado na variável:

segundos <- 3600*horas + 60*minutos + segundos

Operadores aritméticos

Expressões aritméticas sao compostas por números e operadores aritméticos:

Obs: para os exemplos abaixo são usadas estas variáveis:

Real x, area, lado
inteiro dias, horas
Operador Descrição Exemplo
+ Adição x <- x + 1
- Subtração x <- x - 1
* Multiplicação x <- x*x*x
/ Divisão dias <- horas / 24
% Módulo (resto de divisão) horas <- horas % 24
^ Potenciação area <- lado^2

Precedência dos operadores (nesta ordem): ^, *, /, %, + e -

A precedência pode ser modificada com o uso de parênteses. Ex:

escrever 1 + 2 * 3
escrever (1 + 2)*3

No Portugol, existem também algumas funções úteis, como a função raiz:

r <- raiz(x^2 + y^2)

O resultado de expressões aritméticas depende dos tipos numéricos das variáveis e constantes:

inicio
  real x
  inteiro y
  inteiro resultadoInteiro
  real resultadoReal
  
  x <- 9
  y <- 9
  
  escrever "O resultado de uma expressão aritmética depende dos tipos das variáveis e constantes\n"
  escrever "usadas na expressão. Se forem todas inteiras, então o resultado será inteiro.\n"
  escrever "Veja este exemplo: \n"
  escrever "Variável inteira y=", y
  escrever "\nExpressão: y/2=", y/2
  
  escrever "\n\nNeste segundo exemplo, repete-se a mesma expressão, porém usando-se uma\n"
  escrever "variável real:\n"
  escrever "Variável real x=", x
  escrever "\nExpressão: x/2=", x/2
  
  x <- 4
  y <- 5
  escrever "\n\nSe as variáveis de diferentes tipos forem combinadas, o resultado da\n"
  escrever "expressão será real:\n"
  escrever "Variável real x=", x, " e inteira y=", y
  escrever "\nExpressão: (x+y)/2=", (x+y)/2

  escrever "\n\nNo entanto, se uma expressão tiver um resultado real, mas este for\n"
  escrever "atribuído a uma variável inteira, então apenas a parte inteira será guardada:\n"
  escrever "Variável real x=", x, " e inteira y=", y
  y <- (x+y)/2
  escrever "\nExpressão: y <- (x+y)/2 ... após executada, y=", y
  
fim

Atividades

  1. Escreva um algoritmo que calcule a raiz de uma equação de 1o grau.
  2. Escreva um algoritmo que calcule as raízes de uma equação de 2o grau. Assuma que existam duas raízes reais.
  3. Um equipamento conta o tempo desde que foi ligado. No entanto, essa contagem é feita em segundos. Faça um algoritmo que converta o valor desse contador para horas, minutos e segundos.
  4. Faça um algoritmo que converta um número decimal para sua representação binária. Assuma que o número decimal tenha até dois dígitos.

16/04: Estruturas de decisão

Foram publicados os conceitos da 1a avaliação.

Estruturas de decisão possibilitam que se executem diferentes sequências de instruções de um programa, dependendo de uma condição a ser avaliada. Por exemplo, um jogo poderia armazenar a maior pontuação já obtida, e verificar se foi ultrapassada ao final de cada partida:

  Se pontuacao > recorde então 
    recorde <- pontuação
  FimSe

O exemplo acima mostra a estrutura de decisão Se condição entao comandos Fimse. Veja o próximo exemplo:

  Se conceito > 70 entao
    escrever 'Voce esta aprovado'
  senao
    escrever 'Desta vez não deu ... tente de novo !'
  Fimse

O uso de Se condição entao comandos Senao comandos Fimse possibilita que se execute uma sequência de comandos se a condição for verdadeira, e outra sequência se for falsa.

Para fazer um bom uso de estruturas de decisão deve-se primeiro conseguir identificar as condições a serem avaliadas. Condições são escritas com expressões lógicas, e estas são compostas de operadores lógicos e relacionais aplicados a variáveis e constantes.

Condições

Obs: para os exemplos abaixo são usadas estas variáveis:

Logico correto, multa, aprovado, barato, bombear_agua
Logico descartar, baixo, reprovado, erro, enviado, recebido
inteiro erros, pontuacao, preco, endereco, velocidade
Real faltas, nivel_agua, altura

Operadores relacionais

Operador Descrição Exemplo
= Igualdade correto <- (erros = 0)
> Maior multa <- (velocidade > 80)
>= Maior ou igual aprovado <- (pontuacao >= 70)
< Menor barato <- (preco < 100)
<= Menor ou igual bombear_agua <- (nivel_agua <= 0.7)
=/= Diferente descartar <- (endereco =/= 12345)


Operadores lógicos

Operador Descrição Exemplo
NAO Negação baixo <- NOT (altura > 1.8)
E Conjunção aprovado <- NOT (conceito = "D") E (faltas <= 0.25)
OU Disjunção reprovado <- (conceito = "D") OU (faltas > 0.25)
XOU Disjunção exclusiva erro <- enviado XOU recebido


Precedência dos operadores (nesta ordem): NAO, E, OU e XOU

Lembre que a precedência pode ser modificada com o uso de parênteses.

Atividades

  1. Faça um programa que leia um número e então informe se ele é par ou ímpar.
  2. Faça um algoritmo que leia três números do teclado, e mostre o maior e menor números.
  3. Em uma rede de computadores, o firewall restringe o acesso a Internet, dependendo do horário e do tipo de usuário que faz o acesso. Os tipos de usuário abaixo têm as seguintes restrições:
    • Funcionario: apenas entre 0:00 e 7:30, entre 18:30 e 0:00, e entre 12:00 e 13:30
    • Financeiro: qualquer horario
    • Diretoria: qualquer horário
      Escreva um algoritmo que informe se um acesso foi permitido, em função do horário e do tipo de usuário.
  4. Modifique o algoritmo acima para adicionar a seguinte restrição:
    • Funcionario: nao pode acessar sites de jornal (ex: www.rbs.com.br)
    • Financeiro: nao pode acessar sites de jornal durante o expediente
    • Diretoria: sem restrições a sites
  5. Faça um algoritmo para fazer a divisão de dois números reais. Antes de dividi-los deve ser feito um teste de validade. Caso não seja possível dividi-los, deve ser mostrada uma mensagem de erro. Se for possível, deve-se mostrar o resultado da divisão.
  6. Faça um jogo de par ou ímpar, em que o jogador aposta contra o computador. O jogador deve digitar um número entre 0 e 5 e optar entre par ou ímpar. O computador deve sortear um número também entre 0 e 5. Se a paridade da soma dos números do jogador e do computador for a mesma que o jogador optou, então ele ganha a partida, senão o computador vence.

23/04: estruturas de decisão

Ver atividades extraclasse desta semana.

Há situações em que se precisa fazer um conjunto de comparações, como mostrado abaixo:

// Lê a data no formato numérico dia, mes, ano, e mostra a data no formato
// dia, nome do mês, ano.
Inicio
  inteiro dia, mes, ano
  texto nome_mes

  escrever "Dia: "
  ler dia
  escrever "Mes: "
  ler mes
  escrever "Ano: "
  ler ano

  se mes = 1 entao
    nome_mes <- "Janeiro"
  senao
    se mes = 2 entao
      nome_mes <- "Fevereiro"
    senao
      se mes = 3 entao
        nome_mes <- "Março"
      senao
        se mes = 4 entao
          nome_mes <- "Abril"
        senao
          se mes = 5 entao
            nome_mes <- "Maio"
          senao
            se mes = 6 entao
              nome_mes <- "Junho"
            senao
              se mes = 7 entao
                nome_mes <- "Julho"
              senao
                se mes = 8 entao
                  nome_mes <- "Agosto"
               senao
                  se mes = 9 entao
                    nome_mes <- "Setembro"
                  senao
                    se mes = 10 entao
                      nome_mes <- "Outubro"
                    senao
                      se mes = 11 entao
                        nome_mes <- "Novembro"
                      senao
                        nome_mes <- "Dezembro"
                      fimSe
                    fimSe
                  fimSe
                fimSe
              fimSe
            fimSe
          fimSe
        fimSe
      fimSe
    fimSe
  fimSe

  escrever dia, " de ", nome_mes, " de ", ano
fim

Além de ser trabalhoso esse encadeamento de Se ... entao ... senao, o algoritmo resultante fica pouco legível. Quer dizer, ele fica feio e difícil de entender.

Existe uma estrutura de decisão criada justamente para casos como esse, e que resulta em um algoritmo mais limpo e compreensível:

// Lê a data no formato numérico dia, mes, ano, e mostra a data no formato
// dia, nome do mês, ano.
Inicio
  inteiro dia, mes, ano
  texto nome_mes

  escrever "Dia: "
  ler dia
  escrever "Mes: "
  ler mes
  escrever "Ano: "
  ler ano

  Escolhe mes
    caso 1: 
      nome_mes <- "Janeiro"
    caso 2: 
      nome_mes <- "Fevereiro"
    caso 3: 
      nome_mes <- "Março"
    caso 4: 
      nome_mes <- "Abril"
    caso 5: 
      nome_mes <- "Maio"
    caso 6: 
      nome_mes <- "Junho"
    caso 7: 
      nome_mes <- "Julho"
    caso 8: 
      nome_mes <- "Agosto"
    caso 9: 
      nome_mes <- "Setembro"
    caso 10: 
      nome_mes <- "Outubro"
    caso 11: 
      nome_mes <- "Novembro"
    Defeito: 
      nome_mes <- "Dezembro"
  fimEscolhe

  escrever dia, " de ", nome_mes, " de ", ano
fim

A estrutura de decisão escolhe ... caso tem uma certa flexibilidade. No exemplo abaixo, mostra-se a possibilidade de testar mais de um valor no mesmo caso:

inicio     
  caracter sexo     

  escrever "Qual o seu sexo (f/m):"     
  ler sexo     

  escrever "Olá "     

  escolhe sexo         
    caso "m", "M" :             
      escrever "senhor"         
    caso "f","F" :             
      escrever "senhorita"         
    defeito :             
      escrever "Sexo indefinido"     
  fimescolhe     

  escrever ", benvindo ao portugol" 
fim

Atividades

  1. Faça um algoritmo que converta um número de 1 a 7 para o respectivo dia da semana (ex: 1 = domingo, 2 = 2a feira, e assim por diante).
  2. Faça uma calculadora com as quatro operações aritméticas. Sua calculadora deve ler (nesta ordem) o primeiro número, a operação aritmética (que deve ser informada usando o símbolo da respectiva operação: +, -, * ou /), e depois o segundo número. Ao final, seu algoritmo deve mostrar o resultado, ou uma mensagem de erro se a operação não for possível de realizar (ex: divisão por zero).
  3. A previsão do tempo na costa brasileira pode ser feita de forma aproximada usando-se um barômetro e um termômetro. Uma estimativa com boa chance de acerto se baseia na tabela abaixo:
    Previsao-barometro.png

    Faça um algoritmo que forneça uma estimativa da previsão do tempo, usando essa tabela.
  4. Faça um algoritmo que mostre qual o último dia de um determinado mês informado pelo teclado. Caso seja informado o mês 2 (fevereiro), seu algoritmo deve identificar se é ano bissexto (assim o mês tem 29 dias), ou não (mês tem 28 dias). Obs: anos bissextos são dados pelas regras (segundo o calendário Gregoriano):
    1. De 4 em 4 anos é ano bissexto.
    2. De 100 em 100 anos não é ano bissexto.
    3. De 400 em 400 anos é ano bissexto.
    4. Prevalecem as últimas regras sobre as primeiras.

28/04: Estruturas de repetição

Ver atividades extraclasse desta semana.

Alguns algoritmos vistos anteriormente possuem sequências repetitivas de instruções. Por exemplo, o algoritmo da média de quatro avaliações:

Inicio
  real m1, m2, m3, m4
  real media

  escrever 'Avaliação 1:'
  Ler m1
  escrever 'Avaliação 2:'
  Ler m2
  escrever 'Avaliação 3:'
  Ler m3
  escrever 'Avaliação 4:'
  Ler m4

  media <- (m1 + m2 + m3 + m4) / 4

  escrever 'Média: ', media
Fim

O algoritmo acima repete quatro vezes a sequência que lê uma nota do teclado. Porém há uma forma de expressar a repetição de sequências de instruções, usando-se o que se chama de estrutura de repetição. A estrutura de repetição enquanto condição faz repete todas as instruções enquanto a condição for verdadeira. A condição é escrita como uma expressão lógica, da mesma forma que na estrutura de decisão se condição então ... senão. Veja como fica o algoritmo acima ao ser reescrito para usar essa estrutura de repetição:

Inicio
  constante inteiro NUMEROS <- 4
  real m
  real media
  inteiro contador <- 0

  enquanto contador < NUMEROS faz  
    escrever 'Avaliação ', contador, ':'
    ler m
    media <- media + m
    contador <- contador + 1
  fimEnquanto

  escrever 'Média: ', media/NUMEROS
Fim

Esse algoritmo funciona somente para médias de quatro números. Porém calcular a média de qualquer quantidade de números usa a mesma lógica: ler os números, somá-los e dividir o total pela quantidade de números lidos. Por exemplo, para fazer com que ele calcule a média de 7 números é necessário escrevê-lo assim:

Inicio
  constante inteiro NUMEROS <- 7
  real m
  real media
  inteiro contador <- 0

  enquanto contador < NUMEROS faz  
    escrever 'Avaliação ', contador, ':'
    ler m
    media <- media + m
    contador <- contador + 1
  fimEnquanto

  escrever 'Média: ', media/NUMEROS
Fim

Note que o algoritmo praticamente não foi modificado, pois somente se alterou o valor da constante NUMEROS.

A estrutura de repetição junto com a sequência de instruções a ser repetida é comumente chamada de 'laço. Assim, no algoritmo acima o laço aparece em:

  enquanto contador < NUMEROS faz  
    escrever 'Avaliação ', contador, ':'
    ler m
    media <- media + m
    contador <- contador + 1
  fimEnquanto

Um outro exemplo ainda mais simples é mostrar na tela uma contagem numérica:

inicio
    inteiro contador
    contador <- 0

    enquanto contador < 10 faz
        escrever contador , " "
        contador <- contador + 1
    fimenquanto
fim

Ao executar esse algoritmo, tem-se como resultado:

0 1 2 3 4 5 6 7 8 9

Repare no uso de uma variável auxiliar contador para controlar a quantidade de repetições. Essa é uma técnica comum para controlar a estrutura de repetição, e já foi usada no exemplo da média. Ela pode também ser combinada com outras condições, como mostrado abaixo:

inicio
    inteiro contador <- 1
    caracter opcao <- "s"
        
    enquanto ((opcao = "s") ou (opcao = "S")) e contador < 11 faz
        escrever contador, "\n"
        contador <- contador + 1
        
        escrever "\nContinuar (S/N) ? "
        ler opcao
    fimenquanto
    
    escrever "Terminou com contador = " , contador
fim

Nesse exemplo se usa um laço para mostrar uma contagem de 1 a 10. Porém há a possibilidade de encerrar o algoritmo. Observe a condição para continuidade do laço: ela é verdadeira somente se contador < 11 e se a variável opcao for igual a "s" ou "S".

Finalmente, apesar de ser comum o uso de contadores para controle do laço, pode-se usar qualquer condição para essa finalidade. Então podem existir laços que não usam contadores para controlar a quantidade de repetições, como no próximo exemplo:

inicio
    constante texto segredo <- "secreto"
    texto senha
    
    ler senha
    enquanto senha =/= segredo faz
        escrever "Voce continua preso ! Digite a senha correta: "
        ler senha
    fimenquanto
    escrever "Voce foi liberado ..."
fim

Atividades

  1. Escreva um algoritmo que mostre a tabuada de um número fornecido pelo teclado. Esse número deve estar entre 1 e 10. Solução mostrada em aula:
    Inicio
      inteiro numero, contador
    
      escrever "Número: "
      ler numero
      
      se numero > 0 e numero < 11 entao
        contador <- 1
        enquanto contador < 11 faz
          escrever numero, " x ", contador, " = ", numero*contador, "\n"
          contador <- contador + 1
        fimenquanto
      senao
        escrever "Número ", numero, " inválido !"
      fimse
    fim
    
  2. Aproveite o algoritmo anterior para mostrar a tabuada de todos os números entre 1 e 10. Solução vista em aula:
    Inicio
      inteiro numero, contador
    
      numero <- 1
      enquanto numero < 11 faz
        contador <- 1
        enquanto contador < 11 faz
          escrever numero, " x ", contador, " = ", numero*contador, "\n"
          contador <- contador + 1
        fimenquanto
      fimenquanto
    fim
    
  3. Modifique o exemplo da média para que a quantidade de números a serem lidos seja previamente informada pelo teclado.
  4. Modifique novamente o exemplo da média para que ela funcione para um quantidade de números desconhecida de antemão. Quer dizer, o algoritmo deve ler os números para calcular a média, mas não sabe quantos números existem (e isto não pode ser informado pelo teclado).
  5. Modifique o exemplo da senha para que o usuário tenha somente três tentativas permitidas para digitar a senha correta. caso ao final as três senhas estejam erradas, o algoritmo deve informar que a conta foi bloqueada.
    Solução vista em aula:
    inicio
        constante texto segredo <- "secreto"
        texto senha
        inteiro tentativas <- 3
     
        ler senha
        enquanto senha =/= segredo e tentativas > 0 faz
            escrever "Voce continua preso ! Digite a senha correta: "
            ler senha
            tentativas <- tentativas - 1
        fimenquanto
        
        se senha = segredo entao
           escrever "Voce foi liberado ..."
        senao
          escrever "Conta bloqueada !"
        fimse 
    fim
    
  6. Escreva um algoritmo que leia até 10 números do teclado, e informe ao final qual o maior e o menor deles.
  7. Escreva um algoritmo que teste se um número informado pelo teclado é primo.
    Solução vista em aula (tente melhorá-la !):
    inicio
        inteiro numero , n , resto <- 1
        escrever "Forneça um número: "
        ler numero
        n <- 2
        enquanto n <= numero / 2 e resto =/= 0 faz
            resto <- numero % n
            escrever "n=" , n , ": resto=" , resto , "\n"
            n <- n + 1
        fimenquanto
        
        se resto = 0 entao
            escrever "nao primo: divisivel por " , n - 1
        senao
            escrever "primo"
        fimse
    fim
    
  8. Usando estrutura de repetição, escreva um algoritmo que converta um número de decimal para binário. O número decimal está entre 0 e 131071.

30/04: Estruturas de repetição

Continuação ...

Foram feitos os exercícios da aula de 28/04.

05/05: Estruturas de repetição

Variáveis multidimensionais

Em matemática existem matrizes e vetores, que são variáveis multidimensionais. Por exemplo, uma matriz 3 x 3 (3 linhas e 3 colunas) pode ser:

Vetores são matrizes unidimensionais, portanto possuem somente uma linha ou uma coluna:

Cada elemento em uma matriz ou vetor é identificado pela sua posição. Por exemplo, na posição 1, 2 da matriz A acima está o valor 6, e na posição 4 do vetor v está o valor 18. Assim, a matriz A do exemplo pode ser entendida da seguinte forma:

... e o vetor v do exemplo:

Nas linguagens de programação em geral existe um conceito muito parecido, chamado de variáveis multidimensionais ou simplesmente matrizes (arrays em inglẽs). Para exemplificar, no Portugol se poderiam definir a matriz A e o vetor v:

inicio
  inteiro A[2][2] <- {{1, 6}, {3, 5}}
  inteiro M[3][2]
  inteiro v[5] <- {1, 6, 2, 18, 5}

  escrever "Valor de A[0][0]: ", A[0][0], "\n"
  escrever "Valor de A[0][1]: ", A[0][1], "\n"
  escrever "Valor de A[1][0]: ", A[1][0], "\n"
  escrever "Valor de A[1][1]: ", A[1][1], "\n"

  escrever "Valor de v[0]: ", v[0], "\n"
  escrever "Valor de v[1]: ", v[1], "\n"
  escrever "Valor de v[2]: ", v[2], "\n"
  escrever "Valor de v[3]: ", v[3], "\n"
  escrever "Valor de v[4]: ", v[4], "\n"

fim

A declaração da matriz se faz como uma variável comum, porém indicando-se suas dimensões:

  inteiro A[2][2] <- {{1, 6}, {3, 5}}
  inteiro M[3][2];

Veja que a matriz M foi declarada sem valores iniciais, porém a matriz A foi inicializada na declaração.

O acesso aos elementos da matriz se faz usando-se índices, que funcionam como coordenadas dos elementos que se quer acessar. Os índices iniciam em 0:

  # índice 0,0
  escrever "Valor de A[0][0]: ", A[0][0], "\n"

O exemplo acima pode ser reescrito usando-se estruturas de repetição:

inicio
  inteiro A[2][2] <- {{1, 6}, {3, 5}}
  inteiro v[5] <- {1, 6, 2, 18, 5}
  inteiro i, j

  enquanto i < 2 faz
    j <- 0
    enquanto j < 2 faz
       escrever "Valor do elemento de A na posição ", i, ", ", j, ": ", A[i][j], "\n"
       j <- j + 1
    fimenquanto
    i <- i + 1
  fimenquanto

  i <- 0
  enquanto i < 5 faz
    escrever "valor de v na posição ", i, ": ", v[i], "\n"
    i <- i + 1
  fimenquanto

fim

Como se vê, matrizes e vetores casam perfeitamente com estruturas de repetição, e são úteis para a resolução de inúmeros problemas. Por exemplo, o problema de mostrar o nome do mês a partir do número do mês, feito anteriormente com escolhe ... caso pode ser feito assim com um vetor:

inicio
  texto nome_mes[12] <- {"Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho",
                         "Julho", "Agosto", "Setembro", "Outubro", "Novembro",
                         "Dezembro"}
  inteiro dia, mes, ano

  escrever "Dia: "
  ler dia
  escrever "Mes: "
  ler mes
  escrever "Ano: "
  ler ano

  escrever dia, " de ", nome_mes[mes - 1], " de ", ano
fim

Outro problema comum é precisar guardar um conjunto de valores, e depois ordená-los:

inicio
  inteiro v[10]
  inteiro i
  inteiro quantidade

  escrever "Quantos valores serão digitados (máximo = 10) ? "
  ler quantidade

  i <- 0
  enquanto i < quantidade faz
    escrever "valor ", i, ": "
    ler v[i]
    i <- i + 1
  fimenquanto

  // ordena os valores ...

  escrever "valores ordenados: "
  i <- 0
  enquanto i < quantidade
    escrever v[i], " "
    i <- i + 1
  fimenquanto
fim

Atividades

  1. Escreva um algoritmo que leia 5 números do teclado, e depois mostre-os em ordem inversa à que foi digitada.
  2. Escreva um algoritmo que leia dois vetores de 5 números, e depois mostre se os vetores são iguais. Solução vista em aula:
    inicio
      inteiro v1[5]
      inteiro v2[5]
      inteiro i
      logico iguais <- verdadeiro
      
      i <- 0
      enquanto i < 5 faz
        escrever "v1[", i, "]: "
        ler v1[i]
        i <- i + 1
      fimenquanto
    
      i <- 0
      enquanto i < 5 faz
        escrever "v2[", i, "]: "
        ler v2[i]
        i <- i + 1
      fimenquanto
     
      i <- 0
      enquanto i < 5 E iguais faz
        iguais <- v1[i] = v2[i]
        i <- i + 1
      fimenquanto
      
      se iguais entao
        escrever "v1 e v2 são iguais"
      senao
        escrever "v1 e v2 são diferentes"
      fimse  
    fim
    
    Algoritmo escrito pelo André:
    inicio
        inteiro v1 [ 5 ]
        inteiro v2 [ 5 ]
        inteiro i , b , a
        
        b <- 0
        i <- 0
        enquanto i < 5 faz
            escrever "Valor " , i + 1 , ": "
            ler v1 [ i ]
            i <- i + 1
        fimenquanto
        
        i <- 0
        enquanto i < 5 faz
            escrever "valor " , i + 1 , ": "
            ler v2 [ i ]
            i <- i + 1
        fimenquanto
        
        a <- 0
        enquanto a < 5 faz
            escrever v1 [ a ] , " = " , v2 [ a ] , ":"
            se v1 [ a ] = v2 [ a ] entao
                b <- b + 1
                escrever " Sim" , "\n"
            senao
                escrever " Não" , "\n"
            fimse
            a <- a + 1
        fimenquanto
               
        se b = 5 entao
            escrever b, " números são iguais, então: \n", "Os vetores são iguais."
        senao
            escrever b, " números são iguais, porém: \n", "Os vetores são diferentes."
        fimse
        
    fim
    
  3. Escreva um algoritmo que leia um palavra do teclado e depois procure-a numa lista de palavras preexistente. Essa lista deve ser implementada usando um vetor.
  4. Escreva um algoritmo que leia 5 números, e mostre-os em ordem crescente.
  5. Modifique o algoritmo anterior para mostrá-los em ordem decrescente.
  6. Em um jogo de bingo devem-se contar quantos números de uma aposta foram sorteados no bingo. Faça um algoritmo que, dados os números sorteados e uma aposta, conta quantos números apostados forma sorteados.

07/05: Estruturas de repetição

Fazer as atividades extraclasse dessa semana.

Para variavel de inicio ate fim passo incremento

Há casos em que se deseja repetir uma parte de um algoritmo certo número de vezes. Para esses casos há uma estrutura mais prática que enquanto condição faz:

inicio
  inteiro i
  inteiro v[5]

  escrever "Digite 5 números: \n"

  para i de 0 ate 4 passo 1
    escrever "Numero ", i, ": "
    ler v[i]
  proximo

  escrever "\nOs numeros em ordem inversa são:\n\n"

  para i de 4 ate 0 passo -1
    escrever "Numero ", i, ": ", v[i], "\n"
  proximo

fim

Atividades

  1. Escreva o algoritmo para comparar dois vetores, porém usando a estrutura para.
    inicio
      inteiro v1[5]
      inteiro v2[5]
      inteiro i
      logico iguais <- verdadeiro
     
      para i de 0 ate 4 passo 1
        escrever "v1[", i, "]: "
        ler v1[i]
      proximo
       
      para i de 0 ate 4 passo 1
        escrever "v2[", i, "]: "
        ler v2[i]
      proximo
     
      para i de 0 ate 4 passo 1
        iguais <- v1[i] = v2[i] E iguais
      proximo
       
      se iguais entao
        escrever "v1 e v2 são iguais"
      senao
        escrever "v1 e v2 são diferentes"
      fimse  
    fim
    
  2. Escreva um algoritmo para procurar se um vetor menor (com menos valores) está contido em um vetor maior. Caso afirmativo, mostre a partir de que posição ele aparece. Assuma vetores de números inteiros.
  3. Modifique o algoritmo acima para mostrar todas as ocorrências do vetor menor dentro do maior. Uma solução vista em aula:
    inicio
        inteiro maior [ 15 ] <- {1 , 2 , 3 , 4 , 5 , 10 , 9 , 8 , 7 , 6 , 1 , 2 , 3 , 4 , 5}
        inteiro menor [ 5 ]
        inteiro i , posicao , ok
        logico iguais <- verdadeiro
        
        para i de 0 ate 4 passo 1
            ler menor [ i ]
        proximo
        
        posicao <- 0
        enquanto posicao < 11 faz
            
            i <- 0
            iguais <- verdadeiro
            enquanto i < 5 e iguais faz
                iguais <- menor [ i ] = maior [ i + posicao ]
                i <- i + 1
            fimenquanto
            
            se iguais entao
                escrever "Aparece na posicao " , posicao
            fimse
            
            posicao <- posicao + 1
        fimenquanto
        
        escrever "\n\Fim!"
    fim
    
  4. Modifique o algoritmo do anterior para remover todas as ocorrências do vetor menor dentro do maior.
  5. Resolva o problema do bingo usando a estrutura para

12/05: 2a avaliação

Avaliação em aula, no laboratório. Resolver usando o Portugol. Compactar os arquivos com os algoritmos e enviar para o email msobral@gmail.com.

Obs: para compactar:

tar czf prova2-seu_nome.tgz *.alg

1) Faça um programa que leia a velocidade máxima permitida em uma avenida e a velocidade com que o motorista estava dirigindo nela e calcule a multa que uma pessoa vai receber, sabendo que são pagos:
a) 50 reais se o motorista estiver ultrapassar em até 10km/h a velocidade permitida (ex.: velocidade máxima: 50km/h; motorista a 60km/h ou a 56km/h);
b) 100 reais, se o motorista ultrapassar de 11 a 30 km/h a velocidade permitida.

c) 200 reais, se estiver acima de 31km/h da velocidade permitida.

inicio
  inteiro vmax, v
  inteiro multa
  
  Escrever "Velocidade máxima: "
  ler vmax
  Escrever "Velocidade do veículo: "
  ler v
  
  se v > vmax entao
    se v - vmax <= 10 entao
      multa <- 50
    senao 
      se v - vmax <= 30 entao
        multa <- 100
      senao
        multa <- 200
      fimse
    fimse
    escrever "Multa: ", multa
  senao
    escrever "Tudo certo ... sem multa"
  fimse
fim

2) Para modificar uma senha deve-se primeiro fornecer a senha atual, e então a nova senha. É necessário escrever duas vezes a nova senha para confirmá-la. Escreva um algoritmo que modifique uma senha

predefinida, seguindo essa regra de mudança de senha.

inicio
  texto senha_atual <- "segredo"
  texto senha
  texto senha1, senha2
  
  escrever "Senha atual: "
  ler senha
  se senha = senha_atual entao
    escrever "Digite a nova senha: "
    ler senha1
    escrever "Digite-a novamente para confirmar: "
    ler senha2
    se senha1 = senha2 entao
      senha_atual <- senha1
    senao
      escrever "erro: senhas não conferem ... não modificou a senha"
    fimse
  senao
    escrever "Senha incorreta !"
  fimse
fim

3) Faça um algoritmo que conte quantos números pares e ímpares

existem em um vetor de 10 números inteiros.

inicio
  inteiro vetor[10] <- {1,23,6,2,567,23,3,5,78,769}
  inteiro pares, impares
  inteiro i
  
  para i de 0 ate 9 passo 1
    se vetor[i] % 2 = 0 entao
      pares <- pares + 1
    senao
      impares <- impares + 1
    fimse
  proximo
  
  escrever "Há ", pares, " numeros pares\n"
  escrever "e ", impares, " numeros ímpares"
fim

4) Em um jogo de bingo cada cartela tem 6 números, que estão entre 1 e 20. Durante o jogo são sorteados 10 números. Escreva um algoritmo que conte quantos números de uma cartela foram sorteados. Obs: para gerar os 10 números sorteados use a função "aleatorio()" do Portugol, a qual gera um número aleatório entre 0 e 1; use-a de acordo com este exemplo:

  inteiro  demo

  // a expressão abaixo  gera um número entre 1 e 20, e o guarda  na
variável  demo
  demo <- 1 + aleatorio() * 20

Uma solução que predefine os números sorteados e da cartela:

inicio
  inteiro cartela[6] <- {1,2,3,4,5,9}
  inteiro sorteados[10] <- {2,4,5,6,8,7,1,9,15,18}
  inteiro i, j
  inteiro acertos <- 0
  logico achou
  
  // conta quantos numeros da cartela foram sorteados
  para i de 0 ate 5 passo 1
    j <- 0
    achou <- falso
    enquanto j < 10 e nao achou faz
      achou <- cartela[i] = sorteados[j]
      j <- j + 1
    fimenquanto
    se achou entao
      acertos <- acertos + 1
    fimse
  proximo
  
  escrever acertos, " números da cartela foram sorteados"
  
fim

Uma solução que gera aleatoriamente os números sorteados e da cartela:

inicio
  inteiro cartela[6]
  inteiro sorteados[10]
  inteiro i, j
  inteiro acertos <- 0
  logico achou
  
  // gera os 10 numeros sorteados
  para i de 0 ate 9 passo 1
    sorteados[i] <- 1 + aleatorio()*20
  proximo

  // gera a cartela
  para i de 0 ate 5 passo 1
    cartela[i] <- 1 + aleatorio()*20
  proximo
    
  // conta quantos numeros da cartela foram sorteados
  para i de 0 ate 5 passo 1
    j <- 0
    achou <- falso
    enquanto j < 10 e nao achou faz
      achou <- cartela[i] = sorteados[j]
      j <- j + 1
    fimenquanto
    se achou entao
      acertos <- acertos + 1
    fimse
  proximo
  
  escrever acertos, " números da cartela foram sorteados"
  
fim

Uma solução mais cuidadosa, que evita números repetidos tanto na cartela quanto entre os sorteados:

inicio
  inteiro cartela[6]
  inteiro sorteados[10]
  inteiro i, j
  inteiro acertos <- 0
  logico achou
  
  // gera a cartela
  escrever "Cartela: "
  i <- 0
  enquanto i < 6 faz
    cartela[i] <- 1 + aleatorio()*20
    j <- 0
    enquanto j < i e cartela[j] =/= cartela[i] faz
      j <- j + 1
    fimenquanto
    se i = j entao
      escrever cartela[i], " "
      i <- i + 1
    fimse
  fimenquanto

  // gera os 10 numeros sorteados
  escrever "\nSorteados: "
  i <- 0
  enquanto i < 10 faz
    sorteados[i] <- 1 + aleatorio()*20
    j <- 0
    enquanto j < i e sorteados[j] =/= sorteados[i] faz
      j <- j + 1
    fimenquanto
    se i = j entao
      escrever sorteados[i], " "
      i <- i + 1
    fimse
  fimenquanto
  
    
  // conta quantos numeros da cartela foram sorteados
  para i de 0 ate 5 passo 1
    j <- 0
    achou <- falso
    enquanto j < 10 e nao achou faz
      achou <- cartela[i] = sorteados[j]
      j <- j + 1
    fimenquanto
    se achou entao
      acertos <- acertos + 1
    fimse
  proximo
  
  escrever "\n\n", acertos, " números da cartela foram sorteados"
  
fim

Conceitos

Aluno Conceito
André A
Bárbara D
Claudir D
Gilmar D
Guilherme D
Hannah D
Juliano A
Kalvim A
Leandro D
Lisiane D
Maicky C
Nadir D
Pedro C
Thiego A

Linguagem C: Projeto final

12/05: Introdução à linguagem C

Compilando o primeiro programa

  • O clássico Hello World!
#include <stdio.h>

int main(int argc, char *argv[])
{
	printf("Alô mundo!\n");
}
  • Mostrando mensagens de na tela: puts e printf:
    #include <stdio.h>
    
    int main() {
      int n;
    
      n = 5;
      
      puts("Demonstração de puts e printf");
    
      printf("Valor de n: %d\n", n);
    
      n = n + 1;
    
      printf("Novo valor de n: %d\n", n);
    
      return 0;
    }
    
  • Lendo dados do teclado: scanf
    #include <stdio.h>
    
    int main() {
      int n;
    
      printf("Digite um número inteiro: ");
    
      scanf("%d", &n);
    
      printf("Valor digitado foi %d\n", n);
    
      return 0;
    }
    

Tipos de dados

Portugol C Exemplo
inteiro int int x;
caracter char char letra;
real float ou double float pi = 3.1416;
texto char * ou vetor de char char * mensagem = "Hello world";
char palavra[16];
logico qualquer tipo (valor 0 = Falso, qualquer outro valor = Verdadeiro) int ok = 1;
char teste = 0;

Atividades

  • Traduza para C os seguintes algoritmos Portugol:
    1. Inicio
        inteiro x, y
       
        Escrever "Digite um numero: ",
        Ler x
        Escrever "Digite outro numero: ",
        Ler y
        Escrever "Soma = ", x+y
      Fim
      
    2. Inicio
        inteiro x, y, z
       
        Escrever "Digite um numero: ",
        Ler x
        Escrever "Digite outro numero: ",
        Ler y
        z <- x + y
        Escrever "Soma = ", z
      Fim
      
    3. Inicio
        Inteiro n1, n2, n3, r
       
        Escrever "Primeiro numero: "
        ler n1
        Escrever "Segundo numero: "
        ler n2
        Escrever "Terceiro numero: "
        ler n3
       
        r <- (n1 + n2 + n3) /3
       
        Escrever "Media=", r
      Fim
      
    4. Inicio
        inteiro anos, dias
       
        Escrever "Quantos anos se passaram ? "
        Ler anos
        dias <- anos * 365
        Escrever "... então se passaram ", dias, " dias"
      Fim
      
    5. Inicio
        constante inteiro diasPorAno <- 365
        inteiro anos, dias
       
        Escrever "Quantos anos se passaram ? "
        Ler anos
        dias <- anos * diasPorAno
        Escrever "... então se passaram ", dias, " dias"
      Fim
      

19/05: Começo do projeto

Para referência: apostila online sobre linguagem C.

O jogo: Batalha Naval

  • Etapas de desenvolvimento:
  1. Desenha 1 onda
  2. Desenha 1 linha de ondas
  3. Desenha 1 matriz de tamanho fixo de ondas
  4. Desenha 1 matriz de tamanho variável de ondas (o usuário informa as dimensões)
  5. Mapeia 1 barco: latitude e longitude (vetor)
  6. Desenha o mar com 1 barco
  7. Mapeia barcos: latitude e longitude (matriz)
  8. Desenha todos os barcos
  9. Mapeia todos os barcos: latitude, longitude e se já foi atingido
    1. Mapeia manualmente (ou estaticamente, diretamente no programa)
    2. Mapeia aleatoriamente, deixando o programa colocar os barcos no tabuleiro
  10. Pede ao usuário atirar
  11. Se o barco foi atingido, desenhar uma letra correspondente ao tipo de barco
  12. Ao final (todo os barcos atingidos): informar o usuário que venceu em 'n' movimentos
  • Proposta de código que contempla:
    • Bibliotecas e definições
    • Declaração de constantes e variáveis
      • Uso de variáveis com mesmo nome e diferentes escopos
      • Vetor e matriz
    • Operadores lógicos e matemáticos
    • Expressões
      • E/S
      • Estruturas de decisão e repetição
    • Funções
      • Passagem de parâmetro por valor e por referência
    • Acesso a uma matriz através de um vetor linear (função iniciaJogo)
    • Ponteiros

O tabuleiro

Representar o tabuleiro: etapas 1 a 4.

Etapa 1: desenhar uma onda

Conteúdos abordados:

Nessa etapa se deseja mostrar o estado de uma única posição do tabuleiro. Se o estado for "água", mostra-se uma onda (símbolo ~), e se for "navio" mostra-se X.

#include <stdio.h>

int main() {
  // 0: agua
  // 1: navio
  int posicao = 1;

  if (posicao == 0) {
    printf("~");
  } else {
    printf("X");
  }
}

Usou-se uma variável inteira para representar o estado da posição do tabuleiro. O valor 0 (zero) corresponde a "água", e 1 corresponde a "navio". Para testar o valor dessa variável, e mostrar ~ ou X, precisou-se de uma estrutura de decisão do tipo se (condição) então bloco_de instruções senão outro_bloco_de_instruções. Na linguagem C isso se faz com if (condição) { bloco de instruções } else {outro bloco de instruções}.

Etapa 2: desenhar uma linha de ondas

Conteúdos abordados:

Nessa etapa deseja-se mostrar uma linha do tabuleiro. Por exemplo, para um tabuleiro de 10 colunas, uma linha deve aparecer assim (se tiver só "água'":

~ ~ ~ ~ ~ ~ ~ ~ ~ ~

O problema é parecido com o da etapa 1, mas agora deve-se mostrar o estado de cada posição de uma linha. Foi sugerido o uso de um vetor para representar os estados das posições em uma linha. Assim, imaginando-se uma linha com 10 posições, o vetor abaixo poderia ser usado para representar seus estados:

int linha[10];

Repare na semelhança entre a declaração de um vetor em C e em Portugol. A ideia é a mesma: ao declarar o vetor deve-se informar sua capacidade (quantas posições ele possui, o que corresponde a quantos valores ele é capaz de armazenar). No exemplo acima, o vetor de inteiros linha possui 10 posições, e assim é capaz de guardar 10 números inteiros.

A tarefa da etapa 2 portanto é testar cada posição do vetor linha: se for 0 deve-se mostrar ~(água), e se for 1 deve-se mostrar X (navio).

#include <stdio.h>

int main() {
  // 0: agua
  // 1: navio
  int linha[10] = {0,1,0,0,0,0,0,0,0,0};
  int y;

  y = 0;
  while (y < 10) {

    // Mostra ~ se posicao for agua, e X se for navio
    if (linha[y] == 0) {
      printf("~ ");
    } else {
      printf("X ");
    }

    y = y + 1;
  }

}

21/05: O tabuleiro: etapas 3 e 4

Conteúdos abordados:

Para fixar:

  1. Invente um programa para testar qual o maior valor possível de ser guardado em variáveis dos seguintes tipos:
    • char
    • short
    • int
    • long
    • long long
    • Algumas soluções:
      #include <stdio.h>
      
      #define TIPO char
      #define FORMATO "Maior valor: %d\n"
      
      int main() {
        TIPO c1, c2;
       
        c1 = 1;
        while (c1 > 0) {
          c2 = c1;
          c1 = c1 + 1;
        }
      
        printf(FORMATO, c2);
       
      }
      
      Esse programa incrementa uma variável numérica até que ela atinja seu maior valor. O programa sabe quando ela atinge o maior valor quando ao incrementar a variável ela passa a ter valor negativo (aliás, por que isso acontece ? Use seus conhecimentos sobre sistema de numeração binário vistos em Eletrônica Digital ...). Porém ele tem o defeito de trabalhar muito para descobrir esse maior valor possível.

      Sabendo que as variáveis numéricas inteiras têm representação binária direta (seus valores são números binários equivalentes aos valores decimais que costumamos usar), é possível explorar o fato que cada bit acrescentado possibilita dobrar o valor máximo representado. Esse outro programa usa justamente essa propriedade dos números binários:
      #include <stdio.h>
      
      #define TIPO long long
      #define FORMATO "Maior valor: %lld\n"
      
      int main() {
        TIPO c1, c2;
        TIPO n = 1;
       
        c1 = 1;
        while (c1 > 0) {
          printf("c1=%lld\n", c1);
          c2 = c1;
          n*=2;
          c1 = c1 + n;
        }
      
        printf(FORMATO, c2);
       
      }
      
  2. Porque existem tantos tipos diferentes para as variáveis inteiras ?
  3. Resolva a questão 1 da avaliação sobre Lógica de programação, mas usando linguagem C.

26/05: O tabuleiro: etapas 3 e 4

Conteúdos abordados:

Desenhando o tabuleiro completo

Dando continuidade à visualização do tabuleiro, agora deve-se desenhá-lo por completo na tela. Quer dizer, mostrar um tabuleiro com 10 linhas e 10 colunas, seguindo a abordagem das etapas 1 e 2.

  • Para mostrar uma única casa do tabuleiro (etapa 1) usou-se uma variável inteira, cujo conteúdo representa o estado daquela casa (se água ou navio). Para mostrar uma linha usou-se um vetor com capacidade 10, com cada posição do vetor representando o estado da casa correspondente. Como se deve então fazer para mostrar todo o tabuleiro ?
    Possível solução: usando uma matriz bidimensional para representar todas suas casas:
    #include <stdio.h>
    
    int main() {
      // 0: agua
      // 1: navio
      int tabuleiro[10][10] = {{0,1,1,0,1,0,0,0,0,0}, {0,0,1,0,0,0,0,0,0,0},
                               {0,0,0,0,1,0,0,0,0,1}, {0,1,1,0,1,0,0,0,0,0},
                               {0,0,0,0,1,0,0,0,0,0}, {0,1,1,0,1,0,0,0,0,0},
                               {0,1,0,0,0,0,0,0,0,0}, {0,1,1,0,1,0,0,0,0,0},
                               {0,0,0,0,0,0,0,0,0,0}, {0,1,1,0,1,0,0,0,0,0}};
      int linha, coluna;
    
      linha = 0;
      while (linha < 10) {
          coluna = 0;
          while (coluna < 10) {
    
            // Mostra ~ se posicao for agua, e X se for navio
            if (tabuleiro[linha][coluna] == 0) {
              printf("~ ");
            } else {
              printf("X ");
            }
    
            coluna = coluna + 1;
          }
          printf("\n");
          linha = linha + 1;
      }
    
    }
    
  • Mostrar o tabuleiro na tela parece ser em si um algoritmo. Ele precisa apenas que se informem quais os estados das casas do tabuleiro. Esse algoritmo ficaria bem se implementado em uma função.
    #include <stdio.h>
    
      // 0: agua
      // 1: navio
    
    // Obs: a matriz "tabuleiro" foi tornada uma variável global porque é difícil
    // passar uma matriz como argumento de função. Assim ela pode ser acessada
    // pela função "mostra_tabuleiro".
    
    int tabuleiro[10][10] = {{0,1,1,0,1,0,0,0,0,0}, {0,0,1,0,0,0,0,0,0,0},
                               {0,0,0,0,1,0,0,0,0,1}, {0,1,1,0,1,0,0,0,0,0},
                               {0,0,0,0,1,0,0,0,0,0}, {0,1,1,0,1,0,0,0,0,0},
                               {0,1,0,0,0,0,0,0,0,0}, {0,1,1,0,1,0,0,0,0,0},
                               {0,0,0,0,0,0,0,0,0,0}, {0,1,1,0,1,0,0,0,0,0}};
    
    int mostra_tabuleiro() {
      int linha, coluna;
    
      linha = 0;
      while (linha < 10) {
          coluna = 0;
          while (coluna < 10) {
    
            // Mostra ~ se posicao for agua, e X se for navio
            if (tabuleiro[linha][coluna] == 0) {
              printf("~ ");
            } else {
              printf("X ");
            }
    
            coluna = coluna + 1;
          }
          printf("\n");
          linha = linha + 1;
      }
    }
    
    
    int main() {
      mostra_tabuleiro();
    
    }
    

Para fixar

  1. Escreva o programa para mostrar a tabuada de um número lido do teclado.
    #include <stdlib.h>
    #include <stdio.h>
    
    /*
     * 
     */
    int main(int argc, char** argv) {
    
        int numero, c;
    
        printf("Numero: ");
        scanf("%d", &numero);
    
        c = 1;
        while (c < 11) {
            printf("%d X %d = %d\n", numero, c, numero*c);
            c++;
        }
    
        return (EXIT_SUCCESS);
    }
    
  2. Reescreva o programa anterior, mas usando uma função para mostrar a tabuada.
    #include <stdio.h>
    
    int tabuada(int num) {
        int c = 1;
        while (c < 11) {
            printf("%d X %d = %d\n", num, c, num*c);
            c++;
        }
    
    }
    int main(int argc, char** argv) {
    
        int numero, c;
    
        printf("Numero: ");
        scanf("%d", &numero);
    
        tabuada(numero);
        
        return (EXIT_SUCCESS);
    }
    
  3. Modifique o programa anterior para mostrar a tabuada de todos os números entre 1 e 10. Obs: não modifique a função tabuada !
  4. Escreva um programa para o jogo de par ou ímpar.

28/05: Os navios: etapas 5 a 7

Conteúdos abordados:

Obs: desde aula passada passamos a usar o NetBeans, um Ambiente Integrado de Desenvolvimento (IDE - Integrated Development Environment). Um IDE é um programa que auxilia o programador. Ele integra um editor de programas, um gerenciador de projetos, compilador e um depurador (debugger).

Para instalar o Netbeans:

  1. Faça o download do instalador. Salve-o em algum subdiretório.
  2. Abrindo um terminal, entre no subdiretório onde está o instalador e execute esse comando:
    bash netbeans-6.8-ml-cpp-linux.sh
    
    • Caso o instalador falhe porque não encontrou a JVM (Máquina Virtual Java), instale-a com esse comando:
      sudo apt-get install -y sun-java6-jdk
      
  3. Aceite as opções de instalação sugeridas pelo instalador.
  4. Ao final da instalação, o Netbeans 6.8 estará acessível pelo menu Aplicativos -> Programação.
  5. Sempre que for escrever um novo programa com o Netbeans, crie um novo projeto (ver menu Arquivo->Novo Projeto). Selecione um projeto do tipo "Aplicativo C/C++".

Representando os navios

Um navio ocupa uma região do tabuleiro de batalha naval. No jogo original existem estes tipos de navios (com respectivas quantidades):

Navio Formato Quantidade
Porta-aviões <graphviz>

digraph Frase { navio [shape=record,label="<0> |<1> |<2> |<3> |<4> "] } </graphviz> || 1

Encouraçado <graphviz>

digraph Frase { navio [shape=record,label="<0> |<1> |<2> "] } </graphviz> || 2

Cruzador <graphviz>

digraph Frase { navio [shape=record,label="<0> |<1> "] } </graphviz> || 3

Sumarino <graphviz>

digraph Frase { navio [shape=record,label="<0> "] } </graphviz> || 4

Hidroavião Hidroaviao.png 5

Para começar, deve-se pensar em como representar o mais simples dos navios acima: submarino. Em seguida pode-se pensar em representar o cruzador, encouraçado e porta-aviões, deixando por último o hidroavião.

Para representar um navio, deve-se pensar em:

  1. Como registrar que casas do tabuleiro eles ocupam: além de saber seus posições no tabuleiro, deve-se poder identificar a que tipo de navio pertence cada casa.
  2. Como mostrar o tabuleiro levando em conta os navios: as casas do tabuleiro que contêm navios somente podem ser reveladas após serem atingidas por um tiro.

Até o momento foi usada uma matriz bidimensional para representar o tabuleiro. O uso dessa matriz pode ser incrementado para que se possa realizar as duas tarefas acima, juntamente com seus requisitos. Porém pense se o uso de algumas outras variáveis poderia facilitar o trabalho ...

Fazendo o submarino

Para iniciar essa etapa, estenda seu programa para que se possa representar um submarino, e localizá-lo no tabuleiro. Em seguida torne-o capaz de representar todos os 5 submarinos. Para verificar se você atingiu esse objetivo, faça com que esses submarinos sejam revelados (i.e. imagine que foram todos atingidos por tiros), de forma a revelá-los quando mostrar o tabuleiro na tela.

Funções

A função mostra_tabuleiro corresponde ao algoritmo para desenhar o tabuleiro na tela. O tabuleiro em si é representado pela variável tabuleiro, que tem escopo global (visível em todas as funções do programa). Neste momento é bom ler um pouco mais sobre funções na linguagem C:

Escopo de variáveis

Por escopo de uma variável entende-se o bloco de código onde esta variável é válida. Com base nisto, temos as seguintes afirmações:

  • As variáveis valem no bloco que são definidas;
  • As variáveis definidas dentro de uma função recebem o nome de variáveis locais
  • As variáveis declaradas fora de qualquer função são chamadas de variáveis globais
  • Os parâmetros formais de uma função (também conhecidos como argumentos da função) valem também somente dentro da função;
  • Uma variável definida dentro de uma função não é acessível em outras funções, MESMO QUE ESSAS VARIÁVEIS TENHAM NOMES IDÊNTICOS.
Variáveis locais

No trecho de código a seguir tem-se um exemplo com funções e variáveis com nomes iguais.

#include <stdio.h>

void FUNC1() {
   int B;

   B = -100;
   printf("Valor de B dentro da função FUNC1: %d\n", B);
}

void FUNC2() {
   int B;

   B = -200;
   printf("Valor de B dentro da função FUNC2: %d\n", B);
}

void main() {
   int B;

   B = 10;
   printf("Valor de B: %d\n", B);
   B = 20;
   FUNC1();
   printf("Valor de B: %d\n", B);
   B = 30;
   FUNC2();
   printf("Valor de B: %d\n", B);
}

O resultado de sua execução deve ser:

Valor de B: 10
Valor de B dentro da função FUNC1: -100
Valor de B: 20
Valor de B dentro da função FUNC2: -200
Valor de B: 30
Variáveis globais

O seguinte exemplo mostra o mesmo programa, porém fazendo com que a variável B seja global:

#include <stdio.h>

// Declaração da variável global B
int B;

void FUNC1() {
   B = -100;
   printf("Valor de B dentro da função FUNC1: %d\n", B);
}

void FUNC2() {
   B = -200;
   printf("Valor de B dentro da função FUNC2: %d\n", B);
}

void main() {
   B = 10;
   printf("Valor de B: %d\n", B);
   B = 20;
   FUNC1();
   printf("Valor de B: %d\n", B);
   B = 30;
   FUNC2();
   printf("Valor de B: %d\n", B);
}

O resultado de sua execução deve ser:

Valor de B: 10
Valor de B dentro da função FUNC1: -100
Valor de B: -100
Valor de B dentro da função FUNC2: -200
Valor de B: -200

E se existir um variável local com mesmo nome que uma global ? nesse caso, a variável local vai esconder a sua homônima global:

#include <stdio.h>

// Declaração da variável global B
int B;

void FUNC1() {
   //  no escopo desta função, esta variável local vai esconder a variável global B! 
   int B; 

   B = -100;
   printf("Valor de B dentro da função FUNC1: %d\n", B);
}

void FUNC2() {
   B = -200;
   printf("Valor de B dentro da função FUNC2: %d\n", B);
}

void main() {
   B = 10;
   printf("Valor de B: %d\n", B);
   B = 20;
   FUNC1();
   printf("Valor de B: %d\n", B);
   B = 30;
   FUNC2();
   printf("Valor de B: %d\n", B);
}

O resultado de sua execução deve ser:

Valor de B: 10
Valor de B dentro da função FUNC1: -100
Valor de B: 20
Valor de B dentro da função FUNC2: -200
Valor de B: -200

Para fixar

  1. Escreva um programa para ler 10 números do teclado, e em seguida mostrar o maior e o menor número.
  2. Reescreva o programa anterior, mas criando as função "maior" e "menor", que retornam o maior e menor número de um vetor de tamanho arbitrário.
  3. Faça um programa que desenhe a seguinte figura na tela (use uma função para desenhar cada linha):
        *
       ***
      *****
     *******
    *********
     *******
      *****
       ***
        *
    
  4. Até que ponto se poderiam usar funções para mostrar o tabuleiro ? Imagine que mostrar o tabuleiro fosse uma tarefa composta por 3 subtarefas:
    1. Mostrar o estado de uma casa do tabuleiro
    2. Mostrar toda uma linha: para cada casa de uma linha, mostrar o seu estado (usa subtarefa anterior).
    3. Mostrar o tabuleiro completo: mostrar cada linha (usa subtarefa anterior).

      Note que essas subtarefas correspondem à sequência do projeto até o momento. Um bom exercício seria modelar a tarefa de mostrar o tabuleiro usando uma função para cada subtarefa escrita acima.

02/06: Etapas 5 a 7

  • Continuando a representar os navios ... por enquanto somente os submarinos
    • Ainda há o problema de esconder as casas do tabuleiro ainda não acertadas por tiros: a existência de um navio ou água em uma casa somente pode ser revelada após ser atingida por um tiro.
  • A primeira versão do jogo: atirando no tabuleiro até descobrir todos os submarinos
    • Como ler do teclado as coordenadas de um tiro ?
    • Como contabilizar se acertou em mais um submarino, ou se foi água ?
    • Como identificar que o jogador acertou todos os submarinos, e assim terminar o jogo ?
    • Como contabilizar quantos tiros foram dados até descobrir todos os submarinos ?
  • Tópico sobre linguagem C: continuando funções
    • ... mais especificamente: passagem de parâmetros por valor e por referência

O laço principal do jogo ...

O jogo funciona com um laço principal, que lê as coordenadas do tiro e atualiza o tabuleiro apropriadamente:

Batalha-naval1.png

Note que nesse laço devem-se contabilizar tanto quantos tiros já foram dados, quanto os navios que foram acertados. Esse último valor é necessário para decidir se o jogo já acabou.

09/06: Etapas 5 a 9 e jogo em rede

Além das etapas 5 a 9, uma grande novidade foi adicionada ao projeto: a possibilidade de jogar em rede.

Jogo em rede

OBS: SOMENTE PARA QUEM JÁ TIVER CONSEGUIDO FAZER O JOGO

Jogar em rede significa ter dois jogadores disputando uma partida. Cada jogador terá que preparar seu tabuleiro (i.e. posicionar seus navios manualmente), e então se conectar ao outro jogador. A partida transcorre normalmente, com um jogador atirando no tabuleiro do outro alternadamente, e termina quando um jogador conseguir acertar todos os navios do outro. Jogadores usando programas diferentes devem conseguir realizar partidas, contanto que tenham observado as regras do jogo e de comunicação em rede previamente definidas.

A comunicação em rede implica algumas tarefas:

  • Localizar jogadores disponíveis
  • Anunciar-se como disponível ou ocupado
  • Solicitar uma partida com um jogador disponível
  • Aceitar um pedido de partida de algum outro jogador
  • Enviar e receber tiros
  • Encerrar partidas

Como escrever programas que se comuniquem em rede está fora do escopo da disciplina SOP (mas vocês aprenderão isso em Redes I, na 3a fase), foi preparada a biblioteca bn-net para abstrair as operações em rede. Uma biblioteca contém funções e tipos de dados previamente escritos para serem usados na escrita de outros programas.

Para compilar a biblioteca e o programa de demonstração bn-demo, faça assim:

tar xzf bn-net.tar.gz
cd bn
make
./bn-demo teste

As definições de funções, tipos de dados e valores concernentes à biblioteca ficam em um ou mais arquivos com extensão .h. A documentação sobre essa biblioteca foi gerada com doxygen:

Resumidamente, a API provê as seguintes operações (funções):

  • inicia_rede: inicia as estruturas de dados necessárias para usar a rede
  • descobre_jogadores: descobre que jogadores estão disponíveis
  • aguarda_pedido_jogo: espera que algum jogador solicite o início de uma partida, e automaticamente aceita esse pedido
  • pede_jogo: solicita o início de uma partida para um jogador
  • termina_jogo: encerra a partida
  • envia_tiro: envia um tiro, e recebe seu resultado (o que ele acertou)
  • espera_tiro: espera que o outro jogador envie o seu tiro
  • envia_codigo_alvo: envia para o outro jogador o que ele acertou em seu último tiro

Veja o exemplo bn-demo para saber como usar as funções acima.

Para usar bn-net, inclua esta linha no início do seu programa:

#include "bn/bn-net.h"

Para compilar seu programa, linke-o com a biblioteca libbn-net.a (gerada quando se executa make no diretório onde se descompactou a bn-net):

gcc -o seu_programa seu-programa.c bn/libbn-net.a

Obs: nesse exemplo assume-se que você descompactou a bn-net dentro do diretório onde está seu programa.

Se você está usando o NetBeans, adicione a biblioteca bn-net à configuração do seu projeto:

  1. Selecione o menu Arquivo -> Projeto Properties
  2. Na nova caixa de diálogo selecione Construir -> Vinculador
  3. À direita da caixa de diálogo selecione o botão à direita de Bibliotecas
  4. Na nova caixa de diálogo selecione Adicionar arquivo de biblioteca
  5. Navegue pelas pasta onde está bn-net (pasta bn, dentro do diretório onde você descompactou a biblioteca) e selecione o arquivo libbn-net.a
  6. Clique em Ok em todas essas caixas de diálogo que foram abertas

11/06: continuando desde a etapa 5

  • Foi mostrado um programa que coloca os navios e hidroaviões aleatoriamente no tabuleiro. A abordagem adotada se resume a identificar no tabuleiro o retângulo de exclusividade de um navio, e então verificar se ele está desocupado. Caso esteja livre, o navio é posto no tabuleiro. O retângulo de exclusividade é composto por todas as casas que precisam estar livres para que o navio possa ser colocado.
  • Geração de números aleatórios: foram esclarecidas dúvidas sobre a geração de números aleatórios, e o uso das funções srand e rand.

16/06: etapas 5 em diante

Tópico sobre linguagem C: lendo o manual online

...

18/06: etapas 5 em diante

Tópicos em linguagem C: estruturas de dados (criação de novos tpos de dados)

23/06: etapas 5 em diante

Tópico sobre linguagem C: caracteres e strings

Caracteres (tipo de dados char) seguem a codificação ASCII.

Strings são o equivalente ao tipo Texto do Portugol.

Para fixar

  1. Faça um programa que mostre a tabela ASCII: cada caractere com seu correspondente código numérico.
  2. Escreva um programa que leia separadamente o nome e o sobrenome de uma pessoa, e em seguida mostre-os da seguinte forma na tela: sobrenome, nome.
  3. Escreva um programa para resolver a questão 2 da 2a avaliação.
  4. Escreva um programa que leia uma palavra do teclado, e em seguida mostre-a em ordem invertida.
  5. Faça um programa que leia uma palavra do teclado, e em seguida converta-a para maiúsculas.
  6. Faça um programa para ler uma frase do teclado, e contar quantas palavras nela existem.

25/06: etapas 5 em diante

ATENÇÃO: AULA A PARTIR DE 14 h.

Sugestões de incrementos no jogo:

  • Jogo em rede
  • Armazenamento em arquivo de histórico de jogos
  • Novas regras:
    • Tiros especiais (mais explosivos)
    • Tempo limite para encontrar navios: a cada intervalo de tempo sem acertar navios (ou a cada N tiros na água) um navio já afundado pode ser reposto no tabuleiro.

Tópico sobre linguagem C: caracteres e strings (continuação)

Caracteres (tipo de dados char) seguem a codificação ASCII.

Strings são o equivalente ao tipo Texto do Portugol.

30/06: etapas 5 em diante

Tópico sobre linguagem C: caracteres e strings (continuação)

Caracteres (tipo de dados char) seguem a codificação ASCII.

Strings são o equivalente ao tipo Texto do Portugol.

02/07: etapas 5 em diante

ATENÇÃO: preparar para apresentar o projeto na próxima 4a feira (07/07)


Tópico sobre linguagem C: caracteres e strings (continuação)

Caracteres (tipo de dados char) seguem a codificação ASCII.

Strings são o equivalente ao tipo Texto do Portugol.

07/07: finalização

09/07: recuperação