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.