(→Programa exemplo) |
(→Gato simples) |
||
Line 130: | Line 130: | ||
* função printCat que, quando aplicada a um gato, apresenta os seus dados (use printf para apresentar cada campo do gato) | * função printCat que, quando aplicada a um gato, apresenta os seus dados (use printf para apresentar cada campo do gato) | ||
* 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 "Cat" === | ||
+ | |||
+ | Ficheiro '''Cat.h''': | ||
<c> | <c> | ||
− | + | #ifndef __CAT_H__ | |
+ | #define __CAT_H__ | ||
+ | |||
+ | typedef struct cat *Cat; | ||
+ | |||
+ | Cat newCat(const char *name, int age, double weight, int purrLevel, | ||
+ | double fluffiness); | ||
+ | void destroyCat(Cat cat); | ||
+ | |||
+ | int equalsCat(Cat cat1, Cat cat2); | ||
+ | const char *getCatName(Cat cat); | ||
+ | int getCatAge(Cat cat); | ||
+ | double getCatWeight(Cat cat); | ||
+ | int getCatPurrLevel(Cat cat); | ||
+ | double getCatFluffiness(Cat cat); | ||
+ | void printCat(Cat cat); | ||
+ | |||
+ | #endif | ||
</c> | </c> | ||
+ | |||
+ | === Implementation do conceito "Cat" === | ||
+ | |||
+ | Notar a repetição de muitas definições (relativamente a Animal). | ||
+ | |||
+ | Ficheiro '''Cat.c''': | ||
+ | |||
+ | <c> | ||
+ | #include <string.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <stdio.h> | ||
+ | #include "Cat.h" | ||
+ | |||
+ | struct cat { | ||
+ | char _name[16]; | ||
+ | int _age; | ||
+ | double _weight; | ||
+ | int _purrLevel; | ||
+ | double _fluffiness; | ||
+ | }; | ||
+ | |||
+ | Cat newCat(const char *name, int age, double weight, int purrLevel, | ||
+ | double fluffiness) { | ||
+ | Cat cat = (Cat)malloc(sizeof(struct cat)); | ||
+ | if (cat != NULL) { | ||
+ | strcpy(cat->_name, name); | ||
+ | cat->_age = age; | ||
+ | cat->_weight = weight; | ||
+ | cat->_purrLevel = purrLevel; | ||
+ | cat->_fluffiness = fluffiness; | ||
+ | } | ||
+ | return cat; | ||
+ | } | ||
+ | |||
+ | void destroyCat(Cat cat) { | ||
+ | if (cat) { | ||
+ | free(cat); | ||
+ | cat = NULL; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | const char *getCatName (Cat cat) { return cat->_name; } | ||
+ | int getCatAge (Cat cat) { return cat->_age; } | ||
+ | double getCatWeight (Cat cat) { return cat->_weight; } | ||
+ | int getCatPurrLevel (Cat cat) { return cat->_purrLevel; } | ||
+ | double getCatFluffiness(Cat cat) { return cat->_fluffiness; } | ||
+ | |||
+ | /* note that we require cat1 and cat2 to be valid cats: any of | ||
+ | them being NULL pointers will result in a false comparison. */ | ||
+ | int equalsCat(Cat cat1, Cat cat2) { | ||
+ | if (cat1 == NULL || cat2 == NULL) return 0; | ||
+ | return !strcmp(getCatName(cat1), getCatName(cat2)) && | ||
+ | getCatAge(cat1) == getCatAge(cat2) && | ||
+ | getCatWeight(cat1) == getCatWeight(cat2) && | ||
+ | getCatPurrLevel(cat1) == getCatPurrLevel(cat2) && | ||
+ | getCatFluffiness(cat1) == getCatFluffiness(cat2); | ||
+ | } | ||
+ | |||
+ | void printCat(Cat cat) { | ||
+ | printf("== Cat ==\n"); | ||
+ | printf("Name: %s\n", getCatName(cat)); | ||
+ | printf("Age: %d\n", getCatAge(cat)); | ||
+ | printf("Weight: %g\n", getCatWeight(cat)); | ||
+ | printf("Purr level: %d\n", getCatPurrLevel(cat)); | ||
+ | printf("Fluffiness: %g\n", getCatFluffiness(cat)); | ||
+ | } | ||
+ | </c> | ||
+ | |||
+ | === Programa exemplo === | ||
+ | |||
+ | Ficheiro '''main.c''': | ||
+ | |||
+ | <c> | ||
+ | #include <stdio.h> | ||
+ | #include "Cat.h" | ||
+ | |||
+ | int main() { | ||
+ | Cat c1 = newCat("Tareco", 12, 3.4, 3, 3.1); | ||
+ | Cat c2 = newCat("Pantufa", 1, 12.3, 2, 2.7); | ||
+ | |||
+ | printCat(c1); | ||
+ | printCat(c2); | ||
+ | |||
+ | printf("c1==c1? %s\n", equalsCat(c1, c1) ? "yes" : "no"); | ||
+ | printf("c1==c2? %s\n", equalsCat(c1, c2) ? "yes" : "no"); | ||
+ | |||
+ | destroyCat(c1); | ||
+ | destroyCat(c2); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </c> | ||
+ | |||
+ | === Saída do programa === | ||
+ | |||
+ | <text> | ||
+ | == Cat == | ||
+ | Name: Tareco | ||
+ | Age: 12 | ||
+ | Weight: 3.4 | ||
+ | Purr level: 3 | ||
+ | Fluffiness: 3.1 | ||
+ | == Cat == | ||
+ | Name: Pantufa | ||
+ | Age: 1 | ||
+ | Weight: 12.3 | ||
+ | Purr level: 2 | ||
+ | Fluffiness: 2.7 | ||
+ | c1==c1? yes | ||
+ | c1==c2? no | ||
+ | </text> | ||
== Gato menos simples == | == Gato menos simples == |
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:
Ficheiro Animal.h: <c>
// this typedef is used to hide the concept's implementation details typedef struct animal *Animal;
Animal newAnimal(const char *name, int age, double weight); void destroyAnimal(Animal animal);
int equalsAnimal(Animal animal1, Animal animal2); const char *getAnimalName(Animal animal); int getAnimalAge(Animal animal); double getAnimalWeight(Animal animal); void printAnimal(Animal animal);
</c>
Ficheiro 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(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>
Ficheiro main.c: <c>
int main() {
Animal a1 = newAnimal("Tareco", 12, 3.4); // could be a cat... Animal a2 = newAnimal("Piloto", 1, 12.3); // is it a dog??
printAnimal(a1); printAnimal(a2);
printf("a1==a1? %s\n", equalsAnimal(a1, a1) ? "yes" : "no"); printf("a1==a2? %s\n", equalsAnimal(a1, a2) ? "yes" : "no");
destroyAnimal(a1); destroyAnimal(a2);
return 0;
} </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:
Ficheiro Cat.h:
<c>
typedef struct cat *Cat;
Cat newCat(const char *name, int age, double weight, int purrLevel,
double fluffiness);
void destroyCat(Cat cat);
int equalsCat(Cat cat1, Cat cat2); const char *getCatName(Cat cat); int getCatAge(Cat cat); double getCatWeight(Cat cat); int getCatPurrLevel(Cat cat); double getCatFluffiness(Cat cat); void printCat(Cat cat);
</c>
Notar a repetição de muitas definições (relativamente a Animal).
Ficheiro Cat.c:
<c>
struct cat {
char _name[16]; int _age; double _weight; int _purrLevel; double _fluffiness;
};
Cat newCat(const char *name, int age, double weight, int purrLevel,
double fluffiness) { Cat cat = (Cat)malloc(sizeof(struct cat)); if (cat != NULL) { strcpy(cat->_name, name); cat->_age = age; cat->_weight = weight; cat->_purrLevel = purrLevel; cat->_fluffiness = fluffiness; } return cat;
}
void destroyCat(Cat cat) {
if (cat) { free(cat); cat = NULL; }
}
const char *getCatName (Cat cat) { return cat->_name; } int getCatAge (Cat cat) { return cat->_age; } double getCatWeight (Cat cat) { return cat->_weight; } int getCatPurrLevel (Cat cat) { return cat->_purrLevel; } double getCatFluffiness(Cat cat) { return cat->_fluffiness; }
/* note that we require cat1 and cat2 to be valid cats: any of
them being NULL pointers will result in a false comparison. */
int equalsCat(Cat cat1, Cat cat2) {
if (cat1 == NULL || cat2 == NULL) return 0; return !strcmp(getCatName(cat1), getCatName(cat2)) && getCatAge(cat1) == getCatAge(cat2) && getCatWeight(cat1) == getCatWeight(cat2) && getCatPurrLevel(cat1) == getCatPurrLevel(cat2) && getCatFluffiness(cat1) == getCatFluffiness(cat2);
}
void printCat(Cat cat) {
printf("== Cat ==\n"); printf("Name: %s\n", getCatName(cat)); printf("Age: %d\n", getCatAge(cat)); printf("Weight: %g\n", getCatWeight(cat)); printf("Purr level: %d\n", getCatPurrLevel(cat)); printf("Fluffiness: %g\n", getCatFluffiness(cat));
} </c>
Ficheiro main.c:
<c>
int main() {
Cat c1 = newCat("Tareco", 12, 3.4, 3, 3.1); Cat c2 = newCat("Pantufa", 1, 12.3, 2, 2.7);
printCat(c1); printCat(c2);
printf("c1==c1? %s\n", equalsCat(c1, c1) ? "yes" : "no"); printf("c1==c2? %s\n", equalsCat(c1, c2) ? "yes" : "no");
destroyCat(c1); destroyCat(c2);
return 0;
} </c>
<text>
Name: Tareco Age: 12 Weight: 3.4 Purr level: 3 Fluffiness: 3.1
Name: Pantufa Age: 1 Weight: 12.3 Purr level: 2 Fluffiness: 2.7 c1==c1? yes c1==c2? no </text>
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>