(→Animal simples) |
(→Animal simples) |
||
Line 17: | Line 17: | ||
* função '''printAnimal''' que, quando aplicada a um animal, apresenta os seus dados (use '''printf''' para apresentar cada campo do animal) | * função '''printAnimal''' que, quando aplicada a um animal, apresenta os seus dados (use '''printf''' para apresentar cada campo do animal) | ||
* programa – '''main''' – que ilustra a utilização das funções anteriores | * programa – '''main''' – que ilustra a utilização das funções anteriores | ||
+ | |||
+ | === Interface do conceito "Animal" === | ||
<c> | <c> | ||
//TODO | //TODO | ||
+ | </c> | ||
+ | |||
+ | === Implementação do conceito "Animal" === | ||
+ | |||
+ | Ficheiro Animal.c: [[media:Animal.c]] | ||
+ | <c> | ||
+ | #include <string.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <stdio.h> | ||
+ | #include "Animal.h" | ||
+ | |||
+ | struct animal { | ||
+ | char _name[16]; | ||
+ | int _age; | ||
+ | double _weight; | ||
+ | }; | ||
+ | |||
+ | Animal newAnimal(const char *name, int age, double weight) { | ||
+ | //Animal animal = (Animal)malloc(sizeof(*Animal)); | ||
+ | Animal animal = (Animal)malloc(sizeof(struct animal)); | ||
+ | if (animal != NULL) { | ||
+ | strcpy(animal->_name, name); | ||
+ | animal->_age = age; | ||
+ | animal->_weight = weight; | ||
+ | } | ||
+ | return animal; | ||
+ | } | ||
+ | |||
+ | void destroyAnimal(Animal animal) { | ||
+ | if (animal) { | ||
+ | free(animal); | ||
+ | animal = NULL; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | const char *getAnimalName (Animal animal) { return animal->_name; } | ||
+ | int getAnimalAge (Animal animal) { return animal->_age; } | ||
+ | double getAnimalWeight(Animal animal) { return animal->_weight; } | ||
+ | |||
+ | /* note that we require animal1 and animal2 to be valid animals: any of | ||
+ | them being NULL pointers will result in a false comparison. */ | ||
+ | int equalsAnimal(Animal animal1, Animal animal2) { | ||
+ | if (animal1 == NULL || animal2 == NULL) return 0; | ||
+ | return !strcmp(getAnimalName(animal1), getAnimalName(animal2)) && | ||
+ | getAnimalAge(animal1) == getAnimalAge(animal2) && | ||
+ | getAnimalWeight(animal1) == getAnimalWeight(animal2); | ||
+ | } | ||
+ | |||
+ | void printAnimal(Animal animal) { | ||
+ | printf("== Animal ==\n"); | ||
+ | printf("Name: %s\n", getAnimalName(animal)); | ||
+ | printf("Age: %d\n", getAnimalAge(animal)); | ||
+ | printf("Weight: %g\n", getAnimalWeight(animal)); | ||
+ | } | ||
+ | </c> | ||
+ | |||
+ | === Programa exemplo === | ||
+ | |||
+ | <c> | ||
+ | |||
</c> | </c> | ||
Os exercícios seguintes ilustram a definição de tipos de dados abstractos e de suas instâncias. Estas instâncias são semelhantes aos objectos suportados por linguagens como o C++ ou o Java, mas, como estão implementados em C, algumas das operações têm de ser definidas explicitamente pelo programador.
Os exemplos tocam também no aspecto da reutilização de código: em linguagens OO, é algo que surge "naturalmente". Nestes exemplos, é necessário mais trabalho. Os exemplos são implementados em C++ no final (apenas para uma comparação mais directa com C: deixa-se como exercício a implementação em Java ou em outras linguagens de programação).
A tarefa é a modelação e implementação em C (ficheiros .h e .c) de uma estrutura de dados que represente uma versão simples do conceito “animal”.
Um animal tem como características o nome (_name), a idade (_age) e o peso (_weight).
Devem ser ainda implementadas as funções newAnimal e destroyAnimal. A função newAnimal reserva memória suficiente para representar um animal e permite inicializar os seus campos (através dos argumentos da função). Por simplicidade, assume-se que o campo _name tem comprimento fixo máximo de 16 caracteres (incluindo o terminador). A função destroyAnimal liberta os recursos associados ao animal.
Outras funções a implementar:
<c> //TODO </c>
Ficheiro Animal.c: media:Animal.c <c>
struct animal {
char _name[16]; int _age; double _weight;
};
Animal newAnimal(const char *name, int age, double weight) {
//Animal animal = (Animal)malloc(sizeof(*Animal)); Animal animal = (Animal)malloc(sizeof(struct animal)); if (animal != NULL) { strcpy(animal->_name, name); animal->_age = age; animal->_weight = weight; } return animal;
}
void destroyAnimal(Animal animal) {
if (animal) { free(animal); animal = NULL; }
}
const char *getAnimalName (Animal animal) { return animal->_name; } int getAnimalAge (Animal animal) { return animal->_age; } double getAnimalWeight(Animal animal) { return animal->_weight; }
/* note that we require animal1 and animal2 to be valid animals: any of
them being NULL pointers will result in a false comparison. */
int equalsAnimal(Animal animal1, Animal animal2) {
if (animal1 == NULL || animal2 == NULL) return 0; return !strcmp(getAnimalName(animal1), getAnimalName(animal2)) && getAnimalAge(animal1) == getAnimalAge(animal2) && getAnimalWeight(animal1) == getAnimalWeight(animal2);
}
void printAnimal(Animal animal) {
printf("== Animal ==\n"); printf("Name: %s\n", getAnimalName(animal)); printf("Age: %d\n", getAnimalAge(animal)); printf("Weight: %g\n", getAnimalWeight(animal));
} </c>
<c>
</c>
A tarefa é a modelação e implementação em C (ficheiros .h e .c) de uma estrutura de dados que represente uma versão simples do conceito “gato”.
Um gato tem como características o nome (_name), a idade (_age), o peso (_weight), o volume do ronronar (_purrLevel) e o grau de suavidade do pêlo (_fluffiness).
Devem ser ainda implementadas as funções newCat e destroyCat. A função newCat reserva memória suficiente para representar um gato e permite inicializar os seus campos (através dos argumentos da função). Por simplicidade, assuma que o campo _name tem comprimento fixo máximo de 16 caracteres (incluindo o terminador). A função destroyCat liberta os recursos associados ao gato.
Outras funções a implementar:
<c> //TODO </c>
Como se pode observar acima, existe alguma repetição na definição de animal e de gato. Como o conceito de gato contém alguma informação do conceito de animal, seria conveniente a sua reutilização.
A tarefa é a modelação e implementação em C (ficheiros .h e .c) de uma estrutura de dados que represente uma versão do conceito “gato”, mas considerando-o como uma animal caracterizado pelo volume do ronronar (_purrLevel) e pelo grau de suavidade do pêlo (_fluffiness).
Tal como anteriormente, devem ser ainda implementadas as funções newCat e destroyCat. A função newCat reserva memória suficiente para representar um gato e permite inicializar os seus campos (através dos argumentos da função). Por simplicidade, assuma que o campo _name tem comprimento fixo máximo de 16 caracteres (incluindo o terminador). A função destroyCat liberta os recursos associados ao gato.
Note-se que o facto de o gato ser um animal não altera a necessidade de implementação das funções associadas ao gato.
Assim, as funções a implementar são:
<c> //TODO </c>