You are on page 1of 43

PR3 – LENGUAJE C – ARCHIVOS C.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "city.h"
#include <stdbool.h>
#include <limits.h>
#include "error.h"

// Initialize the City structure


tError city_init(tCity * city, char * name, tDate * date, long
population, int cases, int critical_cases, int deaths, int
recovered, int medical_beds) {
// Verify pre conditions
assert(city != NULL);
assert(name != NULL);
assert(date != NULL);
assert(population > 0);
assert(cases >= 0);
assert(critical_cases >= 0);
assert(deaths >= 0);
assert(recovered >= 0);
assert(medical_beds > 0);

// Allocate the memory for the string fields, using the


length of the provided text plus 1 space
//for the "end of string" char '\0'. To allocate memory we
use the malloc command.
city->name = (char*)malloc((strlen(name) + 1) *
sizeof(char));

// Allocate the memory for the last_update field. We use the


malloc command.
city->last_update = (tDate*)malloc(sizeof(tDate));

// Check that memory has been allocated for all fields.


Pointer must be different from NULL.
if (city->name == NULL || city->last_update == NULL) {
// Some of the fields have a NULL value, what means that
we found some problem allocating the memory
return ERR_MEMORY_ERROR;
}

// Copy params to City fields


strcpy(city->name, name);

city->last_update->day = date->day;
city->last_update->month = date->month;
city->last_update->year = date->year;

city->population = population;
city->cases = cases;
city->critical_cases = critical_cases;
city->deaths = deaths;
city->recovered = recovered;
city->medical_beds = medical_beds;

return OK;
}

