Primeiros exercícios sobre a linguagem C. Exercícios de 31 a 35.
Instalação: Já está instalado nos laboratórios. Para instalar no seu computador pessoal, primeiro veja se o gcc está instalado. Se não estiver, dê o comando sudo apt install gcc make. Depois use o comando do Eclipse "Help>Install New Software...". Na caixa "Work with:" insira o p2 software repository correto para a sua versão do Eclipse. Depois selecione e instale apenas "CDT Main features". [Estas instruções são para o Linux. Noutros sistemas, a instalação do C poderá ser um pouco complicada. No caso do Windows, tente isto (não testado).]
int x; int f(int a) { x = a + 1; return x; } int g(int a) { x = a - 1; return x; }Suponha que f e g são usadas num segmento de programa da seguinte forma:
... x = 10; s1 = f(x) + g(x); x = 10; s2 = g(x) + f(x);
Quais os valores que ficam em s1 e s2, assumindo que os operandos nas expressões são avaliados da esquerda para a direita. Note que, em geral, os compiladores têm a liberdade de definir a ordem de avaliação ou seja a ordem de avaliação das subexpressões está indefinida ao nível da linguagem. Isso recomenda que evitemos escrever código do género do que está contido neste exemplo.
Pedimos-lhe para completar as funções blockFill_char_uint_double e blockPrint_char_uint_double.
A função blockFill_char_uint_double guarda no início dum bloco três valores de diferentes tipos, sem qualquer alinhamento: um char, um unsigned int e um double.
A função blockPrint_char_uint_double extrai e imprime (um por linha) três valores do início dum bloco, com os tipos: char, um unsigned int e um double.
A função main já está escrita e serve para testar se você escreveu bem as funções anteriores.
#include <stdio.h> #define BLOCK_SIZE 32 typedef unsigned char Byte; typedef Byte Block[BLOCK_SIZE]; void blockZero(Block b) { int i; for( i = 0 ; i < BLOCK_SIZE ; i++ ) b[i] = 0; } void blockPrint(Block b) { int i; for( i = 0 ; i < BLOCK_SIZE ; i++ ) printf("%02x ", b[i] & 0xFF); printf("\n"); } void blockFill_char_uint_double(Block b, char c, unsigned int i, double d) { Byte *pt = b; // fazer } void blockPrint_char_uint_double(Block b) { Byte *pt = b; // fazer printf("\n"); } int main(void) { Block b; blockZero(b); blockPrint(b); blockFill_char_uint_double(b, 'a', ~0, 667.6e-22); blockPrint(b); blockPrint_char_uint_double(b); return 0; } |
Use o seguinte código como ponto de partida. Vai precisar de usar um apontador.
#include <stdio.h> #include <stdint.h> #if defined(__LP64__) typedef uint64_t Word; #else typedef uint32_t Word; #endif typedef Word *Ptr; void f(Word a1, Word a2, Word a3) { Word local1 = 55555; Word local2 = 66666; Word local3 = 77777; // ... } int main(void) { f(11111, 22222, 33333); return 0; } |
O problema já está parcialmente resolvido e estude o código abaixo, especialmente o tipo "Shape".
No código abaixo, também se oferece um construtor de pontos e um construtor de linhas.
#include <stdio.h> #include <math.h> #include <stdlib.h> typedef enum { LINE, CIRCLE, RECTANGLE } ShapeKind ; typedef struct { double x, y; } Point; typedef struct { Point p1, p2; } Line; typedef struct { Point centre; double radius; } Circle; typedef struct { Point top_left; double width, height; } Rectangle; typedef struct { // Isto é um tipo SOMA, programado com a ajuda duma UNION ShapeKind kind; int color; union { Line line; Circle circle; Rectangle rectangle; } u; } Shape; Point point(double x, double y) // construtor de pontos { Point p = {x, y}; return p; } Shape line(Point p1, Point p2, int color) // construtor de linhas { Line l = {p1, p2}; Shape s = {LINE, color}; s.u.line = l; return s; } int main(void) { Shape c = circle(point(0,0), 1, 99); printf("%f\n", area(c)); Shape t = triangle(point(0,0), point(5,10), point(10,5), 99); printf("%f\n", area(t)); return 0; } |
a) Escreva os construtores que faltam.
b) Escreva uma função chamada area para calcular a área duma Shape.
c) Para verificar se a solução obtida é ou não é extensível, faça todas as modificações necessárias para adicionar triângulos representados por três vértices. (área do triângulo)
Depois execute o programa e observe o aparecimento de valor real expecial inf.
Explicação: Uma variável real tem uma capacidade limitada relativamente à magnitude dos valores representáveis. Mas existem estes três valores especiais: inf -inf nan. O primeiro representa infinito, o segundo representa menos infinito, e o terceiro significa not a number. O valor nan é gerado quando se tenta efetuar uma operação com argumentos inválidos, por exemplo, uma divisão de zero por zero. A linguagem C suporta especificamente o standard da indústria: IEEE 754.
Sugestão: Tome o valor 1.0/3.0 = 0.3333333..., decomponha-o em 100 partes, adicione as 100 partes. Será que assim conseguimos reconstituir o valor 1.0/3.0.
Discussão: Quando trabalhamos com números reais temos de tomar em consideração o problema da inexatidão dos reais e em muitas situações não nos interessa usar a operação de igualdade. É melhor testar se o valor está a uma distância muito pequena (digamos a menos de 0.00000000001) do valor a comparar. Outra questão que vale a pena referir: as quatro operações básicas dos reais (+ - * /) são mais exatas do que as operações da biblioteca math.h. Por exemplo, para se obter o quadrado dum número real x, a forma certa é x*x e jamais pow(x,2). Se o problema se resolver de forma simples usando as operações aritméticas básicas, então devemos evitar as funções de biblioteca.