Programação Computacional para Engenharia – 2017.1


MENU: [ Avisos | Informações Gerais | Regras | Bibliografia | Plano de Atividades | Dados das Aulas ]


Avisos


Informações Gerais

Nesta disciplina aprende-se a programar – mais precisamente, a resolver problemas por meio de algoritmos estruturados, escritos na linguagem de programação C.

Uma visão geral do conteúdo da disciplina está presente no plano de atividades, onde todas elas já têm data estimada (você pode comparar o conteúdo lá listado com recomendações curriculares internacionais). Caso haja choque de datas importantes com outras disciplinas suas e você deseje sugerir alterações de datas, por favor me comunique o quanto antes!

Nesta disciplina nós não seguimos nenhum livro em particular, mas na seção de bibliografia há indicações de livros que você pode utilizar para estudo individual, tanto com relação à chamada lógica de programação quanto com relação à linguagem de programação C.

  • Esteja atento(a), desde o início do semestre, às regras para solicitação de segunda chamada e para o cálculo da nota da disciplina.

    Para a obtenção de um bom desempenho na disciplina, a minha sugestão é:

    1. Acompanhe as aulas com atenção, tirando dúvidas o quanto antes.

    2. Faça os exercícios essenciais a cada aula (são 2 por aula).

    Caso você possua uma dúvida no horário da aula, o ideal é tirá-la na própria ocasião, para que os demais alunos também se beneficiem das explicações. Esteja, porém, à vontade para me contactar fora do horário de aula.


    Regras

    • Segunda chamada: consulte as regras para a solicitação de prova de segunda chamada.

    • Nota da disciplina: Consistirá na média aritmética das notas obtidas pelo aluno nas 4 avaliações parciais da disciplina:
      Média das Avaliações ≥ 7 7 > média ≥ 4 < 4
      Situação Aprovado AF Reprovado

    Bibliografia

    Atenção: consulte a biblioteca para saber sobre a disponibilidade dos livros abaixo.

    Livros sobre Lógica de Programação:

    1. Fundamentos da Programação de Computadores, 3ª edição. Ana Fernanda Gomes Ascencio, Edilene Aparecida Veneruchi de Campos. Editora Pearson. 2012. ISBN: 9788564574168.

    2. Lógica de Programação, 3ª edição. André Luiz Villar Forbellone, Henri Frederico Eberspacher. Editora Pearson. 2005. ISBN: 9788576050247.

    3. Algoritmos e Estruturas de Dados. Guimarães/Lages. Editora LTC. 1994. ISBN: 9788521603788.

    Livros sobre a Linguagem de Programação C:
    1. The C Programming Language, Second Edition. Brian W. Kernighan, Dennis M. Ritchie. Editora Prentice Hall. 1988. ISBN: 0-13-110362-8, 0-13-110370-9.

      Esse é o meu livro favorito sobre a linguagem de programação C, e é o livro do autor da linguagem (devido à idade, porém, ele descreve C89, e não C90 ou C11). Havia uma tradução pela editora Campus ("C - A linguagem de Programação - PADRÃO ANSI"), mas aparentemente ela não está mais sendo impressa. :-( Há exemplares na biblioteca!

    2. Programando em C - Volume I - Fundamentos. Ulysses de Oliveira. Editora Ciência Moderna. 2008. ISBN: 9788573936599.

    3. C: A Reference Manual, Fifth Edition. Samuel P. Harbison, Guy L. Steele. Editora Prentice Hall. 2002. ISBN-13: 978-0-13-089592-9.

    Fontes de qualidade na internet (livremente acessíveis, legalmente):
    1. The C Book, second edition. Mike Banahan, Declan Brady, Mark Doran. Editora Addison Wesley. 1991.

      Um livro didático, preciso, muito bom sobre C89, livremente disponível em html e pdf.

    2. cppreference.com - C reference.

      Não ensina programação para iniciantes, mas é uma excelente referência sobre os detalhes técnicos da linguagem C (C89, C99, C11), e particularmente sobre a biblioteca padrão – útil para perguntas como "qual é mesmo o formato esperado pela função printf?"

    3. O rascunho do padrão ISO C11, diretamente do grupo que o produziu.

      O padrão é a referência definitiva em caso de dúvida sobre a linguagem. Leitura bastante técnica, entretanto: acho que muitos programadores profissionais de C não consultam esse documento (uma pena, porém).


    Plano de Atividades

    Esta é uma disciplina de 6 créditos, e ela portanto possui 6*16/2 = 48 encontros, dos quais 44 serão aulas e 4 serão provas. A AF não está incluída nessa contagem, e ela será realizada em 2 partes, para que os alunos tenham mais tempo de fazer a prova. A tabela abaixo apresenta as datas previstas para todas as atividades da disciplina (clique no número da aula para acessar os detalhes dela):

    Aula Data Descrição
    01 14/03 Introdução à Disciplina; "Olá, mundo!" em C.
    02 16/03 E/S de inteiros; Operadores Aritméticos e Relacionais; Testes aninhados com if.
    03 17/03 Prática em Laboratório: Programas com Números e Testes; Operadores Lógicos; Atribuição.
    04 21/03 Números Naturais: Representação, E/S, Limites, Aritmética Modular.
    05 23/03 Números Inteiros: Representações Possíveis.
    06 24/03 Prática em Laboratório: Números Naturais e Inteiros; E/S; Limites; Transbordo; Conversões.
    07 28/03 Números Racionais: E/S, Constantes, Notação Científica, Conversões entre as Bases 10 e 2.
    30/03 Sem Aula: Encontros Universitários
    31/03 Sem Aula: Encontros Universitários
    08 04/04 Números Racionais: Representação segundo o Padrão IEEE 754; Valores Especiais.
    09 06/04 Problemas Importantes envolvendo Testes e Atribuição.
    10 07/04 Prática em Laboratório: Números Racionais, Contagem e Acumulação (limitadas).
    11 11/04 Funções: Definição, Chamadas, Parâmetros, Retorno.
    13/04 Sem Aula: Recesso da Semana Santa
    14/04 Sem Aula: Feriado da Paixão de Cristo
    * 18/04 AP1
    12 20/04 Repetição e Contagem usando goto, while, do, break.
    21/04 Sem Aula: Feriado de Tiradentes
    13 25/04 Repetição com Variável de Controle; for; continue; Conversões Numéricas.
    14 27/04 Vetores como Variáveis Automáticas: Declaração (de VLA's) e Acesso Indexado.
    15 28/04 Prática em Laboratório: Funções, Repetição e Vetores.
    16 02/05 E/S Orientada a Linha; Caracteres: Constantes, E/S.
    17 04/05 Sequências de Caracteres (strings): Definição e Manipulação.
    18 05/05 Prática em Laboratório: Vetores, Caracteres, Strings.
    19 09/05 Testes com switch; Revisão sobre Caracteres e Strings.
    20 11/05 Funções para Manipular Caracteres e Strings; Laços Aninhados.
    21 12/05 Prática em Laboratório: Caracteres e Strings. (Fim Conteúdo AP2)
    22 16/05 Ponteiros: Declaração; Referência e Dereferência; Conversão de Vetores para Ponteiros.
    23 18/05 Aritmética de Ponteiros; Percurso de Vetor via Ponteiros.
    24 19/05 Prática em Laboratório: Ponteiros e Strings.
    25 23/05 Operador "[]" para Ponteiros; Percurso Indexado x Percurso com Ponteiros; Ponteiros Nulos.
    26 25/05 Arquivos de Texto: Abertura, Escrita, Fechamento e Leitura Caractere-a-Caractere.
    27 26/05 Prática em Laboratório: Arquivos de Texto.
    28 30/05 Revisão sobre Arquivos de Texto
    29 01/06 Leitura de Arquivos via Linhas, Números, etc.
    30 02/06 Ponteiros para void; Alocação Dinâmica de Memória. (Fim Conteúdo AP3)
    31 06/06 Registros (struct's): Definição, Declaração, Acesso a Membros, Cópia.
    32 08/06 Programas envolvendo Registros
    33 09/06 Prática em Laboratório: Registros e Alocação Dinâmica.
    34 13/06 Matrizes como Vetores de Vetores em C
    15/06 Sem Aula: Feriado de Corpus Christi
    35 16/06 Prática em Laboratório: Matrizes.
    36 20/06 Ponteiros para Matrizes; Matrizes e Funções.
    37 22/06 Alocação Dinâmica de Matrizes. (Fim Conteúdo AP4)
    38 23/06 Prática em Laboratório: exercícios anteriores.
    39 27/06 Tira-dúvidas
    * 29/06 AP2 - Vetores e Strings (Laboratório)
    40 30/06 Tira-dúvidas no Laboratório (Opcional)
    41 04/07 Solução da AP2 e Tira-dúvidas
    42 06/07 Tira-dúvidas
    * 07/07 AP3 - Ponteiros e Arquivos (Bloco 904, Sala 1006)
    43 11/07 Solução da AP3 e Tira-dúvidas
    44 13/07 Tira-dúvidas
    * 14/07 AP4 - Registros e Matrizes
    18/07
    * 20/07 AF – Parte 1
    * 21/07 AF – Parte 2
    24/07 Resultados Finais

    Aulas: Conteúdo, Materiais e Exercícios

    • Aula 1 (2017-03-14, Terça-feira):

      EXERCÍCIOS ESSENCIAIS:

      1. Escreva, em C:

        1. Um programa que imprima o seu nome completo na tela, incluindo uma quebra de linha ao final.

        2. Um programa que imprima o seu nome completo na tela, mas cada palavra do nome em uma linha diferente.

        3. Você deve ter feito o item anterior ou por meio de múltiplas chamadas à função printf ou por meio de uma única chamada. Neste item, escreva o programa por meio da outra opção.

      2. Instale um compilador C no seu computador:

        1. No Windows, a maneira mais fácil provavelmente é instalar o Code::Blocks, ou o CodeLite, ou o Dev-C++.

        2. Você também pode experimentar um Linux, como o Ubuntu, que já vem com um compilador (além de ser um sistema operacional muito bom e gratuito).

        3. Para usos eventuais via internet (incluindo pelo celular), você pode usar um compilador online: JDoodle, CodeChef, Ideone, etc.

        4. Para usos eventuais no celular sem internet, você pode instalar um aplicativo para isso, como estes da Google Play (mas eu não conheço os fornecedores listados e por isso não faço indicações).

        Em seguida, compile e execute os programas da questão anterior.

    • Aula 2 (2017-03-16, Quinta-feira):

      • Variáveis, E/S, Expressões: um programa que lê 2 inteiros e então imprime a soma.

        • Exercício em Sala: dado que - * / % (subtração, multiplicação, divisão e resto) também existem como operadores em C, escreva um programa que também imprima na tela os resultados dessas outras operações.

      • Testes com if, Operadores Relacionais: imprimir quociente e resto apenas se divisor não nulo.

        OBSERVAÇÃO: além de == (igual), C possui os operadores relacionais != (diferente) e < <= > >=.

        • Exercício em Sala: escreva um programa para imprimir apenas quociente e resto, mas que leia o divisor novamente se nulo (se o novo divisor também for nulo, "desista").

      EXERCÍCIOS ESSENCIAIS:

      1. (Calculadora) Escreva um programa em C que primeiramente leia do usuário dois números inteiros; esses serão os "operandos". Em seguida, o programa deve ler um terceiro inteiro: a operação. Se a operação for 1, então o programa deve imprimir a soma dos operandos. Idem para 2, 3, 4, 5: subtração, multiplicação, quociente da divisão, resto da divisão. Caso a operação não seja um número de 1 a 5, o programa deve imprimir algo como "operação inválida". O programa também deve imprimir uma mensagem de erro em caso de divisão por zero.

      2. (Ordem Crescente) Escreva um programa que leia 3 inteiros do usuário e então os imprima na tela em ordem crescente.

      TEXTOS PARA REFERÊNCIA:

    • Aula 3 (2017-03-17, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO: (SUGESTÃO: crie um arquivo .c para cada questão)

      1. (Intervalo) Veja as explicações adicionais sobre operadores lógicos. Em seguida, escreva um programa que leia dois inteiros "x" e "y" e que então verifique se "x" está no intervalo [−y, y]. (Você pode escolher o que fazer caso y < 0.)

      2. (Módulo) Veja as explicações adicionais sobre atribuição e inicialização. Em seguida, escreva um programa que leia um número inteiro e então imprima na tela o módulo (valor absoluto) desse número.

      3. (Trocar 2 Valores) Escreva um programa que leia 2 inteiros do usuário, gravando-os em 2 variáveis "a" e "b". Em seguida, os valores de "a" e "b" devem ser trocados; você pode utilizar atribuições, outras variáveis, etc. Por fim, o programa deve imprimir na tela os valores de "a" e "b".

      4. (Ordenar 3 Variáveis) Escreva um programa que leia 3 inteiros do usuário, gravando-os em 3 variáveis "a", "b" e "c". Em seguida, por meio de comparações e possivelmente trocas entre essas variáveis, o programa deve ordenar esses valores de forma que passe a valer a ≤ b ≤ c. Por fim, o programa deve imprimir na tela os valores das variáveis "a", "b" e "c", nessa ordem.

      5. (Nomes de Poĺígonos) Escreva um programa que leia um inteiro "n" do usuário e então imprima na tela o nome de um polígono de "n" lados (exemplo: 3 → triângulo). O seu programa deve aceitar pelo menos os números de 3 a 6. Caso n < 3, o seu programa deve informar que não há polígono com menos de 3 lados. Caso n > 6 (ou outro número maior à sua escolha), o programa deve informar que o número está fora do escopo do programa.

      6. (Pontos formam Linha?) Escreva um programa que leia do usuário as coordenadas (inteiras) de dois pontos do plano cartesiano, e que então informe se eles determinam uma reta ou não; além disso, caso definam, informe se a reta é paralela ao eixo "x", ou ao eixo "y", ou a nenhum.

      7. (Retângulo Delimitador) Escreva em C um programa que inicialmente leia, ponto-a-ponto, as coordenadas (inteiras) de 5 pontos do plano cartesiano. Em seguida, com relação ao menor retângulo cujos lados são paralelos aos eixos "x" e "y" e que contém os 5 pontos fornecidos pelo usuário, o programa deve classificar o retângulo em ``largo'' (base maior que a altura), ``alto'' (altura maior que a base) ou ``quadrado'' (base igual à altura).

        (Importante: a solução esperada não é enorme; veja o exercício do máximo de 5.)

        Exemplo de execução:

        Digite a coordenada x do ponto 1: 5
        Digite a coordenada y do ponto 1: 4
        Digite a coordenada x do ponto 2: -1
        Digite a coordenada y do ponto 2: 5
        Digite a coordenada x do ponto 3: 6
        Digite a coordenada y do ponto 3: 0
        Digite a coordenada x do ponto 4: 5
        Digite a coordenada y do ponto 4: 6
        Digite a coordenada x do ponto 5: 2
        Digite a coordenada y do ponto 5: 1
        
        Classificação do retângulo: largo.
        

      TEXTOS PARA REFERÊNCIA:

    • Aula 4 (2017-03-21, Terça-feira):

      • Evolução dos Sistemas de Numeração: Base Unária, Sistemas "Símbolo-Valor" (ex.: números romanos) e Sistema Posicional.

      • Definição do Sistema Posicional e Conversão para a Base 10.

        • Se "n" é representado por (dk-1dk-2 ... d2d1d0)b, então n = ∑i=0..k-1 (di * bi).

        • Exercício em Sala: converta os números (326)7, (431)5, (ABA)16 para a base 10.

      • Conversão para uma Base Qualquer.

        • Ideia: se n = (...)*b + d0, e se d0 < b, então d0 é o resto da divisão de "n" por "b".

        • Exercício em Sala: faça as conversões (500)9 = (?)13 e (500)10 = (?)2.

      • Números Naturais em C: tipo unsigned int, entrada-e-saída (%u) e representação.

      EXERCÍCIOS ESSENCIAIS:

      1. Faça as conversões abaixo (e confira as respostas pela definição do sistema posicional):

        1. (100)5 para a base 3.

        2. (615)7 para a base 9.

        3. (FACA)16 para a base 2.

      2. Com base na representação do tipo unsigned int, responda:

        1. Qual é o maior número natural representável com 8 bits? (Dica: lembre que o sucessor de 1111 é o número 10000.)

        2. O padrão C11, §5.2.4.2.1, garante que uma variável do tipo unsigned int pode armazenar pelo menos qualquer número de 0 a 65535.

          Isso significa que o padrão exige que a representação de um unsigned int possua pelo menos quantos bits?

        3. O valor do maior natural armazenável num unsigned int depende da máquina utilizada, mas esse valor pode ser descoberto e manipulado por meio da constante UINT_MAX (para utilizá-la, é necessário #include <limits.h>).

          Escreva um programa que imprima o valor dessa constante na tela (%u), e descubra o número de bits utilizados por um unsigned int no seu computador.

        4. A aritmética dos números naturais em C é modular: todo valor é sempre computado "módulo 2n", sendo "n" o número de bits utilizado.

          Na prática, isso significa que, do maior valor (UINT_MAX) passa-se, por incremento, ao menor valor (zero), e analogamente no sentido contrário (decremento de zero).

          Comprove isso escrevendo um pequeno programa que decremente (--n) uma variável unsigned int valendo zero, e então imprima na tela o novo valor dela. Em seguida, adicione a ela algum valor positivo (digamos, 3) e novamente veja o que acontece.

      TEXTOS PARA REFERÊNCIA:

    • Aula 5 (2017-03-23, Quinta-feira):

      • Bits (binary digits) e Palavras de Memória.

      • O Problema da Representação de Números Inteiros.

      • Representação por Sinal-e-Magnitude.

        • Ideia: 1º bit → sinal (0 → +, para igualar com unsigned); demais bits → magnitude.

        • Exercícios em Sala:

          1. Quais as representações em 5 bits de 5 e −8?

          2. Quais os números representados por 01010 e por 10101?

      • Representação por Complemento de 1.

        • Ideia: inverter os bits para encontrar inverso aditivo (1º bit ainda indica o sinal).

        • Exercícios em Sala:

          1. Quais as representações em 5 bits de 14 e −9?

          2. Quais os números representados por 01110 e por 10101?

      • Representação por Complemento de 2 (veja as explicações adicionais).

        • Ideia: num relógio, o número de horas a adicionar a 3 horas para retornarmos a zero horas é 9 = 12 − 3.

        • Exercícios de fixação (não houve tempo para fazê-los em sala):

          1. Quais as representações em 5 bits de 8 e −13?

          2. Quais os números representados por 10100 e por 11100?

      EXERCÍCIOS ESSENCIAIS:

      1. Primeiramente, veja as explicações adicionais sobre complemento de 2.

        Em seguida, faça os exercícios de fixação acima sobre complemento de 2, os quais não houve tempo de fazer em sala de aula.

        Finalmente, escreva uma tabela de 8 linhas e 5 colunas. A primeira coluna deve conter as sequências de bits 000, 001, 010, …, 111. As outras 4 colunas devem ser preenchidas com os números correspondentes a essas sequências em cada método de representação que já estudamos: inteiros sem sinal, sinal-e-magnitude, complemento de 1 e complemento de 2.

        Exemplo: "100" significa "4" na notação de inteiro sem sinal, "−0" em sinal-e-magnitude, "−3" em complemento de 1 e "−4" em complemento de 2.

      2. Com base nos métodos de representação já estudados:

        1. Escreva os números −37, −126 e −65 utilizando 8 bits.

        2. As sequências 10100010, 11100101, 10010100 e 10000000 representam que números em cada método?

      TEXTOS PARA REFERÊNCIA:

    • Aula 6 (2017-03-24, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO: (SUGESTÃO: crie um arquivo .c para cada questão)

      1. (Transbordo int) Veja as explicações adicionais sobre limites e transbordo de inteiros.

        Em seguida, escreva um programa para testar o transbordo de inteiros na máquina que você está usando: o que acontece quando se vai além de INT_MAX? E aquém de INT_MIN?

      2. (Conversões Inteiras) Veja as explicações adicionais sobre conversões entre int e unsigned int.

        Em seguida, escreva um programa para testar essas conversões: atribua valores grandes (INT_MAX, UINT_MAX) e pequenos a variáveis com e sem sinal; imprima essas variáveis na tela; você entende os resultados?

      3. (Digitar Negativo) Escreva um programa que leia 3 números naturais do usuário, grave-os em variáveis do tipo unsigned int e em seguida simplesmente os imprima de volta na tela. Em seguida, execute o programa e experimente: o que acontece se você digitar números negativos?

      4. (Pares e Ímpares) Escreva um programa que leia 5 números naturais do usuário, e que em seguida os imprima de volta na tela, primeiro os pares e depois os ímpares:

        Digite o primeiro número: 5
        Digite o segundo número: 78
        Digite o terceiro número: 36
        Digite o quarto número: 0
        Digite o quinto número: 101
        
        Os números pares digitados foram:
        78
        36
        0
        
        Os números ímpares digitados foram:
        5
        101
        
      5. (Dias do Mês) Escreva um programa que leia do usuário o número de um mês e então imprima na tela o número de dias daquele mês: 30, 31 ou 28. O seu programa deve também imprimir uma mensagem de erro caso o número digitado não esteja no intervalo de 1 a 12.

      6. (Bissexto) Escreva um programa que leia do usuário o número de um ano, e que em seguida imprima na tela se esse ano é bissexto ou não, de acordo com estas regras:

        1. São bissextos os anos múltiplos de 400.

        2. São bissextos os múltiplos de 4, exceto se múltiplo de 100 mas não de 400. Exemplos: 1996, 2004, 2008, 2012, 2016.

        3. Não são bissextos os demais anos.

      7. (Máximo de 5) Escreva um programa que leia 5 inteiros do usuário, e que em seguida imprima na tela o maior desses números.

        IMPORTANTE: esse programa pode ser escrito fazendo-se apenas 4 usos do operador < (e sem usar outras comparações).

      8. (Máximo com 2 Variáveis) Escreva uma variação do programa anterior que use apenas 2 variáveis inteiras.

      9. (Retângulo Delimitador 2) Usando as técnicas aprendidas nos 2 exercícios anteriores, escreva um programa que resolva o problema do retângulo delimitador usando no máximo 5 variáveis.

      TEXTOS PARA LEITURA:

    • Aula 7 (2017-03-28, Terça-feira):

      EXERCÍCIOS ESSENCIAIS:

      1. Converta para a base 10:

        • (1010101,10101)2

        • (1001001,001001)2

        • (1000,1111)2

      2. Converta para a base 2:

        • 61,625

        • 320,0625

        • 171,78125

      TEXTOS PARA REFERÊNCIA:

      • Veja as hiperligações presentes na lista de assuntos da aula.

    • Aula 8 (2017-04-04, Terça-feira):

      • Representação de Inteiros por Excesso de K.

      • Formato do Padrão IEEE 754 para Racionais Normais: [ sinal | expoente | significando ]

        1. Sinal: 1º bit.

        2. Expoente: próximos "w" bits, usando Excesso de K = 2w−1 − 1.

        3. Significando: os demais bits (ficando implícito o dígito 1 antes da vírgula).

      • Valores Especiais: Zeros, Infinitos e NaNs, Números "Subnormais".

          sinal     exp.      signif.
        [   b   | 0 ... 0 | 0  ...   0 ] : +0 (se b = 0) ou −0 (se b = 1)
        [   b   | 0 ... 0 | nem tudo 0 ] : número subnormal
        [   b   | 1 ... 1 | 0  ...   0 ] : +∞ (se b = 0) ou −∞ (se b = 1)
        [   b   | 1 ... 1 | nem tudo 0 ] : NaN
        

      CORREÇÃO: em sala, foi comentado, corretamente, que os zeros e os racionais normais não-nulos são representados distintamente, conforme indicado acima. Entretanto, com relação à terminologia, foi dito que os zeros eram também números normais, o que está errado: a definição 2.1.38 do padrão IEEE 754-2008 afirma que zero não é normal nem subnormal. Isso significa, portanto, que a designação "racionais normais não-nulos" é redundante: basta escrever "racional normal", pois todo número normal é não-nulo.

      EXERCÍCIOS ESSENCIAIS:

      1. Descubra os valores representados pelas sequências de 32 bits abaixo, sabendo que são utilizados 8 bits para o expoente:

        1. 1100 0001 0001 1101 0000 0000 0000 0000

        2. 0100 0011 1100 1000 0000 0000 0000 0000

      2. Descubra as representações dos números abaixo em 32 bits, usando 8 bits para o expoente:

        1. 1492

        2. −1,78125

      3. As respostas dos 4 itens acima estão neste arquivo.

      TEXTOS PARA REFERÊNCIA:

    • Aula 9 (2017-04-06, Quinta-feira):

    • Aula 10 (2017-04-07, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO: (SUGESTÃO: crie um arquivo .c para cada questão)

      1. (Classificar double) Escreva um programa que leia um double do usuário, e que em seguida classifique na tela o valor lido: infinito, NaN, subnormal, zero ou normal.

        Para descobrir se um double x é infinito, basta usar a função isinf, de <math.h>, como em if( isinf(x) ) { ... }. Analogamente, existem as funções isnan (NaN?), isnormal (normal?) e isfinite (esta última retorna verdadeiro quando o racional é subnormal, zero ou normal, e retorna falso quando o valor é infinito ou NaN).

        Em seguida, teste o seu programa. Um double infinito pode ser digitado como inf ou infinity, e um NaN como nan (em ambos os casos, maiúsculas ou minúsculas não fazem diferença).

      2. (Calculadora Racional) Escreva um programa que leia do usuário 2 racionais e então imprima na tela, com relação a esses números, a soma, a subtração, o produto e a divisão. (Observação: o operador % se aplica apenas a inteiros.)

        Em seguida, faça testes no seu programa: o que ocorre se os operandos forem

        1. tais que o resultado é muito grande, ou muito pequeno?

        2. um racional normal e um infinito?

        3. dois infinitos?

        4. um NaN e um infinito?

        5. infinito e zero?

        6. dois zeros? Etc.

      3. (Contagem sobre 5) Escreva um programa que leia do usuário 5 racionais e que então imprima na tela a quantidade de números positivos que foram digitados.

      4. (Média de Selecionados) Escreva um programa que leia do usuário 6 racionais e que então imprima na tela a média dos números positivos que foram digitados.

      5. (Mesmo Módulo) Escreva um programa que leia do usuário 2 racionais e que então informe se eles têm o mesmo módulo (valor absoluto).

      6. (Desvio Médio de Selecionados) Escreva um programa que leia do usuário 6 racionais e que então imprima na tela o desvio médio dos números positivos que foram digitados (os outros números não devem entrar no cálculo).

        O desvio médio "d" de uma coleção de números x1, ..., xn é a média dos desvios absolutos dos números com relação à média "m" dos números:

        • m = ( x1 + ... + xn ) / n

        • d = ( |x1 − m| + ... + |xn − m| ) / n

        O módulo |x| de um double x é fácil de ser computado explicitamente, mas também pode ser obtido pela função fabs, de <math.h>.

      7. (Votos de 6 sobre 3) Escreva um programa para contar os votos de uma eleição com apenas 3 candidatos e 6 votos. O programa deverá ler do usuário 6 números (votos) de 1 a 3 (candidatos), e ao final imprimir na tela o número de votos de cada candidato. Além disso, sendo "m" o máximo de votos recebidos por um único candidato, o programa deve informar também quantos candidatos tiveram "m" votos.

      TEXTOS PARA REFERÊNCIA:

      • Veja as hiperligações presentes na lista de assuntos da aula.

    • Aula 11 (2017-04-11, Terça-feira):

      • Funções sem Parâmetros.

        • Exemplo em Sala: int ler_int (void).

      • Múltiplas chamadas a uma mesma função.

      • Funções com Parâmetros e Inicialização dos Parâmetros.

        • Exemplo em Sala: int ler_int (int i) (lê o i-ésimo inteiro, dentre vários que serão lidos).

      • Múltiplos Parâmetros e Diferenciação de Variáveis de Mesmo Nome mas de Funções Distintas:

        • Exemplo em Sala: double calc (double x, double y, int op) (calculadora).

      • O Operador +=.

      OBSERVAÇÃO: veja as explicações adicionais sobre funções sem retorno.

      EXERCÍCIOS ESSENCIAIS:

      1. (Veja primeiramente as explicações adicionais sobre funções sem retorno.)

        Como a troca dos valores de 2 variáveis é um procedimento comum, alguém poderia desejar fazê-lo por meio da função troca abaixo:

        #include <stdio.h>
        
        void troca (int x, int y)
          {
          int cp_x = x;
          x = y;
          y = cp_x;
          }
        
        int main (void)
          {
          int x,y;
          printf("x: "); scanf("%d", &x);
          printf("y: "); scanf("%d", &y);
          troca(x,y);
          printf("x: %d\n", x);
          printf("y: %d\n", y);
          }
        

        E então: a função troca efetivamente troca os valores das variáveis x e y da função main acima? Explique.

        SUGESTÃO: Simule uma execução do programa acima, da maneira ilustrada em sala, e veja como ele se comporta.

      2. Escreva uma função "max" que receba 4 racionais e retorne o maior deles. Em seguida, escreva uma função "min" análoga, que retorne o menor dentre 4 racionais. Por fim, utilizando as funções em questão, escreva um programa que leia 4 racionais do usuário e que então imprima na tela o maior e o menor dentre os números que foram digitados.

      TEXTOS PARA REFERÊNCIA:

      • Veja as hiperligações acima.

    • Aula 12 (2017-04-20, Quinta-feira):

      • Repetição com goto, while e do while:

        • Exemplo em Sala: ler ano do Calendário Gregoriano e determinar se bissexto.

      • Repetição para Contagem:

        • Exemplo em Sala: ler vários anos e contar os bissextos (parada: ano fora do Calendário Gregoriano).

          ler número
          ENQUANTO número válido
          | atualizar contagem
          | ler número // Código repetido
          
      • Repetição Incondicional via while(1) e Saída no Meio da Iteração via break.

        • Exemplo em Sala: igual ao anterior, mas evitando a repetição do código de leitura do ano.

          REPITA SEMPRE
          | ler número // Sem repetição de código
          | SE número válido
          | | sair do laço
          | atualizar contagem
          

      OBSERVAÇÃO: como vimos na aula de hoje, em C, qualquer expressão aritmética (inteira ou racional) serve como condição, e será entendida como verdadeira se e somente se for diferente de zero.

      EXERCÍCIOS ESSENCIAIS:

      1. (Repetição Contada) Usando um laço para fazer a repetição, escreva um programa que leia 10 inteiros do usuário, e que ao final informe quantos dos inteiros digitados são positivos.

      2. (Média) Escreva um programa para calcular a média das notas de uma turma numa prova. Inicialmente, o usuário deve informar ao programa o número "n" de alunos da turma (esse passo é crucial e não deve ser modificado). Em seguida, o usuário deve informar cada uma das "n" notas dos alunos. Ao final, o programa deve exibir a média das notas.

      TEXTOS PARA REFERÊNCIA:

    • Aula 13 (2017-04-25, Terça-feira):

      • Repetição com Variável de Controle usando while.

        • Exemplo em Sala: ler "n" inteiros e contar os positivos.

      • Laço for.

        • Exemplo em Sala: o mesmo de antes, agora por meio do for.

        • Versão do Exemplo usando continue.

        • Elementos Opcionais do for e Repetição Incondicional via for(;;).

        • Exercício em Sala: média de "n" notas usando um for.

        • Solução do Exercício usando Declaração de Variável na Inicialização do for.

      • Conversões Numéricas:

        • Conversão Implícita de int para double (como em "soma / n", soma sendo double e n sendo int)

        • Conversão Explícita de int para double (como em "(double) soma", soma sendo int).

        • Conversão de double para int: parte fracionária descartada.

      OBSERVAÇÃO: Veja as explicações sobre Conversões Implícitas Adicionais.

      EXERCÍCIOS ESSENCIAIS:

      1. (Fatorial) Escreva um programa que leia um inteiro "n" do usuário e então imprima na tela o valor de n! = n*(n−1)*(n−2)*...*2*1. (Se o usuário digitar um valor negativo para "n", a leitura de "n" deve acontecer novamente, até que um valor não-negativo seja digitado. Lembre que 0! = 1.)

      2. (Fibonacci) Escreva um programa que leia um inteiro "n" do usuário e então imprima na tela o valor de "fib(n)", sendo

        fib(n) = | n,                   se n ≤ 1
                 | fib(n−2) + fib(n−1), se n > 1.
        
        Como no exercício anterior, "n" deve ser lido repetidamente até que um número não-negativo seja digitado.

      TEXTOS PARA REFERÊNCIA:

    • Aula 14 (2017-04-27, Quinta-feira):

      • Vetores como Variáveis Automáticas.

        • Declaração de "variable length arrays" e Acesso Indexado aos Elementos.

        • Exemplo em Sala: ler "n" números e imprimi-los na ordem contrária.

        • Exercício em Sala: calcular média e desvio médio de "n" notas.

      EXERCÍCIOS ESSENCIAIS:

      1. (Maiores que o último) Escreva um programa que leia "n" números do usuário e que ao final imprima, dentre os números que foram digitados, aqueles que são maiores que o último número digitado. O valor de "n" deve ser informado inicialmente pelo usuário.

      2. (Consultar i-ésimo) Escreva um programa que leia "n" inteiros do usuário e que depois repetidamente faça o seguinte:

        1. Leia um número "i".

        2. Se "i" não estiver no intervalo de 1 a n, o programa termina.

        3. Se "i" estiver no intervalo, então o programa deve imprimir na tela o i-ésimo número inicialmente digitado pelo usuário. Em seguida, deve-se retornar ao primeiro passo, para nova leitura de "i".

      TEXTOS PARA REFERÊNCIA:

    • Aula 15 (2017-04-28, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO: (SUGESTÃO: crie um arquivo .c para cada questão)

      1. (Distância no Plano) Escreva uma função que receba como argumentos as coordenadas de dois pontos do plano cartesiano, e que retorne a distância euclidiana entre eles.

        Em seguida, escreva um programa que imprima na tela o resultado dado por esta função para dois pontos digitados pelo usuário.

      2. (Contar num Vetor) Escreva um programa que leia "n" números do usuário, guardando-os num vetor (o valor de "n" deve ser informado inicialmente pelo usuário). Em seguida o programa deve ler um número "x", e o programa deve então imprimir na tela o número de ocorrências de "x" no vetor (ou seja, quantos dos "n" números são iguais a "x").


        IMPORTANTE: a partir deste ponto, as soluções das questões podem envolver belas ideias de programação, e é natural que nem todas lhe venham à mente de pronto. Vale a pena, porém, pensar sobre cada questão, mesmo que isso leve um tempo; você aprenderá mais assim.

        (Além disso, as questões mais difíceis estão além do que será cobrado em prova, de forma que você deve se concentrar em aprender, ao invés de se preocupar em encontrar soluções para todas as questões antes da prova.)


      3. (Inverter um Vetor) Escreva um programa que leia um vetor de "n" números do usuário (isto é). Em seguida, inverta os elementos do vetor, sem usar outro vetor para isso. Por fim, imprima o vetor invertido na tela.

        Exemplo: se o vetor digitado for a sequência "3, 5, −1, 9", então o vetor invertido deverá conter a sequência "9, −1, 5, 3". Você deve realmente inverter o vetor, e não simplesmente imprimi-lo na ordem contrária na tela!

      4. (Comparar Vetores) Escreva um programa que leia do usuário 2 vetores de "n" números, e que então informe se os dois vetores são iguais ou não (isto é, se os dois armazenam exatamente a mesma sequência de números).

      5. (Interseção de Vetores) Escreva um programa que leia do usuário 2 vetores de "n" números. Em seguida, o programa deve imprimir na tela os números que os vetores possuem em comum.

      6. (Ordenar Vetor) Escreva um programa que leia um vetor de "n" números do usuário. Em seguida, o programa deve ordenar o vetor, isto é, permutar os números de forma que eles fiquem em ordem crescente. Ao final, o programa deve imprimir na tela o vetor ordenado.

    • Aula 16 (2017-05-02, Terça-feira):

      • Entrada-e-Saída Orientada a Linha.

        printf("Uma");        // Não imprime ainda
        printf(" linha.\n");  // Agora imprime
        int x,y;
        scanf("%d", &x);  // Os 2 números podem ser digitados na mesma linha
        scanf("%d", &y);
        
      • O Tipo char: Constantes e E/S (via getchar e putchar).

      • Relação entre os valores de '0', '1', ..., '9'.

      • Gravação de Texto em Vetor (usando caractere terminal).

      EXERCÍCIOS ESSENCIAIS:

      1. (Tamanho da Linha) Escreva um programa que leia uma linha do usuário, e que em seguida imprima na tela o tamanho da linha.

        Dicas: (1) como detectar o fim da linha? (2) não é necessário usar um vetor.

      2. (Ler "k" Linhas) Escreva um programa que:

        1. Leia um número "k".

        2. Leia um texto de "k" linhas, gravando-o num vetor.

        3. Imprima o texto para o usuário.

        Caso o texto digitado não caiba no vetor, basta imprimir ao final a parte que coube.

      TEXTOS PARA REFERÊNCIA:

      • E/S Orientada a Linha: C11, 5.1.2.3 - 6, 7.21.3 - 3, 7.21.3 - 7.

    • Aula 17 (2017-05-04, Quinta-feira):

      • String em C: sequência de caracteres terminando no valor inteiro zero.

        • Explicação de que 0 == '\0' e que 0 != '0'.

        • Exemplo em Sala: ler linha do usuário, caractere-a-caractere, gravá-la como uma string e depois imprimi-la de volta na tela.

      • Vetores como Argumentos para Funções.

        • Exemplo em Sala: Funções para Ler e Comparar Vetores de Inteiros.

      EXERCÍCIOS ESSENCIAIS:

      1. (Comparar Strings) Escreva uma função que informe se duas strings são iguais ou não. Em seguida, escreva um programa que leia do usuário duas linhas, grave-as como strings e então informe se as linhas são iguais ou não.

        Importante: a função para comparar strings deve receber apenas os vetores onde estão as strings; não é necessário receber os tamanhos desses vetores.

      2. (Palíndromo) Escreva uma função que receba uma string e informe se ela é ou não um palíndromo, isto é, se ela é a mesma sequência lida do início para o fim e do fim para o início. (Naturalmente, apenas os caracteres antes do '\0' entram nessa consideração.)

        Em seguida, escreva um programa que leia uma linha e, usando a função acima, determine se ela é ou não um palíndromo (naturalmente, apenas os caracteres antes do '\n' entram nessa consideração).

      TEXTOS PARA REFERÊNCIA:

    • Aula 18 (2017-05-05, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO: (SUGESTÃO: crie um arquivo .c para cada questão)


      IMPORTANTE: os 4 "exercícios essenciais" das aulas desta semana são importantes e devem ser feitos antes dos exercícios abaixo.
      1. (Contar Dígitos) Escreva um programa que leia uma linha do usuário e então imprima na tela quantos dos caracteres dessa linha são dígitos. Para tanto, use a função isdigit de <ctype.h>, que recebe um caractere e informa se esse caractere é um dígito.

        Importante: você não precisa usar um vetor.

        Opcional: após concluir o exercício da forma acima, escreva você mesmo uma função como isdigit, lembrando do fato de que os valores inteiros '0' ... '9' são consecutivos.

      2. (Códigos dos Caracteres) Escreva um programa que leia caracteres do usuário e então imprima na tela os "códigos" desses caracteres, isto é, os valores inteiros que são utilizados para armazenar esses caracteres no computador. O programa deve seguir os seguintes passos:

        1. Ler uma linha do usuário.

        2. Caso a linha seja vazia (isto é, caso o primeiro caractere já seja o '\n'), então o programa deve imprimir o valor inteiro '\n' e terminar.

        3. Caso a linha não seja vazia, o programa deve imprimir na tela o "código" do primeiro caractere da linha, e em seguida retornar ao passo 1, para ler uma nova linha.

        Importante: você não precisa usar um vetor.

      3. (Ler Texto) Escreva um programa que leia do usuário um texto, gravando-o num vetor. O fim do texto será a primeira linha vazia que o usuário digitar (isto é, uma linha cujo primeiro caractere já seja '\n').

        Ao final, o programa deve imprimir o texto de volta na tela, e informar também:

        1. Quantas linhas o texto possui (sem contar a linha vazia).

        2. Qual é o tamanho da maior linha (não incluindo o '\n').

        Dica: esse exercício pode e deve ser feito em partes. Comece programando a leitura do texto; depois, a impressão; depois, as contagens.
    • Aula 19 (2017-05-09, Terça-feira):

      • O comando switch:

        • Exemplo em Sala: calculadora (ilustra break e default).

        • Exemplo em Sala: caractere é vogal? (Ilustra switch para char e case sem break.)

      • Tira-dúvidas sobre caracteres e strings.

      • Explicação de Função para Comparar duas Strings.

      EXERCÍCIOS ESSENCIAIS:

      1. (Cópia sem Limite) Escreva uma função

        void copiar_sem_limite (char origem[], char destino[])
        
        para copiar uma string de um vetor para outro, já supondo que o vetor de destino é grande o suficiente.

        Em seguida, escreva um programa que:

        1. Leia do usuário uma linha, gravando-a num vetor como uma string.

        2. Copie a string para um segundo vetor.

        3. Imprima a string do segundo vetor na tela.

      2. (Cópia com Limite) Escreva agora uma função

        int copiar_com_limite (char origem[], char destino[], int tam_destino)
        
        que também faça cópia de string, mas que receba o tamanho do vetor de destino, e que, caso a string seja grande demais, grave apenas o que couber no vetor, sempre gravando um '\0' ao final.

        A função acima deve também retornar um inteiro:

        • Caso a string tenha sido inteiramente copiada, então deve ser retornado o índice do vetor de destino onde foi gravado o '\0'.

        • Em caso contrário, deve ser retornado -1 (o que indicará que o '\0' foi gravado na última posição do vetor de destino).

        Por fim, assim como no exercício anterior, escreva um programa que use essa função, e em particular experimente o caso em que o vetor de destino não é grande o suficiente.

    • Aula 20 (2017-05-11, Quinta-feira):

      • Manipulação de Caracteres via <ctype.h>:

        • Exemplo em Sala: trocar caixa (maiúsculas e minúsculas) numa linha.

          • Inclui Função para Ler Linha, Descartando o que não for Gravado.

      • Manipulação de Strings via <string.h>:

        • Exemplo em Sala: ler duas linhas e compará-las via strcmp.

      • Laços Aninhados:

        • Exemplo em Sala: determinar se substring (semelhante a strstr).

      EXERCÍCIOS ESSENCIAIS:

      1. (Contar Tipos de Caracteres) Escreva um programa que leia do usuário uma linha de texto (o seu programa deve funcionar para linhas de qualquer tamanho, e não é necessário gravar a linha num vetor). Em seguida, o programa deve imprimir na tela:

        • O número de letras minúsculas presentes na linha.

        • O número de letras maiúsculas.

        • O número de dígitos.

        • O número de caracteres de pontuação.

        • O número de espaços em branco.

      2. (Contar Ocorrências de Substring) Escreva um programa que leia duas strings do usuário, e que então imprima na tela quantas ocorrências da segunda existem na primeira (essa contagem deve ser feita exclusivamente pelo seu programa, sem recorrer a funções da biblioteca padrão).

    • Aula 21 (2017-05-12, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO: (SUGESTÃO: crie um arquivo .c para cada questão)


      SUGESTÃO: faça os 4 "exercícios essenciais" das aulas desta semana antes de seguir para os exercícios abaixo.
      1. (Funções E/S Strings) Escreva um programa que leia do usuário 2 strings, gravando cada uma num vetor de 20 caracteres, e que então imprima as strings de volta na tela. Requisitos:

        1. Versão 1: as strings devem ser lidas usando fgets. Para um vetor "v" de tamanho "t", a chamada é "fgets(v, t, stdin)".

          Para imprimir as strings, use fputs – chamada do tipo "fputs(v, stdout)".

          Veja a documentação das funções acima para entender os detalhes do que elas realizam. Observe, por exemplo, que "fgets" inclui o '\n' na string se houver espaço. E, caso não haja espaço, o restante da linha é descartado ou continua para ser processado pelo programa?

        2. Versão 2: as strings devem ser lidas usando scanf e impressas usando printf, ambas usando %s.

          Compare com a versão anterior: a chamada a scanf usa o tamanho do vetor? E grava uma string com mais de uma palavra? E o '\n' da linha é gravado na string?

      2. (sprintf e sscanf) variações de printf para escrever numa string da mesma forma como se escreve na tela:

        int n = 5;
        char v1[100];
        sprintf (v1,      "O quadrado de %d é %d.\n", n, n*n);
        snprintf(v1, 100, "O quadrado de %d é %d.\n", n, n*n);
        
        De forma análoga, existe a função sscanf, para ler de uma string como se lê da tela.

        Para praticar o uso de sscanf, escreva um programa que leia uma linha do usuário e grave-a numa string (você pode usar "fgets" para isso). Essa linha deve conter três números separados por espaços, e você deve usar sscanf para ler esses números da string e gravá-los em três variáveis numéricas. Por fim, essas três variáveis devem ser impressas de volta na tela.

      3. (Literais String) Uma "literal string" como "Linguagem C" denota uma string gravada pelo programa em algum vetor que estará alocado durante todo o programa. Tal string pode ser livremente lida e percorrida pelo seu programa, mas não é válido escrever nelas.

        Sabendo disso, escreva um programa que peça ao usuário para digitar uma linha com o nome dele. Em seguida, o programa deve informar se o nome do usuário é igual ao seu nome. Seja objetivo: use "fgets" para ler o nome do usuário, e use "strcmp" para fazer a comparação – como em strcmp(v, "Bezerra de Menezes").

      4. (Remover Caractere de String) Escreva uma função

        void remover_char_de (char c, char s[])
        
        que remova de uma string "s" todas as ocorrências de um caractere "c" (exemplo: removendo "o" de "computador", obtemos "cmputadr").

        Observação: essa função pode ser escrita sem o uso de um vetor auxiliar.

      5. (Ocorrência Indexada de String) Escreva uma função

        int ocorre_no_indice (char r[], int i, char s[])
        
        que informe se no índice "i" da string "s" começa uma ocorrência da string "r".
      6. (Remover Substring) Escreva uma função

        void remover_str_de (char r[], char s[])
        
        que remova de uma string "s" todas as ocorrências de uma string "r".

        Dica: você não precisa usar um vetor auxiliar, mas pode usar a função do exercício anterior como auxílio.

    • Aula 22 (2017-05-16, Terça-feira):

      • Ponteiros:

        • Introdução ao Conceito de Ponteiro.

        • Os operadores & e *: descrição e exemplos.

        • Declaração de Ponteiros.

        • Exemplo em Sala: a Função para Troca de Valores de Variáveis.

        • Conversão Implícita de Vetor para Ponteiro. Exceções:

          1. Se operando de &.

          2. Se operando de sizeof.

          3. Se literal string em inicialização.

        • Exemplos de Ponteiros para Elementos de Vetor (incluindo conversão implícita).

      MATERIAL PARA LEITURA (OPCIONAL):

      EXERCÍCIOS ESSENCIAIS:

      1. Escreva uma função

        void inverter (int v[], int t)
        
        que inverta um vetor de números, mas que, ao invés de trocar elementos explicitamente, chame a função "trocar" escrita em sala.

        Teste a sua função e se certifique de que ela funciona, inclusive para vetores de apenas um elemento.

      2. Escreva uma função

        void ler_int (int *p)
        
        que leia do usuário os dígitos de um número inteiro, caractere-a-caractere (via "getchar"), e que ao final grave o inteiro digitado na variável apontada por "p". A leitura dos dígitos deve parar após a detecção do primeiro caractere que não seja um dígito.

        Dicas: lembre (1) de "isdigit", (2) que '7' - '0' == 7, e (3) que 421 = (4*10 + 2)*10 + 1.

    • Aula 23 (2017-05-18, Quinta-feira):

      • Aritmética de Ponteiros:

        • Soma e Subtração de Ponteiros e Inteiros.

        • Comparação e Subtração entre Ponteiros.

        • Percurso de Vetores via Ponteiros.

        • Exemplo em Sala: Leitura e Soma de Vetor via Ponteiros.

      EXERCÍCIOS ESSENCIAIS:

      1. (Inverter String) Escreva uma função

        void inverter_string (char *s)
        
        que inverta a string (iniciada no elemento apontado por) "s". Use apenas ponteiros para percorrer o vetor.
      2. (Palavras da String) Escreva uma função

        void imprimir_palavras (char *s)
        
        que imprima, em linhas diferentes, todas as palavras presentes na string "s". Use ponteiros para percorrer a string.

        Exemplo de saída, para a string "Avenida 13 de maio, esquina com Senador Pompeu."

        Avenida
        13
        de
        maio
        esquina
        com
        Senador
        Pompeu
        

        Ao final, escreva um programa que leia uma string do usuário e então aplique a função acima sobre essa string.

        Dica: classificação de caracteres via <ctype.h>.

    • Aula 24 (2017-05-19, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO:


      SUGESTÕES:
      • Antes de seguir para os exercícios abaixo, faça os exercícios anteriores desta semana.

      • Crie um arquivo .c para cada questão.


      1. (Concatenação) Escreva uma função

        char* concatenar (char *p, char *q, char *r)
        
        que concatene (isto é, "junte") as strings p e q, gravando o resultado como uma string no vetor apontado por r. (Suponha que o vetor é grande o suficiente.)

        Ao final, a função deve retornar um ponteiro para o elemento de r onde foi gravado o '\0'.

        Escreva um programa que aplique essa função a strings digitadas pelo usuário.

      2. (Imprimir Primeira Palavra) Escreva uma função

        void primeira_palavra (char *s)
        
        que imprima na tela a primeira palavra da string s.

        Dica: classificação de caracteres via <ctype.h>.

      3. (n-ésima Palavra) Escreva uma função

        char* esima_palavra (char *s, int n)
        
        que retorne um ponteiro para o início da n-ésima palavra da string s. Observações:
        1. As palavras devem ser indexadas a partir de zero: palavra 0, palavra 1, palavra 2, etc.

        2. Caso a string não possua palavras o suficiente, deve ser retornado um ponteiro para o '\0' da string.

        Em seguida, usando essa função e aquela do exercício anterior, escreva um programa que leia do usuário uma string e um inteiro "n", e que então imprima na tela a n-ésima palavra da string.

      4. (String Terminando Texto) Escreva uma função

        char* ler_texto (char *v, int t, char *termino)
        
        que leia um texto do usuário e grave-o como uma string no vetor "v", de tamanho "t". O texto pode ter várias linhas, mas a leitura terminará quando for lida uma linha na qual ocorra a string apontada por termino; nesse caso, apenas as linhas anteriores a essa última devem fazer parte da string gravada em "v".

        Caso o fim do vetor seja atingido antes de ser detectado o fim do texto, a string gravada no vetor deve possuir os t-1 primeiros caracteres do texto.

        Ao final, a função deve retornar um ponteiro para o elemento do vetor onde foi gravado o '\0'.

        Após escrever a função acima, escreva um programa que a utilize para ler um texto do usuário, e que depois imprima o texto de volta na tela.

    • Aula 25 (2017-05-23, Terça-feira):

      • Operador []: Definição e Exemplos.

      • Percurso de Vetor via Ponteiro e via Indexação.

        • Exemplo em Sala: Impressão de String na Tela.

        • Passagem de Vetores para Funções.

        • Considerações sobre Performance.

        • Inicialização de Ponteiro via literal string.

      • Versões Prefixa e Posfixa do Operador de Incremento.

        • Definições e Exemplos.

        • Uma Implementação Minimalista de strcpy.

      • Ponteiros Nulos.

        • Exemplo em Sala: função que retorna ponteiro para primeiro '\n', ou ponteiro nulo (se não houver '\n').

      EXERCÍCIOS ESSENCIAIS:

      1. (Remover '\n') Escreva uma função

        char* remover_bn (char *s)
        
        que substitua por '\0' o primeiro '\n' da string s, e que retorne um ponteiro para o elemento em questão. Caso a string não possua um '\n', a função deve retornar um ponteiro nulo, deixando a string inalterada.

        Em seguida, escreva um programa que leia uma linha do usuário via "fgets", aplique a função acima à string lida e imprima a string resultante na tela.

      2. (Remover Caractere de String) Escreva uma função

        char* remover_char (char *s, char c)
        
        que remova da string s a primeira ocorrência de c. Exemplo: removendo a primeira ocorrência de 'a' em "palavra", obtemos a string "plavra".

        A função deve retornar um ponteiro para o elemento da ocorrência, ou um ponteiro nulo se não houver ocorrências do caractere na string.

    • Aula 26 (2017-05-25, Quinta-feira):

      • O Processo de Manipulação de Arquivos em C: abertura, uso e fechamento.

      • Escrita de Arquivos:

        • Exemplo em Sala: imprimir string "Duas\nlinhas\n" no arquivo "teste.txt" via fputc, fputs e fprintf.

      • Preliminares para "fgetc":

      • Leitura de Arquivos Caractere-a-Caractere via fgetc:

        • Exemplo em Sala: imprimir arquivo "teste.txt" na tela.

        • Lembrete: "fgetc" retorna valor de "signed char", convertido para "int", ou EOF (também "int").

      EXERCÍCIOS ESSENCIAIS:

      1. (Número de Caracteres do Arquivo) Escreva um programa que leia do usuário um nome de arquivo, e que em seguida imprima na tela quantos caracteres o referido arquivo possui.

        ATENÇÃO: todo programa envolvendo arquivos deverá imprimir um aviso em caso de erro ao abrir arquivos.

        Sugestão: não use vetores, exceto para o nome do arquivo.

      2. (Copiar Arquivo) Escreva um programa para copiar um arquivo. O nome do arquivo a ser copiado deve ser lido do usuário, assim como o nome do arquivo novo, onde será gravada a cópia.

        A cópia deve ser feita caractere-a-caractere.

        Sugestão: não use vetores, exceto para os nomes dos arquivos.

    • Aula 27 (2017-05-26, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO:


      SUGESTÕES:
      • Antes de seguir para os exercícios abaixo, faça os exercícios anteriores desta semana.

      • Crie um arquivo .c para cada questão.


      1. (Da Tela para Arquivo) Escreva um programa que leia do usuário um texto, e que então grave-o no arquivo "texto.txt". O fim do texto será indicado pela primeira linha vazia digitada pelo usuário.

        O seu programa deve funcionar para textos de qualquer tamanho, e não deve consultar o usuário a respeito do tamanho do texto que será digitado.

        Sugestão: não use vetores.

      2. (Tamanho da Maior Linha) Escreva um programa que leia do usuário um nome de arquivo, e que em seguida imprima na tela o tamanho da maior linha do arquivo.

        Sugestão: não use vetores, exceto para o nome do arquivo.

      3. (N-ésima Linha do Arquivo) Escreva um programa que leia do usuário um nome de arquivo e um inteiro "n", e que então imprima na tela a n-ésima linha do arquivo. Caso o arquivo seja "pequeno" e não possua a linha de número "n", deve ser impressa na tela uma mensagem informando o número de linhas do arquivo.

        Sugestão: não use vetores, exceto para o nome do arquivo.

      4. (Imprimir Maior Linha) Escreva um programa que leia do usuário um nome de arquivo, e que então imprima na tela a maior linha do arquivo.

        Sugestão: leia o arquivo uma primeira vez, para descobrir o número da maior linha (veja o penúltimo exercício anterior). Em seguida leia o arquivo novamente, dessa vez para imprimir na tela a linha cujo número foi calculado no passo anterior (veja o exercício anterior). Observe que tudo isso pode ser feito sem o uso de vetores, exceto pelo nome do arquivo.

      5. (Remover Linha de Arquivo) Escreva um programa que leia do usuário um nome de arquivo e um inteiro "n", e que então remova a n-ésima linha do referido arquivo.

        Sugestão: crie um arquivo auxiliar, e nele grave as linhas do arquivo original, com exceção da linha "n". Em seguida, feche o arquivo original e o abra novamente, agora em modo de escrita (o que irá apagar o conteúdo dele), e então copie o conteúdo do arquivo auxiliar para o arquivo original. Observe que tudo isso pode ser feito sem o uso de vetores, exceto pelo nome do arquivo.

    • Aula 28 (2017-05-30, Terça-feira):

    • Aula 29 (2017-06-01, Quinta-feira):

      • Recapitulação: Escrita em Arquivo via fputc, fputs e fprintf.

        • Exercício em Sala: ler nomes e idades do usuário (parando ao primeiro nome vazio), e gravá-los em "cadastro.txt", neste formato:

          nome  1
          idade 1
          nome  2
          idade 2
          ...
          
        • Solução 1: Escrita via "fputc" e "fprintf".

        • Solução 2: Escrita via "fputs" e "fprintf".

      • Leitura de Arquivos via fgets e fscanf:

        • Valores Retornados e Detecção de Fim de Arquivo.

        • Exemplo em Sala: leitura do arquivo "cadastro.txt", via "fgets" e "fscanf", e impressão na tela, via "fputs" e "fprintf".

      EXERCÍCIOS ESSENCIAIS:

      1. (Escrever na Mesma Linha) Escreva uma variação do programa escrito em sala, que também leia nomes e idades do usuário (também em linhas separadas e até o primeiro nome vazio), mas que escreva o arquivo "cadastro.txt" no formato abaixo:

        nome 1 / idade 1
        nome 2 / idade 2
        ...
        
      2. (Idades do Cadastro) Escreva agora um programa que leia o arquivo "cadastro.txt" acima e que então imprima na tela a maior idade, a menor idade e a média das idades presentes no cadastro.

    • Aula 30 (2017-06-02, Sexta-feira):

      EXPLICAÇÕES ADICIONAIS: Funções para Alocação Dinâmica de Memória.

      EXERCÍCIOS ESSENCIAIS:

      1. (Alocar Vetor Grande) Escreva um programa que leia um inteiro positivo "n" do usuário, e que então aloque um vetor de "n" double's dinamicamente, isto é, via "malloc" ou "calloc". Em seguida, o programa deve apenas informar ao usuário se a alocação foi bem-sucedida.

        Posteriormente, escreva um programa parecido com aquele acima, mas que declare o vetor como um "variable length array" (double v[n]), e que escreva na tela uma mensagem informando que o vetor está alocado.

        Por fim, experimente com os dois programas e verifique: o que acontece quando tentamos alocar vetores muito grandes?

      2. (De Arquivo para Vetor) Escreva um programa que leia do usuário um nome de arquivo, e que em seguida:

        1. Calcule o tamanho "n" do arquivo, em caracteres.

        2. Aloque dinamicamente um vetor de "n" caracteres.

        3. Grave todo o arquivo no vetor, caractere-a-caractere.

        4. Imprima na tela uma mensagem de leitura bem-sucedida.

        Em seguida, teste o seu programa com arquivos grandes, lembrando que, apesar de o programa funcionar usando caracteres, o arquivo pode ser de qualquer tipo: foto, vídeo, etc.

    • Aula 31 (2017-06-06, Terça-feira):

      • Introdução a Registros (Estruturas) em C

      • Exemplo em Sala:

        • Definição de um Tipo "struct" com Membros de Diferentes Tipos

        • Declaração de Variáveis de Tipo "struct"

        • Acesso a Membros por meio do Operador "."

        • Cópia de struct's via Atribuição e em Chamada de Função com Parâmetro "struct"

        • Declaração e Definição separadas de Função

      • Exercício em Sala: ler cadastro do usuário e gravar em arquivo (1º exercício abaixo).

      EXERCÍCIOS ESSENCIAIS:

      1. (Gravar Cadastro em Arquivo) Primeiramente, defina um struct "Data" para armazenar datas via dia, mês e ano. Em seguida, defina um struct "Pessoa" para armazenar nome e data de nascimento de uma pessoa.

        Em seguida, escreva um programa que leia do usuário os dados de várias pessoas (condição de parada: nome vazio), gravando-os no arquivo "cadastro.txt", no seguinte formato:

        Dennis Ritchie
        9/9/1941
        Bjarne Stroustrup
        30/12/1950
        ...
        
        Atenção: ao ler os dados de uma pessoa, você deve primeiramente gravá-los numa variável "struct", e só depois gravá-los no arquivo.
      2. (Ler Cadastro de Arquivo) Escreva um programa para permitir ao usuário consultas sobre o cadastro gravado pelo programa anterior. Mais especificamente, o seu programa deve:

        1. Ler o arquivo "cadastro.txt" uma primeira vez, para contar o número "n" dos cadastros gravados no arquivo. Observe que todo cadastro ocupa 2 linhas, e que todas as linhas desse arquivo específico estão terminadas por um \n.

        2. Alocar dinamicamente um vetor de "n" struct's "Pessoa", e nele gravar os cadastros do arquivo.

        3. A partir daqui, repetidamente responder consultas do usuário. O dado de cada consulta é um ano lido do usuário, e em resposta o programa deve imprimir na tela os nomes das pessoas que nasceram naquele ano. O programa deve terminar quando o usuário digitar um ano negativo.

    • Aula 32 (2017-06-08, Quinta-feira):

      EXERCÍCIOS ESSENCIAIS:

      1. (Consulta por Intervalo de Datas) Escreva uma função

        int anterior_ou_igual (struct Data *a, struct Data *b)
        
        que retorne 1 caso a data apontada por "a" seja anterior ou igual à data apontada por "b", e que retorne 0 em caso contrário.

        Em seguida, usando a função acima, escreva uma variação do 2º exercício feito em sala, na qual a entrada de cada consulta consista em uma data de início e uma data de fim, e em resposta às quais o programa imprima na tela os nomes das pessoas que nasceram no intervalo de datas em questão.

      2. (Consulta por Parte do Nome) Escreva uma variação do 2º exercício feito em sala, na qual a entrada de cada consulta seja uma palavra digitada pelo usuário, e em resposta à qual o programa imprima na tela os nomes completos (do cadastro) nos quais essa palavra ocorre.

        Dica: lembre que a função strstr detecta substrings.

    • Aula 33 (2017-06-09, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO:


      SUGESTÕES:
      • Antes de seguir para os exercícios abaixo, faça os exercícios anteriores desta semana.

      • Crie um arquivo .c para cada questão.


      1. (Retângulo Delimitador via Estruturas) Defina um struct "Ponto", que armazene as coordenadas racionais de um ponto do plano cartesiano.

        Em seguida, defina um struct "Retangulo", para representar retângulos cujos lados sejam paralelos aos eixos. Observe que tais retângulos podem ser especificados de maneira simples por meio de duas coordenadas "x" e duas coordenadas "y".

        Em seguida, escreva uma função

        struct Retangulo ret_delimitador (struct Ponto *v, int n)
        
        que calcule e retorne o menor retângulo (de lados paralelos aos eixos) que contenha todos os "n" pontos de um dado vetor "v". A função deve supor que n ≥ 1.

        Por fim, escreva um programa que leia "n" pontos do usuário e ao final imprima os dados do menor retângulo delimitador dos pontos digitados.

      2. (Uso de Realocação) Defina um struct "Pessoa" que armazene nome e idade.

        Em seguida, escreva uma função

        struct Pessoa* ampliar_vetor (struct Pessoa *v, int t, int novo_t)
        
        para "ampliar" um vetor "v", do tamanho original "t" para um tamanho "novo_t" tal que novo_t ≥ t ≥ 1. A função deve usar realloc para fazer realizar a tarefa, e deve retornar um ponteiro para o novo vetor (ou nulo, caso a alocação seja mal-sucedida). Atenção: devido ao uso de "realloc", o corpo dessa função pode ser escrito em apenas uma linha!

        Por fim, usando a função acima, escreva um programa que grave em vetor os dados de uma quantidade qualquer de pessoas, parando quando for digitado o primeiro nome vazio. Passos a seguir:

        1. O programa deve começar alocando, via malloc, um vetor de apenas 1 Pessoa.

          (Em qualquer momento do programa, se houver erro de alocação, deve ser impressa uma mensagem para o usuário e o programa deve terminar.)

        2. Em seguida, o programa deve entrar numa repetição para ler do usuário os dados das pessoas.

        3. O programa deve manter registrados o tamanho do vetor atual e a quantidade de pessoas digitadas. Sempre que necessário, o programa deve usar a função "ampliar_vetor" para conseguir um vetor com o dobro do tamanho atual.

        4. Quando o usuário terminar a digitação dos dados das pessoas, o programa deve imprimir na tela os dados de todas elas.

      3. (Função de Realocação) Escreva agora, sem usar realloc, a sua própria versão da função "ampliar_vetor" explicada no exercício anterior:

        struct Pessoa* ampliar_vetor (struct Pessoa *v, int t, int novo_t)
        

        Passos a seguir:

        1. Alocar, via "malloc", um vetor de "novo_t" Pessoa's. (Lembre que novo_t ≥ t ≥ 1.)

        2. Caso a alocação seja mal-sucedida, a função deve retornar um ponteiro nulo.

        3. Caso a alocação seja bem-sucedida, a função deve:

          1. Copiar os "t" registros de "v" para o novo vetor.

          2. Desalocar "v", via "free".

          3. Retornar um ponteiro para o novo vetor.

        Em seguida, escreva uma variação do programa anterior:

        1. Usando a nova função "ampliar_vetor".

        2. Na qual, ao final do programa, os dados das pessoas sejam gravados no arquivo "cadastro.txt".

    • Aula 34 (2017-06-13, Terça-feira):

      • Exemplos de Vetores de Diferentes Tipos e Acesso aos Elementos:

        • Vetor de double's

        • Vetor de struct's

        • Vetor de Ponteiros para struct's

        • Vetor de Vetores de double's

      • Matrizes como Vetores de Vetores em C

        • Exemplo em Sala: ler matriz de inteiros, um elemento por linha, e depois imprimi-la de forma retangular e alinhada.

      EXERCÍCIOS ESSENCIAIS:

      1. (Soma de Matrizes) Escreva um programa que leia do usuário duas matrizes m × n (os valores das dimensões devem ser lidos do usuário no início), e que ao final imprima na tela a soma das matrizes.

        Sugestão: por conveniência, ao invés de ler um elemento por linha, escreva o programa de forma que o usuário já possa digitar as matrizes em formato retangular.

      2. (Triangular Superior) Escreva um programa que leia do usuário uma matriz m × n, e que em seguida imprima na tela se a matriz é ou não triangular superior (isto é, se todos os elementos abaixo da diagonal principal da matriz são iguais a zero).

    • Aula 35 (2017-06-16, Sexta-feira): prática em laboratório.

      EXERCÍCIOS PARA O LABORATÓRIO:


      SUGESTÕES:
      • Antes de seguir para os exercícios abaixo, faça os exercícios anteriores desta semana.

      • Crie um arquivo .c para cada questão.


      1. (Trocar Linhas e Colunas) Escreva um programa que comece lendo do usuário uma matriz, cujas dimensões devem também lidas do usuário inicialmente. Em seguida, a matriz lida do usuário deve ser impressa na tela, em forma retangular. Em seguida, o programa deve:

        1. Ler do usuário se ele deseja trocar linhas, ou se deseja trocar colunas, ou se deseja sair.

        2. Em caso de opção por troca, o programa deve ler do usuário os números de duas linhas ou duas colunas, de acordo com a opção selecionada.

        3. Em seguida, o programa deve trocar as linhas ou colunas escolhidas, imprimir na tela a matriz resultante, e por fim voltar ao passo 1, para escolha de nova opção.

        Dica: faça a troca elemento-a-elemento, sem usar um vetor ou matriz auxiliar.

      2. (Multiplicação de Matrizes) Escreva um programa que leia duas matrizes de dimensões "p × q" e "q × r", e que então imprima na tela o produto dessas matrizes.

        Dica: caso você tenha dificuldade em vislumbrar de início a forma geral do algoritmo, os seguintes passos deverão ajudar:

        1. Lembre que o produto de matrizes "p × q" e "q × r" é uma matriz "p × r". Isso significa que a sua tarefa é calcular cada um dos elementos de uma matriz com essas dimensões.

        2. Naturalmente, no código final, o cálculo de cada um dos elementos da matriz acontecerá dentro de estruturas de repetição. Porém, para mais claramente entender o código para o cálculo de cada elemento, escreva, como rascunho, um código que sirva exclusivamente para calcular o elemento [0,0] da matriz produto.

          Atenção: isso não é perda de tempo, ao contrário: é uma maneira concreta por meio da qual você pode chegar, sozinho(a), à solução da questão.

        3. Em seguida, escreva, também como rascunho, um código para calcular o elemento [0,1] da matriz produto. Em que esse código difere do anterior?

        4. E como fica, agora, o código para o cálculo do último elemento da primeira linha?

        5. Feitos os itens acima, você está em posição de escrever um laço para calcular todos os elementos da primeira linha: vá em frente!

        6. Como fica, agora o cálculo do elemento [1,0], o primeiro da segunda linha?

        7. E o cálculo do primeiro elemento da última linha, como fica?

        8. Feitos os itens acima, você deverá estar em condições de escrever um laço para "passar por todas as linhas", e, em cada linha, usando o laço escrito anteriormente, calcular os elementos de todas as colunas, concluindo o algoritmo.

      3. (Adição Ponderada de Linhas) Escreva uma variação do programa de trocar linhas e colunas, na qual, ao invés de trocar, o programa adicione os elementos da linha "i", multiplicados por um número "k", aos elementos da linha "j" (o número "k" é o mesmo para todos os elementos da linha). Caso deseje, você pode fazer um programa que manipule apenas linhas (e não colunas), mas, como antes, o programa deve permitir ao usuário a realização de várias operações (e não apenas uma).

        Observe que esse programa permite ao usuário "brincar" de resolver sistemas lineares, por meio de matrizes "m × m+1": experimente!

    • Aula 36 (2017-06-20, Terça-feira):

      • Exemplos sobre Ponteiros para Matrizes (representadas como Vetores de Vetores).

      • Matrizes e Funções:

        • Matrizes como Parâmetros

        • Matrizes como Argumentos

        • Exemplo em Sala: função para imprimir coluna de uma matriz, e programa usando a função.

        • Exemplo em Sala: função para multiplicar matrizes "p × q" e "q × r".

      EXERCÍCIOS ESSENCIAIS:

      1. (Função para Ler Matriz) Escreva uma função

        void ler_matriz (int m, int n, double M[m][n])
        
        que leia do usuário os números de uma matriz racional m × n, digitados em forma retangular, e que grave-os na matriz "M" recebida pela função.

        Você pode utilizar essa função no programa da próxima questão.

      2. (Solução de Sistema Linear?) Escreva um programa que leia do usuário um sistema de equações lineares, bem como um candidato a solução, e que então imprima na tela se o candidato é de fato uma solução.

        O sistema linear será digitado pelo usuário na forma de uma matriz m × n+1, sendo "m" o número de equações e "n" o de variáveis. O candidato a solução é uma atribuição de valores às "n" variáveis, e deve ser lido como uma sequência de números numa mesma linha.

        O cerne do programa deve ser uma função

        int eh_solucao ( int num_eq,                   // número de equações
                         int num_vars,                 // número de variáveis
                         double S[num_eq][num_vars+1], // Sistema
                         double cand[num_vars],        // Candidato a solução
                         int equacao_ok[num_eq] )      // Equação resolvida?
        
        que, para cada "i", grave 1 em equacao_ok[i] se a equação S[i] é resolvida pelo candidato "cand", e que grave 0 em caso contrário. A função deve ainda retornar 1 se "cand" for de fato uma solução (isto é, resolver todas as equações), e 0 em caso contrário. (Atenção: essa função já recebe "S" e "cand" prontos; ela não lê valor algum do usuário.)

        Ao final, o programa deve usar a função acima para informar ao usuário se o candidato é solução, e, caso não seja, quais equações não foram resolvidas.

    • Aula 37 (2017-06-22, Quinta-feira):

      • Nomes de Tipos em C

      • Declaração de Ponteiros para Alocação Dinâmica de Vetores:

        • Exemplo com "double": versão n*sizeof(double)

        • Exemplo com "double": versão sizeof(double [n])

        • Exemplos com Registros

        • Forma Geral

        • Exemplos com Matrizes (representadas como vetores de vetores)

        • Exemplos com Ponteiros

      • Passagem de Matrizes Alocadas Dinamicamente para Funções

    • Aula 39 (2017-06-27, Terça-feira):