// Free a city
void city_free(tCity * city){
assert(city != NULL);

// All memory allocated with malloc and realloc needs to be


freed using the free command. In this case, as we use malloc to
allocate the fields, we have to free them
if (city->name != NULL) {
free(city->name);
city->name = NULL;
}

if (city->last_update != NULL) {
free(city->last_update);
city->last_update = NULL;
}

bool city_equal(tCity * city1, tCity * city2){


// Verify pre conditions
assert(city1 != NULL);
assert(city2 != NULL);

// To see if two cities are equals, we need to compare only


their names

if (strcmp(city1->name, city2->name) != 0) {
// cities are different
return false;
}

return true;

// Create a list of cities


void cityList_create(tCityList *cities)
{
// Verify pre conditions
assert(cities != NULL);

cities->first = NULL;
}

// Insert a city at index position


tError cityList_insert(tCityList *cities, tCity *city, int
index)
{
tCityNode * prev;
tCityNode * newCity;
int i = 0;

// Verify pre conditions


assert(cities != NULL);
assert(city != NULL);
assert(index >= 0);

// If city exists return ERR_DUPLICATED


if (cityList_find(cities, city->name) != NULL){
return ERR_DUPLICATED;
}

// Create new city


newCity = (tCityNode*) malloc(sizeof(tCityNode));
// Check that memory has been allocated
if (newCity == NULL){
return ERR_MEMORY_ERROR;
}
else{
newCity->city = (tCity*) malloc(sizeof(tCity));
// Check that memory has been allocated
if (newCity->city == NULL)
{
free(newCity);
return ERR_MEMORY_ERROR;
}
city_init(newCity->city, city->name, city-
>last_update, city->population, city->cases,
city->critical_cases, city->deaths,
city->recovered, city->medical_beds);

if (index == 0) {
// no previous element
newCity->next = cities->first;
cities->first = newCity;
}
else{
if (index > cityList_size(cities)) {
city_free(newCity->city);
free(newCity->city);
free(newCity);
return ERR_INVALID;
}

// move prev to index -1 position


prev = cities->first;
while (i < index -1 && prev->next != NULL) {
prev = prev->next;
i++;
}

if (prev != NULL){
// standard case
newCity->next = prev->next;
prev->next = newCity;
}
else{
city_free(newCity->city);
free(newCity->city);
free(newCity);
return ERR_INVALID;
}
}
}

return OK;
}

// Delete the city at index position


bool cityList_delete(tCityList * cities, int index) {
int num_elements;
int i;
tCityNode * ptr;
tCityNode * ptr_del;

// Verify pre conditions


assert(cities != NULL);
assert(index >= 0);

// Out of range
num_elements = cityList_size(cities);
if (num_elements == 0 || index > num_elements) return false;

// Find element at index-1 position


i = 0;
ptr = cities->first;
while (i < index - 1) {
ptr = ptr->next;
i++;
}
// Now ptr points to element at index-1 position

// ptr_del points to element to be deleted


if (index == 0){
ptr_del = ptr;
cities->first = ptr_del->next;
}
else {
ptr_del = ptr->next;
}

// Element at index-1 position points to element at index+1


position
if (ptr_del != NULL){
ptr->next = ptr_del->next;
}
else {
ptr->next = NULL;
}
// Delete element
city_free(ptr_del->city);
free(ptr_del->city);
free(ptr_del);

return true;
}

// Get the city at index position


tCity * cityList_get(tCityList * cities, int index) {
int num_elements;
int i;
tCityNode * ptr;

// Verify pre conditions


assert(cities != NULL);
assert(index >= 0);

// Out of range
num_elements = cityList_size(cities);
if (num_elements == 0 || index > num_elements) return NULL;

// Find element at index position


i = 0;
ptr = cities->first;
while (i < index) {
ptr = ptr->next;
i++;
}
// Now ptr points to element at index position
if (ptr != NULL)
return ptr->city;
else return NULL;
}

// Returns true if the list is empty


bool cityList_empty(tCityList * cities) {
// Verify pre conditions
assert(cities != NULL);

if (cities->first == NULL) return true;


else return false;
}

// Find cities by name


tCity * cityList_find(tCityList * cities, char * cityName) {
int num_elements;
tCityNode * ptr;
bool findCity = false;

// Verify pre conditions


assert(cities != NULL);
assert(cityName != NULL);

// Out of range
num_elements = cityList_size(cities);
if (num_elements == 0) return NULL;

// Find element with city-name = cityName


ptr = cities->first;
while (ptr != NULL) {
if (strcmp(ptr->city->name, cityName) == 0) {
// Now ptr points to element with city-name =
cityName
findCity = true;
break;
}
ptr = ptr->next;
}

if (findCity)
return ptr->city;
else return NULL;
}

// Update the city data


tCity * cityList_update(tCityList * cities, char * cityName,
tDate * date, int cases, int critical_cases, int deaths, int
recovered) {
tCity * city;

// Verify pre conditions


assert(cities != NULL);
assert(cityName != NULL);
assert(date != NULL);
assert(cases >= 0);
assert(critical_cases >= 0);
assert(deaths >= 0);
assert(recovered >= 0);

// If City don't exists return NULL


city = cityList_find(cities, cityName);

if (city == NULL)
return NULL;

city->last_update->day = date->day;
city->last_update->month = date->month;
city->last_update->year = date->year;
city->cases += cases;
city->critical_cases += critical_cases;
city->deaths += deaths;
city->recovered += recovered;
city->population -= deaths;

return city;
}

// Delete all cities


void cityList_free(tCityList * cities) {
tCityNode * ptrCity;
tCityNode * ptrDeleteCity;

// Verify pre conditions


assert(cities != NULL);

ptrCity = cities->first;

while (ptrCity != NULL) {


ptrDeleteCity = ptrCity;
ptrCity = ptrCity->next;

city_free(ptrDeleteCity->city);
free(ptrDeleteCity->city);
free(ptrDeleteCity);

}
//free(ptr);
cities->first = NULL;
}

// Gets the number of elements in the list


int cityList_size(tCityList * cities) {
int num_elements = 0;
tCityNode * ptr;

ptr = cities->first;

while (ptr != NULL) {


num_elements++;
ptr = ptr->next;
}

return num_elements;
}

// Create a list of cities


void cityList_print(tCityList * cities) {
// Verify pre conditions
assert(cities != NULL);
int num_elements = 0;
tCityNode * ptr;
ptr = cities->first;
while (ptr != NULL) {
printf("%d %s \n ", num_elements, ptr->city->name);
printf("\tpopulation:%li medical_beds:%d
updated:%d/%d/%d \n ",
ptr->city->population,
ptr->city->medical_beds,
ptr->city->last_update->day,
ptr->city->last_update->month,
ptr->city->last_update->year);
printf("\tcases:%d critical:%d deaths:%d recovered:%d \n
", ptr->city->cases, ptr->city->critical_cases, ptr->city-
>deaths, ptr->city->recovered);
ptr = ptr->next;
num_elements++;
}
printf("\n ");
}

long cityList_populationIterative(tCityNode * ptr){


assert(ptr != NULL);
long total_population = 0;
while (ptr != NULL) {
total_population += ptr->city->population;
ptr = ptr->next;
}
return total_population;
}

long cityList_populationRecursive(tCityNode * ptr){


if (ptr == NULL){
return 0;
}
return cityList_populationRecursive(ptr->next) + ptr->city-
>population;

// Calculate recursively the total critical cases by going


through all the items on the list.
int cityList_casesRecursive(tCityNode * cityNode){
if (cityNode == NULL){
return 0;
}
return cityList_casesRecursive(cityNode->next) + cityNode-
>city->cases;

// Calculate recursively the total critical cases by going


through all the items on the list.
int cityList_criticalCasesRecursive(tCityNode * cityNode){
if (cityNode == NULL){
return 0;
}
return cityList_criticalCasesRecursive(cityNode->next) +
cityNode->city->critical_cases;

// Calculate recursively the total deaths by going through all


the items on the list.
int cityList_deathsRecursive(tCityNode * cityNode){
if (cityNode == NULL){
return 0;
}
return cityList_deathsRecursive(cityNode->next) + cityNode-
>city->deaths;
}
// Calculate recursively the total Recovered by going through
all the items on the list.
int cityList_recoveredRecursive(tCityNode * cityNode){
if (cityNode == NULL){
return 0;
}
return cityList_recoveredRecursive(cityNode->next) +
cityNode->city->recovered;

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "country.h"
#include "city.h"

// Initialize the Country structure


tError country_init(tCountry * country, char * name) {
// Verify pre conditions
assert(country != NULL);
assert(name != NULL);

// Allocate the memory for the string fields, using the


length of the provided text plus 1 space
//for the "end of string" char '\0'. To allocate memory we
use the malloc command.
country->name = (char*)malloc((strlen(name) + 1) *
sizeof(char));

// Allocate the memory for the list of cities. We use the


malloc command.
country->cities = (tCityList*)malloc(sizeof(tCityList));

// Check that memory has been allocated for all fields.


Pointer must be different from NULL.
if (country->name == NULL || country->cities == NULL) {
// Some of the fields have a NULL value, what means that
we found some problem allocating the memory
return ERR_MEMORY_ERROR;
}

// Copy params to Country fields


strcpy(country->name, name);
country->health_collapse = false;

// Create the list of cities


cityList_create(country->cities);

return OK;
}
// Copy the data of a Country to another Country
tError country_cpy(tCountry* dst, tCountry* src){
tError err;
tCityNode* ptr = NULL;
// Verify pre conditions
assert(src != NULL);

// Initialize the element with the new data


err = country_init(dst, src->name);
if (err != OK){
free(dst);
return err;
}
cityList_create(dst->cities);

ptr = src->cities->first;
while (ptr != NULL) {
err = country_addCity(dst, ptr->city);
if (err != OK){
free(dst);
return err;
}
ptr = ptr->next;
}

return OK;
}

// Add new City to Country


tError country_addCity(tCountry * country, tCity * city) {
tError error;

// Verify pre conditions


assert(country != NULL);
assert(city != NULL);

error = cityList_insert(country->cities, city,


cityList_size(country->cities));

return error;
}

bool country_equal(tCountry * country1, tCountry * country2){


// Verify pre conditions
assert(country1 != NULL);
assert(country2 != NULL);

// To see if two countries are equals, we need to compare


only their names

if (strcmp(country1->name, country2->name) != 0) {
// countries are different
return false;
}
// All fields have the same value
return true;

// Remove the memory used by tCountry structure


tError country_free(tCountry * country){
assert(country != NULL);

// All memory allocated with malloc and realloc needs to be


freed using the free command. In this case, as we use malloc to
allocate the fields, we have to free them
if (country->name != NULL) {
free(country->name);
country->name = NULL;
}

if (country->cities != NULL) {
cityList_free(country->cities);
free(country->cities);
country->cities = NULL;
}

return OK;
}

long country_totalPopulation(tCountry * country){


//return cityList_populationIterative(country->cities-
>first);
return cityList_populationRecursive(country->cities->first);

// Calculate recursively the total cases by going through all


the items on the list.
int country_totalCases(tCountry * country){
return cityList_casesRecursive(country->cities->first);
}

// Calculate recursively the total critical cases by going


through all the items on the list.
int country_totalCriticalCases(tCountry * country){
return cityList_criticalCasesRecursive(country->cities-
>first);
}

// Calculate recursively the total deaths by going through all


the items on the list.
int country_totalDeaths(tCountry * country){
return cityList_deathsRecursive(country->cities->first);
}

// Calculate recursively the total Recovered by going through


all the items on the list.
int country_totalRecovered(tCountry * country){
return cityList_recoveredRecursive(country->cities->first);
}

#include "error.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "commons.h"
#include "infection.h"
#include <stdio.h>

// Initialize the Infection structure


tError infection_init(tInfection* object, tInfectiousAgent*
infectiousAgent, tCountry* country, tDate* date){
// Verify pre conditions
assert(object != NULL);
assert(infectiousAgent != NULL);
assert(country != NULL);
assert(date != NULL);

// Allocate the memory for all the fields. To allocate


memory we use the malloc command.
object->country = (tCountry*)malloc(sizeof(tCountry));

// Allocate the memory for the date field. We use the malloc
command.
object->date = (tDate*)malloc(sizeof(tDate));

object->infectiousAgent =
(tInfectiousAgent*)malloc(sizeof(tInfectiousAgent));

// Check that memory has been allocated for all fields.


Pointer must be different from NULL.
if (object->country == NULL || object->date == NULL ||
object->infectiousAgent == NULL) {
// Some of the fields have a NULL value, what means that
we found some problem allocating the memory
return ERR_MEMORY_ERROR;
}

// Once the memory is allocated, copy the data.


country_cpy(object->country, country);

infectiousAgent_cpy(object->infectiousAgent,
infectiousAgent);

// As the field date is a struct, we need to copy all


fields.
object->date->day = date->day;
object->date->month = date->month;
object->date->year = date->year;

object->totalCases = 0;
object->totalCriticalCases = 0;
object->totalDeaths = 0;
object->totalRecovered = 0;

return OK;
}

// Remove the memory used by Infection structure


void infection_free(tInfection* object){
// Verify pre conditions
assert(object != NULL);

// All memory allocated with malloc and realloc needs to be


freed using the free command. In this case, as we use malloc to
allocate the fields, we have to free them
if (object->country != NULL) {
country_free(object->country);
free(object->country);
object->country = NULL;
}
if (object->date != NULL) {
free(object->date);
object->date = NULL;
}

if (object->infectiousAgent != NULL) {
infectiousAgent_free(object->infectiousAgent);
free(object->infectiousAgent);
object->infectiousAgent = NULL;
}

// Update cases and deaths of an Infection


void infection_update(tInfection* infection, int cases, int
deaths, int criticalCases, int recovered){
// Verify pre conditions
assert(infection != NULL);
assert(cases >= 0);
assert(deaths >= 0);
assert(criticalCases >= 0);
assert(recovered >= 0);

infection->totalCases += cases;
infection->totalDeaths += deaths;
infection->totalCriticalCases += criticalCases;
infection->totalRecovered += recovered;
}

// Update cases and deaths of an Infection rescursively


void infection_update_recursive(tInfection* infection){
assert(infection != NULL);

int totalCases = country_totalCases(infection->country);


infection->totalCases = totalCases;
infection->totalDeaths = country_totalDeaths(infection-
>country);
infection->totalCriticalCases =
country_totalCriticalCases(infection->country);
infection->totalRecovered =
country_totalRecovered(infection->country);

// Compare two infections


bool infection_equals(tInfection* infection1, tInfection*
infection2) {

// Verify pre conditions


assert(infection1 != NULL);
assert(infection2 != NULL);

// To see if two infections are equals, we need to see ALL


the values for their fields are equals.
// Strings are pointers to a table of chars, therefore,
cannot be compared as " infection1->country == infection2-
>country ". We need to use a string comparison function

if (strcmp(infection1->infectiousAgent->name, infection2-
>infectiousAgent->name) != 0) {
// infectious Agents are different
return false;
}

if (!country_equal(infection1->country, infection2-
>country)) {
// countries are different
return false;
}

// All fields have the same value


return true;
}

// Initialize the Table of infections


void infectionTable_init(tInfectionTable* table){
// Verify pre conditions
assert(table != NULL);

// The initialization of a table is to set it to the empty


state. That is, with 0 elements.
table->size = 0;
// Using dynamic memory, the pointer to the elements must be
set to NULL (no memory allocated). This is the main difference
with respect to the reservoir of static memory, were data was
allways initialized (tInfection elements[MAX_ELEMENTS])
table->elements = NULL;
}

// Remove the memory used by InfectionTable structure


void infectionTable_free(tInfectionTable* object){
// Verify pre conditions
assert(object != NULL);

// All memory allocated with malloc and realloc needs to be


freed using the free command. In this case, as we use
malloc/realloc to allocate the elements, and need to free them.
if (object->elements != NULL) {
for (int i = 0; i < object->size; i++) {
infection_free(&object->elements[i]);
}
free(object->elements);
object->elements = NULL;
// As the table is now empty, assign the size to 0.
object->size = 0;
}

// Add a new Infection to the table


tError infectionTable_add(tInfectionTable* table, tInfection*
infection){
// Verify pre conditions
assert(table != NULL);
assert(infection != NULL);

// Check if reservoirs already is on the table


if (infectionTable_find(table, infection->infectiousAgent-
>name, infection->country))
return ERR_DUPLICATED;

// The first step is to allocate the required space. There


are two methods to manage the memory (malloc and realloc).
Malloc allows to allocate a new memory block, while realloc
allows to modify an existing memory block.
if (table->size == 0) {
// Empty table

// Increase the number of elements of the table


table->size = 1;

// Since the table is empty, and we do not have any


previous memory block, we have to use malloc. The amount of
memory we need is the number of elements (will be 1) times the
size of one element, which is computed by sizeof(type). In this
case the type is tInfection.
table->elements = (tInfection*)malloc(table->size *
sizeof(tInfection));
}
else {
// table with elements

// Increase the number of elements of the table


table->size = table->size + 1;

// Since the table is not empty, we already have a


memory block. We need to modify the size of this block, using
the realloc command. The amount of memory we need is the number
of elements times the size of one element, which is computed by
sizeof(type). In this case the type is tInfection. We provide
the previous block of memory.
table->elements = (tInfection*)realloc(table->elements,
table->size * sizeof(tInfection));
}

// Check that the memory has been allocated


if (table->elements == NULL) {
// Error allocating or reallocating the memory
return ERR_MEMORY_ERROR;
}

// Once we have the block of memory, which is an array of


tInfection elements, we initialize the new element (which is the
last one). The last element is " table->elements[table->size -
1] " (we start counting at 0)
return infection_init(&(table->elements[table->size - 1]),
infection->infectiousAgent, infection->country, infection-
>date);

// Get the size of the table


unsigned int infectionTable_size(tInfectionTable* table){
// Verify pre conditions
assert(table != NULL);

// The size of the table is the number of elements. This


value is stored in the "size" field.
return table->size;
}

// Get Infection by Infection and country name


tInfection* infectionTable_find(tInfectionTable* table, const
char* infectiousAgentName, tCountry* country){
int i;

// Verify pre conditions


assert(table != NULL);
assert(infectiousAgentName != NULL);
assert(country != NULL);

// Search over the table and return once we found the


element.
for (i = 0; i<table->size; i++) {
if ((strcmp(table->elements[i].infectiousAgent->name,
infectiousAgentName) == 0)) {
if (country_equal(table->elements[i].country,
country)) {
// We return the ADDRESS (&) of the element,
which is a pointer to the element
return &(table->elements[i]);
}
}
}

// The element has not been found. Return NULL (empty


pointer).
return NULL;
}

// Compare two Table of infections


bool infectionTable_equals(tInfectionTable* infectionTable1,
tInfectionTable* infectionTable2){
// Verify pre conditions
assert(infectionTable1 != NULL);
assert(infectionTable2 != NULL);

int i;
if (infectionTable1->size != infectionTable2->size){
return false;
}

for (i = 0; i< infectionTable1->size; i++)


{
// Uses "find" because the order of reservoirs could be
different
if (!infectionTable_find(infectionTable1,
infectionTable2->elements[i].infectiousAgent->name,
infectionTable2->elements[i].country)) {
// names are different
return false;
}
}

return true;
}

// Copy the data of a Infection to another Infection


tError infection_cpy(tInfection* dst, tInfection* src){
// Verify pre conditions
//assert(dst != NULL);
assert(src != NULL);

// Free the space used by destination object.


if (dst != NULL)
infection_free(dst);

// Initialize the element with the new data


return infection_init(dst, src->infectiousAgent, src-
>country, src->date);

// Remove a Infection from the table


tError infectionTable_remove(tInfectionTable* table, tInfection*
infection){
int i;
bool found;
// Verify pre conditions
assert(table != NULL);
assert(infection != NULL);

// To remove an element of a table, we will move all


elements after this element one position, to fill the space of
the removed element.
found = false;
for (i = 0; i<table->size; i++) {
// If the element has been found. Displace this element
to the previous element (will never happend for the first one).
We use the ADDRESS of the previous element &(table->elements[i-
1]) as destination, and ADDRESS of the current element &(table-
>elements[i]) as source.
if (found) {
// Check the return code to detect memory allocation
errors
if (infection_cpy(&(table->elements[i - 1]),
&(table->elements[i])) == ERR_MEMORY_ERROR) {
// Error allocating memory. Just stop the
process and return memory error.
return ERR_MEMORY_ERROR;
}
}
else if (infection_equals(&table->elements[i],
infection)){
// The current element is the element we want to
remove. Set found flag to true to start element movement.
found = true;
}
}

// Once removed the element, we need to modify the memory


used by the table.
if (found) {
// If we are removing the last element, we will free
// the last/remaining element in table / assign pointer
// to NULL
if (table->size <= 1) {
infectionTable_free(table);
}
else {
infection_free(&table->elements[table->size - 1]);
// Modify the used memory. As we are modifying a
previously
// allocated block, we need to use the realloc
command.
table->elements = (tInfection*)realloc(table-
>elements, table->size * sizeof(tInfection));

// Check that the memory has been allocated


if (table->elements == NULL) {
// Error allocating or reallocating the memory
return ERR_MEMORY_ERROR;
}
else {
// Succesfully allocated, set new table size
table->size = table->size - 1;
}
}
}
else {
// If the element was not in the table, return an error.
return ERR_NOT_FOUND;
}

return OK;
}

// Given an infectious agent and a table of type


tinfectionTable,
// it performs a search of the country with the largest infected
population,
// offering us a pointer to it. In case of a tie, the country
that is first on the list will be returned.
// In case of not finding the infectious agent in the list, it
will return NULL.

tInfection* infectionTable_getMaxInfection(tInfectionTable*
table, const char* infectiousAgentName){
int maxCases = 0;
int maxDeaths = 0;
int i;
tInfection * infection = NULL;

for (i = 0; i<table->size; i++) {


if (strcmp(table->elements[i].infectiousAgent->name,
infectiousAgentName) == 0){
if (table->elements[i].totalCases > maxCases){
infection = &table->elements[i];
maxCases = table->elements[i].totalCases;
}
if (table->elements[i].totalCases == maxCases &&
table->elements[i].totalDeaths > maxDeaths){
infection = &table->elements[i];
maxDeaths = table->elements[i].totalDeaths;

}
}
}

return infection;

// Given an infectious agent and a tinfectionTable type table,


// calculate the mortality rate of an infectious agent
worldwide,
// adding all the deceased and dividing it by the number of
affected.

float infectionTable_getMortalityRate(tInfectionTable* table,


const char* infectiousAgentName){
int cases = 0;
int deaths = 0;
float mortalityRate = 0;
int i;

for (i = 0; i<table->size; i++) {


if (strcmp(table->elements[i].infectiousAgent->name,
infectiousAgentName) == 0){
cases += table->elements[i].totalCases;
deaths += table->elements[i].totalDeaths;

}
}

mortalityRate = (float)deaths / (float)cases;

return mortalityRate;
}
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "infectiousAgent.h"

// Initialize the infectious agent structure


tError infectiousAgent_init(tInfectiousAgent* object, char*
name, float r0, char* medium, tDate* date, char* city,
tReservoirTable* reservoirList) {
tReservoir element;

// Verify pre conditions


assert(object != NULL);
assert(name != NULL);
assert(r0 > 0);
assert(medium != NULL);
assert(date != NULL);
assert(city != NULL);
assert(reservoirList != NULL);

// Allocate the memory for all the string fields, using the
length of the provided text plus 1 space for the "end of string"
char '\0'.
// To allocate memory we use the malloc command.
object->name = (char*)malloc((strlen(name) + 1) *
sizeof(char));
object->medium = (char*)malloc((strlen(medium) + 1) *
sizeof(char));
object->city = (char *)malloc((strlen(city) + 1) *
sizeof(char));
// Check that memory has been allocated for all fields.
Pointer must be different from NULL.
if (object->name == NULL || object->medium == NULL ||
object->city == NULL) {
// Some of the string fields have a NULL value, what
means that we found some problem allocating the memory
return ERR_MEMORY_ERROR;
}

// Allocate the memory for the date field. We use the malloc
command.
object->date = (tDate*)malloc(sizeof(tDate));

// Check that memory has been allocated.


if (object->date == NULL) {
// We found some problem allocating the memory
return ERR_MEMORY_ERROR;
}

// Allocate the memory for the reservoir list field. We use


the malloc command.
// First we need to allocate the memory for the
tReservoirTable and init the strucutre.
// After this, we copy all the elements.
object->reservoirList =
(tReservoirTable*)malloc(sizeof(tReservoirTable));
//object->reservoirList->elements = (tReservoir*)
malloc(reservoirList->size * sizeof(tReservoir));
reservoirTable_init(object->reservoirList);

for (int i = 0; i < reservoirList->size; i++) {


reservoir_init(&element, reservoirList-
>elements[i].name, reservoirList->elements[i].species);
reservoirTable_add(object->reservoirList, &element);
reservoir_free(&element);
}

// Check that memory has been allocated.


if (object->reservoirList == NULL) { //|| object-
>reservoirList->elements == NULL) {
// We found some problem allocating the memory
return ERR_MEMORY_ERROR;
}

// Once the memory is allocated, copy the data.

// As the fields are strings, we need to use the string copy


function strcpy.
strcpy(object->name, name);
strcpy(object->medium, medium);
strcpy(object->city, city);

// As the field date is a struct, we need to copy all


fields.
object->date->day = date->day;
object->date->month = date->month;
object->date->year = date->year;

// Create all the elements of the reservoir list.


/*
object->reservoirList->size = reservoirList->size;
for(int i; i < reservoirList->size; i++) {
initReservoirError = reservoir_init(&object->reservoirList-
>elements[i],
reservoirList->elements[i].name,
reservoirList->elements[i].species);
if(initReservoirError != OK) {
return initReservoirError;
}
}
*/
// Copy the basic reproductive rate R0 data
object->r0 = r0;

return OK;
}

// Remove the memory used by infectious agent structure


void infectiousAgent_free(tInfectiousAgent* object) {

// Verify pre conditions


assert(object != NULL);

// All memory allocated with malloc and realloc needs to be


freed using the free command.
// In this case, as we use malloc to allocate the fields, we
have to free them

object->r0 = 0;

if (object->name != NULL) {
free(object->name);
object->name = NULL;
}

if (object->medium != NULL) {
free(object->medium);
object->medium = NULL;
}

if (object->date != NULL) {
free(object->date);
object->date = NULL;
}

if (object->city != NULL) {
free(object->city);
object->city = NULL;
}

if (object->reservoirList != NULL) {
reservoirTable_free(object->reservoirList);
free(object->reservoirList);
object->reservoirList = NULL;
}

// Get the reservoirs list of an infectious agent


tReservoirTable* infectiousAgent_getReservoirs(tInfectiousAgent*
object) {
// Verify pre conditions
assert(object != NULL);

return object->reservoirList;
}

// Compare two infectious agent


bool infectiousAgent_equals(tInfectiousAgent* infectiousAgent1,
tInfectiousAgent* infectiousAgent2) {

// Verify pre conditions


assert(infectiousAgent1 != NULL);
assert(infectiousAgent2 != NULL);

// To see if two infectious agents are equals, we need to


see ALL the values for their fields are equals.
// Strings are pointers to a table of chars, therefore,
cannot be compared as "infectiousAgent1->name ==
infectiousAgent2->name".
// We need to use a string comparison function.

if (strcmp(infectiousAgent1->name, infectiousAgent2->name)
!= 0) {
// names are different
return false;
}

if (infectiousAgent1->r0 != infectiousAgent2->r0) {
// basic reproductive ratio r0 are different
return false;
}

if (strcmp(infectiousAgent1->medium, infectiousAgent2-
>medium) != 0) {
// transmission medium
return false;
}

if (infectiousAgent1->date->day != infectiousAgent2->date-
>day ||
infectiousAgent1->date->month != infectiousAgent2->date-
>month ||
infectiousAgent1->date->year != infectiousAgent2->date-
>year) {
// date of first infection
return false;
}

if (strcmp(infectiousAgent1->city, infectiousAgent2->city)
!= 0) {
// city of first infection
return false;
}

if (!reservoirTable_equals(infectiousAgent1->reservoirList,
infectiousAgent2->reservoirList)) {
// infectious agent reservoir list
return false;
}

return true;
}

// Copy the data of a infectious agent to another infectious


agent
tError infectiousAgent_cpy(tInfectiousAgent* dest,
tInfectiousAgent* src) {
// Verify pre conditions
assert(dest != NULL);
assert(src != NULL);

// Initialize the element with the new data


infectiousAgent_init(dest, src->name, src->r0, src->medium,
src->date, src->city, src->reservoirList);

return OK;
}

// Initialize the Table of infectious agents


void infectiousAgentTable_init(tInfectiousAgentTable* table) {
// Verify pre conditions
assert(table != NULL);

// The initialization of a table is to set it to the empty


state. That is, with 0 elements.
table->size = 0;
// Using dynamic memory, the pointer to the elements must be
set to NULL (no memory allocated).
// This is the main difference with respect to the
infectious agents of static memory, were data was allways
initialized (tInfectiousAgent elements[MAX_ELEMENTS])
table->elements = NULL;
}

// Remove the memory used by infectious agent table structure


void infectiousAgentTable_free(tInfectiousAgentTable* object) {
// Verify pre conditions
assert(object != NULL);
// All memory allocated with malloc and realloc needs to be
freed using the free command.
// In this case, as we use malloc/realloc to allocate the
elements, and need to free them.
if (object->elements != NULL) {
for (int i = 0; i < object->size; i++) {
infectiousAgent_free(&object->elements[i]);
}
free(object->elements);
object->elements = NULL;
// As the table is now empty, assign the size to 0.
object->size = 0;
}

// Add a new infectious agent to the table


tError infectiousAgentTable_add(tInfectiousAgentTable* table,
tInfectiousAgent* infectiousAgent) {
// Verify pre conditions
assert(table != NULL);
assert(infectiousAgent != NULL);

// Check if reservoirs already is on the table


if (infectiousAgentTable_find(table, infectiousAgent->name))
return ERR_DUPLICATED;

// The first step is to allocate the required space. There


are two methods to manage the memory (malloc and realloc).
// Malloc allows to allocate a new memory block, while
realloc allows to modify an existing memory block.
if (table->size == 0) {
// Empty table

// Increase the number of elements of the table


table->size = 1;

// Since the table is empty, and we do not have any


previous memory block, we have to use malloc.
// The amount of memory we need is the number of
elements (will be 1) times the size of one element,
// which is computed by sizeof(type). In this case the
type is tInfectiousAgent.
table->elements = (tInfectiousAgent*)malloc(table->size
* sizeof(tInfectiousAgent));
}
else {
// table with elements

// Increase the number of elements of the table


table->size = table->size + 1;

// Since the table is not empty, we already have a


memory block. We need to modify the size of this block,
// using the realloc command. The amount of memory we
need is the number of elements times the size of one element,
// which is computed by sizeof(type). In this case the
type is tInfectiousAgent. We provide the previous block of
memory.
table->elements = (tInfectiousAgent*)realloc(table-
>elements, table->size * sizeof(tInfectiousAgent));
}

// Check that the memory has been allocated


if (table->elements == NULL) {
// Error allocating or reallocating the memory
return ERR_MEMORY_ERROR;
}

// Once we have the block of memory, which is an array of


tInfectiousAgent elements, we initialize the new element (which
is the last one).
// The last element is " table->elements[table->size - 1] "
(we start counting at 0)
infectiousAgent_init(&(table->elements[table->size - 1]),
infectiousAgent->name, infectiousAgent->r0,
infectiousAgent->medium, infectiousAgent->date,
infectiousAgent->city, infectiousAgent->reservoirList);

return OK;
}

// Remove a infectious agent from the table


tError infectiousAgentTable_remove(tInfectiousAgentTable* table,
tInfectiousAgent* infectiousAgent) {
bool found;

// Verify pre conditions


assert(table != NULL);
assert(infectiousAgent != NULL);

// To remove an element of a table, we will move all


elements after this element one position,
// to fill the space of the removed element.
found = false;
for (int i = 0; i<table->size; i++) {
// If the element has been found. Displace this element
to the previous element
// (will never happend for the first one). We use the
ADDRESS of the previous element &(table->elements[i-1])
// as destination, and ADDRESS of the current element
&(table->elements[i]) as source.
if (found) {
// Check the return code to detect memory allocation
errors
if (infectiousAgent_cpy(&(table->elements[i - 1]),
&(table->elements[i])) == ERR_MEMORY_ERROR) {
// Error allocating memory. Just stop the
process and return memory error.
return ERR_MEMORY_ERROR;
}

}
else if (strcmp(table->elements[i].name,
infectiousAgent->name) == 0) {
// The current element is the element we want to
remove. Set found flag to true to start element movement.
found = true;
}
}

// Once removed the element, we need to modify the memory


used by the table.
if (found) {
// If we are removing the last element, we will free
// the last/remaining element in table / assign pointer
// to NULL
if (table->size <= 1) {
infectiousAgentTable_free(table);
}
else {
infectiousAgent_free(&table->elements[table->size -
1]);
// Modify the used memory. As we are modifying a
previously
// allocated block, we need to use the realloc
command.
table->elements = (tInfectiousAgent*)realloc(table-
>elements, table->size * sizeof(tInfectiousAgent));

// Check that the memory has been allocated


if (table->elements == NULL) {
// Error allocating or reallocating the memory
return ERR_MEMORY_ERROR;
}
else {
// Succesfully allocated, set new table size
table->size = table->size - 1;
}
}
}
else {
// If the element was not in the table, return an error.
return ERR_NOT_FOUND;
}

return OK;

// Get infectious agent by infectious agent name


tInfectiousAgent*
infectiousAgentTable_find(tInfectiousAgentTable* table, const
char* infectiousAgentName) {
int i;
// Verify pre conditions
assert(table != NULL);
assert(infectiousAgentName != NULL);

// Search over the table and return once we found the


element.
for (i = 0; i<table->size; i++) {
if (strcmp(table->elements[i].name, infectiousAgentName)
== 0) {
// We return the ADDRESS (&) of the element, which
is a pointer to the element
return &(table->elements[i]);
}
}

// The element has not been found. Return NULL (empty


pointer).
return NULL;
}

// Get the size of the table


unsigned int infectiousAgentTable_size(tInfectiousAgentTable*
table) {
// Verify pre conditions
assert(table != NULL);

return table->size;
}

void infectiousAgentTable_print(tInfectiousAgentTable * table) {


// Verify pre conditions
assert(table != NULL);

for (int i = 0; i< table->size; i++) {


printf("%s %s \n ", table->elements[i].name, table-
>elements[i].city);

}
printf("\n ");
}

#include <stdbool.h>
#include <stdio.h>
#include <limits.h>
#include <assert.h>
#include <stdlib.h>
#include "research.h"
#include "infection.h"
#include "country.h"
#include "commons.h"
#include "error.h"

// Creates a research element out of a country and a stats


tError research_init(tResearch* object, tCountry* country) {
// PR3_EX1
tInfectionStats ifs = { 0, 0, 0};

assert (object != NULL);

// Allocate the memory for all the fields. To allocate


memory we use the malloc command.
object->country = (tCountry*)malloc(sizeof(tCountry));

if (object->country == NULL) {
// Some of the fields have a NULL value, what means that
we found some problem allocating the memory
return ERR_MEMORY_ERROR;
}

// Once the memory is allocated, copy the data.


country_cpy(object->country, country);

ifs.Infectivity = country_totalCases(object->country);
ifs.Severity = country_totalCriticalCases(object->country);
ifs.Lethality = country_totalDeaths(object->country);

object->stats = ifs;

return OK;
}

// Releases data pointed by research element


void research_free(tResearch* object) {
// PR3_EX1
assert (object != NULL);

if (object->country != NULL) {
country_free(object->country);
free(object->country);
object->country = NULL;
}

// Compare stats of two countries, 1 if s1 wins, -1 if s2 wins,


0 if tie
int research_compare(tInfectionStats s1, tInfectionStats s2) {
// PR3_EX1
if (s1.Infectivity == s2.Infectivity) {
if (s1.Severity == s2.Severity) {
if (s1.Lethality == s2.Lethality) {
return 0;
}
else if (s1.Lethality > s2.Lethality) {
return 1;
}
else return -1;
} else if (s1.Severity > s2.Severity) {
return 1;
} else return -1;
} else if (s1.Infectivity > s2.Infectivity) {
return 1;
} else return -1;
}

// Create the research list


void researchList_create(tResearchList* list) {
// PR3_EX2
// Check preconditions
assert(list != NULL);

// Assign pointers to NULL


list->first = NULL;
list->last = NULL;
list->size = 0;
}

// Insert/adds a new research to the research list

tError researchList_insert(tResearchList* list, tResearch*


research, int index) {
// PR3_EX2

// Check preconditions
assert(list != NULL);
assert(index > 0);

tResearchListNode *tmp;
tResearchListNode *prev; // Stores the node allocated on
index-1

// Out of range
if (index > list->size+1)
return ERR_INVALID_INDEX;

// Create new ResearchListNode


tmp = (tResearchListNode*)
malloc(sizeof(tResearchListNode));

if (tmp == NULL) {
return ERR_MEMORY_ERROR;
} else {
// Create new research
tmp->e = (tResearch*) malloc(sizeof(tResearch));
if (tmp->e == NULL)
{
free(tmp);
return ERR_MEMORY_ERROR;
}
research_init(tmp->e, research->country);

if (index == 1) {
// add to first position
tmp->next = list->first;
tmp->prev = NULL;

// Update first position of the list


if (list->first != NULL) {
list->first->prev = tmp;
}

list->first = tmp;
} else {
// Goes in between. Gets current node from position
index-1, that will we "prev" from new node
prev = researchList_get(list, index-1);
if (prev != NULL) {
// Fill "prev" and "next" from new node
tmp->prev = prev;
tmp->next = prev->next; // Could be null if
index==size

// New node goes in position index


prev->next = tmp;
if (tmp->next != NULL)
tmp->next->prev = tmp;
}
else {
research_free(tmp->e);
free(tmp->e);
free(tmp);
return ERR_INVALID_INDEX;

}
}

// Update size of list


list->size++;

// Update last position


if (index == list->size) {
list->last = tmp;
}

return OK;
}
}

// Deletes a research from the research list


tError researchList_delete(tResearchList* list, int index) {
// PR3_EX2

// Check preconditions
assert(list != NULL);
assert(index > 0);

tResearchListNode *tmp;
tResearchListNode *prev;

if (index == 1) {
// Deletes first position
tmp = list->first;
if (tmp == NULL) {
return ERR_EMPTY_LIST;
} else {
// Updates first position
list->first = tmp->next;

// Updates prev after deleting first position


if (tmp->next != NULL) {
tmp->next->prev = NULL;
}
}
} else {
prev = researchList_get(list, index - 1);
if (!(prev == NULL)) {
// standard case, deletes node from between
tmp = prev->next;
if (tmp == NULL) {
return ERR_INVALID_INDEX;
} else {
// Updates list after deleting a node
prev->next = tmp->next;
if (tmp->next != NULL) {
tmp->next->prev = tmp;
}
}
} else {
return ERR_INVALID_INDEX;
}
}

// Update size of list


list->size--;

// Update last position


if (list->size > 0) {
list->last = researchList_get(list, list->size);
} else {
list->last = NULL;
}

// Free memory
research_free(tmp->e);
free(tmp->e);
free(tmp);

return OK;
}

// Gets research from given position, NULL if out of bounds


tResearchListNode* researchList_get(tResearchList* list, int
index) {
// PR3_EX2

// Check preconditions
assert(list != NULL);
assert(index > 0);

int i;
tResearchListNode *prev;

// Loop until find index position


i = 1;
prev = list->first;
while (i < index && (prev != NULL)) {
prev = prev->next;
i++;
}

return prev;
}

// Gets true if list is empty


bool researchList_empty(tResearchList* list) {
// PR3_EX2
// Check preconditions
assert(list != NULL);
if(list->first == NULL){
return true;
}
return false;
}

// Remove all data for a research list


void researchList_free(tResearchList* list) {
// PR3_EX2
// Check preconditions
assert(list != NULL);

int i;

// Delete all elements from the list. Start in last position


for optimization
for (i = list->size; i > 0; i--) {
researchList_delete(list, i);
}

list->first = NULL;
list->last = NULL;
}

// given a list of country' research, returns the position of


the country in the list
int researchList_getPosByCountryRecursive(tResearchListNode*
first, tCountry *country, int pos) {
// PR3_EX3

// Check preconditions
if (first == NULL) return -1;
if (country_equal(first->e->country, country)){
return pos;
}

return researchList_getPosByCountryRecursive(first->next,
country, ++pos);

// given a list of country' research, returns the position of


the country in the list
int researchList_getPosByCountry(tResearchList* list, tCountry
*country) {
// PR3_EX3

// Check preconditions
assert(list != NULL);

tResearchListNode *prev = NULL;


int position;

prev = list->first;
// check if is an empty list

if (researchList_empty(list)) {
position = -1;
}
else{
// recursive until find country position
position =
researchList_getPosByCountryRecursive(prev,country,1);
}

return position;
}

// Swap two elements in the list


tError researchList_swap(tResearchList* list, int index_dst, int
index_src) {
// PR3_EX3

assert (list != NULL);

tError err;
tResearch research_src, research_dst;
tResearchListNode * researchNode_src, * researchNode_dst;

// get source node, store its elem / don't delete (do not
modify list len)
researchNode_src = researchList_get(list, index_src);
research_init(&research_src,researchNode_src->e->country);
//e_src = pNode_src->e;
// get dest node, store / don't delete (do not modify list
len)
researchNode_dst = researchList_get(list, index_dst);
research_init(&research_dst,researchNode_dst->e->country);
//e_dst = pNode_dst->e;

// now delete src_node


err = researchList_delete(list, index_src);
if (err == OK) {
// And put destination elem in source pos

err = researchList_insert(list, &research_dst,


index_src);
if (err ==OK) {
// Now delete dest pos, insert source elem in
its pos
err = researchList_delete(list, index_dst);
if (err ==OK) {
err = researchList_insert(list,
&research_src, index_dst);

}
}
}

research_free(&research_src);
research_free(&research_dst);

return err;
}

// Sorts input list using bubbleSort algorithm


tError researchList_bubbleSort(tResearchList *list) {
// PR3_EX3

assert (list != NULL);

int i, j;
tError err;
tResearchListNode *j_node, *jj_node;

for(i = 0; i < list->size - 1; i++) {

for (j = 0; j < list->size - i - 1; j++) {

// Get two nodes to compare


j_node = researchList_get(list, j + 1);
jj_node = researchList_get(list, j + 2);

if (research_compare(j_node->e->stats, jj_node->e-
>stats) == -1) {

err = researchList_swap(list, j + 1, j + 2);


if (err != OK) {
return err; // Broken list
}

}
}

return OK;
}

// Helper function, print list contents


void researchList_print(tResearchList list) {
tResearchListNode *pLNode;

printf("===== List Contents:\n\n");

for (int i = 0; i < list.size; i++) {


pLNode = researchList_get(&list, i+1);
printf("\tElemPos: %d:\tInfectivity: %d;\tSeverity:
%d;\tLethality: %d;\tCountry_Name: \"%s\"\n",
i+1,
pLNode->e->stats.Infectivity,
pLNode->e->stats.Severity,
pLNode->e->stats.Lethality,
pLNode->e->country->name
);

printf("\n===== End Of List: %d elems\n", list.size);


}

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "reservoir.h"
#include <stdio.h>

// Initialize the reservoir structure


tError reservoir_init(tReservoir* object, const char* name,
const char* species) {

// Verify pre conditions


assert(object != NULL);
assert(name != NULL);
assert(species != NULL);

// Allocate the memory for all the fields, using the length
of the provided text plus 1 space for the "end of string" char
'\0'. To allocate memory we use the malloc command.
object->name = (char*)malloc((strlen(name) + 1) *
sizeof(char));
object->species = (char*)malloc((strlen(species) + 1) *
sizeof(char));

// Check that memory has been allocated for all fields.


Pointer must be different from NULL.
if (object->name == NULL || object->species == NULL) {
// Some of the fields have a NULL value, what means that
we found some problem allocating the memory
return ERR_MEMORY_ERROR;
}

// Once the memory is allocated, copy the data. As the


fields are strings, we need to use the string copy function
strcpy.
strcpy(object->name, name);
strcpy(object->species, species);

return OK;
}

// Remove the memory used by reservoir structure


void reservoir_free(tReservoir* object) {

// Verify pre conditions


assert(object != NULL);

// All memory allocated with malloc and realloc needs to be


freed using the free command. In this case, as we use malloc to
allocate the fields, we have to free them
if (object->name != NULL) {
free(object->name);
object->name = NULL;
}
if (object->species != NULL) {
free(object->species);
object->species = NULL;
}
}

// Compare two reservoirs


bool reservoir_equals(tReservoir* reservoir1, tReservoir*
reservoir2) {

// Verify pre conditions


assert(reservoir1 != NULL);
assert(reservoir2 != NULL);

// To see if two reservoirs are equals, we need to see ALL


the values for their fields are equals.
// Strings are pointers to a table of chars, therefore,
cannot be compared as " reservoir1->reservoirname ==
reservoir2->reservoirname ". We need to use a string comparison
function

if (strcmp(reservoir1->name, reservoir2->name) != 0) {
// names are different
return false;
}

if (strcmp(reservoir1->species, reservoir2->species) != 0) {
// species are different
return false;
}

// All fields have the same value


return true;
}

// Compare two Table of reservoirs. There are equals if they


have the same number of reservoir, they have the same
reservoirname. The order of reservoirs of two tables could be
different
bool reservoirTable_equals(tReservoirTable* reservoirTable1,
tReservoirTable* reservoirTable2){
// Verify pre conditions
assert(reservoirTable1 != NULL);
assert(reservoirTable2 != NULL);

int i;
if (reservoirTable1->size != reservoirTable2->size){
return false;
}

for (i = 0; i< reservoirTable1->size; i++)


{
// Uses "find" because the order of reservoirs could be
different
if (!reservoirTable_find(reservoirTable1,
reservoirTable2->elements[i].name)) {
// names are different
return false;
}
}

return true;
}

// Copy the data of a reservoir to another reservoir


tError reservoir_cpy(tReservoir* dst, tReservoir* src) {

// Verify pre conditions


assert(dst != NULL);
assert(src != NULL);

// Free the space used by destination object. An initialized


object is assumed.
reservoir_free(dst);

// Initialize the element with the new data


reservoir_init(dst, src->name, src->species);

return OK;
}

// Initialize the table of reservoirs


void reservoirTable_init(tReservoirTable* table) {
// Verify pre conditions
assert(table != NULL);

// The initialization of a table is to set it to the empty


state. That is, with 0 elements.
table->size = 0;
// Using dynamic memory, the pointer to the elements must be
set to NULL (no memory allocated). This is the main difference
with respect to the reservoir of static memory, were data was
allways initialized (tReservoir elements[MAX_ELEMENTS])
table->elements = NULL;
}

// Remove the memory used by reservoirTable structure


void reservoirTable_free(tReservoirTable* object) {
// Verify pre conditions
assert(object != NULL);
tReservoir * ptr;
// All memory allocated with malloc and realloc needs to be
freed using the free command. In this case, as we use
malloc/realloc to allocate the elements, and need to free them.
if (object->elements != NULL) {
for (int i = 0; i < object->size; i++) {
ptr = &object->elements[i];
reservoir_free(ptr);
}
free(object->elements);
object->elements = NULL;

}
// As the table is now empty, assign the size to 0.
object->size = 0;
}

// Add a new reservoir to the table


tError reservoirTable_add(tReservoirTable* table, tReservoir*
reservoir) {
// Verify pre conditions
assert(table != NULL);
assert(reservoir != NULL);

// Check if reservoirs already is on the table


if (reservoirTable_find(table, reservoir->name))
return ERR_DUPLICATED;

// The first step is to allocate the required space. There


are two methods to manage the memory (malloc and realloc).
Malloc allows to allocate a new memory block, while realloc
allows to modify an existing memory block.
if (table->size == 0) {
// Empty table
// Increase the number of elements of the table
table->size = 1;

// Since the table is empty, and we do not have any


previous memory block, we have to use malloc. The amount of
memory we need is the number of elements (will be 1) times the
size of one element, which is computed by sizeof(type). In this
case the type is tReservoir.
table->elements = (tReservoir*)malloc(table->size *
sizeof(tReservoir));
}
else {
// table with elements

// Increase the number of elements of the table


table->size = table->size + 1;

// Since the table is not empty, we already have a


memory block. We need to modify the size of this block, using
the realloc command. The amount of memory we need is the number
of elements times the size of one element, which is computed by
sizeof(type). In this case the type is tReservoir. We provide
the previous block of memory.
table->elements = (tReservoir*)realloc(table->elements,
table->size * sizeof(tReservoir));
}

// Check that the memory has been allocated


if (table->elements == NULL) {
// Error allocating or reallocating the memory
return ERR_MEMORY_ERROR;
}

// Once we have the block of memory, which is an array of


tReservoir elements, we initialize the new element (which is the
last one). The last element is " table->elements[table->size -
1] " (we start counting at 0)
reservoir_init(&(table->elements[table->size - 1]),
reservoir->name, reservoir->species);

return OK;
}

// Remove a reservoir from the table


tError reservoirTable_remove(tReservoirTable * table, tReservoir
* reservoir) {
int i;
bool found;

// Verify pre conditions


assert(table != NULL);
assert(reservoir != NULL);

// To remove an element of a table, we will move all


elements after this element one position, to fill the space of
the removed element.
found = false;
for (i = 0; i < table->size; i++) {
// If the element has been found. Displace this element
to the previous element (will never happend for the first one).
We use the ADDRESS of the previous element &(table->elements[i-
1]) as destination, and ADDRESS of the current element &(table-
>elements[i]) as source.
if (found) {
// Check the return code to detect memory allocation
errors
if (reservoir_cpy(&(table->elements[i - 1]),
&(table->elements[i])) == ERR_MEMORY_ERROR) {
// Error allocating memory. Just stop the
process and return memory error.
return ERR_MEMORY_ERROR;
}

}
else if (strcmp(table->elements[i].name, reservoir-
>name) == 0) {
// The current element is the element we want to
remove. Set found flag to true to start element movement.
found = true;
}
}

// Once removed the element, we need to modify the memory


used by the table.
if (found) {
// If we are removing the last element, we will free
// the last/remaining element in table / assign pointer
// to NULL
if (table->size <= 1) {
reservoirTable_free(table);
}
else {
reservoir_free(&table->elements[table->size - 1]);
// Modify the used memory. As we are modifying a
previously
// allocated block, we need to use the realloc
command.
table->elements = (tReservoir*)realloc(table-
>elements, table->size * sizeof(tReservoir));

// Check that the memory has been allocated


if (table->elements == NULL) {
// Error allocating or reallocating the memory
return ERR_MEMORY_ERROR;
}
else {
// Succesfully allocated, set new table size
table->size = table->size - 1;
}
}
}
else {
// If the element was not in the table, return an error.
return ERR_NOT_FOUND;
}

return OK;

// Get reservoir by reservoirname


tReservoir* reservoirTable_find(tReservoirTable* table, const
char* name) {
int i;

// Verify pre conditions


assert(table != NULL);
assert(name != NULL);

// Search over the table and return once we found the


element.
for (i = 0; i<table->size; i++) {
if (strcmp(table->elements[i].name, name) == 0) {
// We return the ADDRESS (&) of the element, which
is a pointer to the element
return &(table->elements[i]);
}
}

// The element has not been found. Return NULL (empty


pointer).
return NULL;
}

// Get the size of a the table


unsigned int reservoirTable_size(tReservoirTable* table) {
// Verify pre conditions
assert(table != NULL);

// The size of the table is the number of elements. This


value is stored in the "size" field.
return table->size;
}

void reservoirTable_print(tReservoirTable * table) {


// Verify pre conditions
assert(table != NULL);

for (int i = 0; i< table->size; i++) {


printf("%s %s \n ", table->elements[i].name, table-
>elements[i].species);

}
printf("\n ");
}

You might also like