• No se han encontrado resultados

Relationships between R and SD–RH with a 1-day lag

In document 271Jorge Alonso Carné (página 112-128)

IMPLICATIONS FOR EVALUATING THE HABITAT OF TICKS

5.2 Materials and methods

5.3.3 Relationships between R and SD–RH with a 1-day lag

To illustrate some of the ideas discussed in this section, a vector object will be created that can be used with other source les. It stores and manipulates a vector of typedouble. The

Vectorstructure is similar to a 1 dimensional array to typedouble, except that it remembers its own length, and also a set of initialisation, destroying and manipulation functions are also provided.

16.5.1 Example:

Vector.h

/* Header file for a double Vector library

*/

#ifndef VECTOR_H

#define VECTOR_H

#include <stdio.h> /* necessary for FILE* */

/* declare Vector structure */

typedef struct Vector {

int length /* store vector's length */

double *parr /* pointer to a 1-d array */

} Vector

Vector Vec_init_filename(char *name) /* create from file name */

void Vec_destroy(Vector *pvec) /* destroy memory */

void Vec_print(Vector vec) /* print to screen */

Vector Vec_add(Vector v1, Vector v2)

Vector Vec_subtract(Vector v1, Vector v2)

double in_prod(Vector v1, Vector v2)

#endif

16.5.2 Examination of

Vector.h

The most important issue to decide when the header le was created was whether the structure or a pointer to the structure was going to be used to initialise and access information. The structure is small so the copying overhead associated with passing the structure will not be too signicant, but the structure contains a pointer to a 1-D array of typedouble, so it may be better to force the user to pass across pointers. In the end, I decided to design theVector library based on passing structures because it is more natural to code, but if running speed was critical, a set of alternative functions based on pointers could be designed. This is left as an exercise.

Two interface functions are provided that ensure that variable of typeVectoris initialised and destroyed correctly, and three basic operations are coded: adding and subtracting two vectors and taking two vectors' inner product. In addition, a small function has been written which prints the elements contained in the vector to the screen. This is very useful during

the early stages of code development, as it can be used to check that all the other functions are working correctly.

When you are designing a library of routines such as this, it is essential that you give your structure and its functions meaningful names, otherwise they may clash with functions dened in other libraries.

16.5.3 Example:

Vector.c

#include "Vector.h" /* include interface definitions */

#include <assert.h> /* assert() function used in source code */

Vector Vec_init_memory(int len) /* function internal to this file */

/* Initialise a vector from a file with supplied filename

*/

Vector Vec_init_filename(char *name) {

int len

FILE *read

Vector vec = {0, NULL} /* assign default values */

read = fopen(name, "r") /* open file */

assert(read != NULL)

fscanf(read, "%d", &len) /* read in vector's size */

vec = Vec_init_memory(len)

/* read init values from file */

for (i = 0 i < vec.length i++) fscanf(read, "%lf", &vec.parri])

fclose(read)

/* return copy of vec */

return vec

}

/* Set up memory for a vector of length len

*/

Vector Vec_init_memory(int len) {

int i

Vector vec = {0, NULL}

assert(len >= 0) /* set length */

vec.length = len

/* allocate memory */

vec.parr = (double *) malloc(vec.length*sizeof(double))

assert(vec.parr != NULL)

/* initialise memory */

for (i = 0 i < vec.length i++)

vec.parri] = 0.0

return vec

}

/* Free the memory associated with vec

*/

void Vec_destroy(Vector *pvec) {

if (pvec->length == 0 && pvec->parr == NULL) return

else {

free(pvec->parr)

pvec->length = 0 /* once deleted, set default values */

pvec->parr = NULL

}

return

}

/* Print the length of the vector and the

* individual elements to the screen.

*/

void Vec_print(Vector vec) {

int i

printf("length of vector = %d\n", vec.length)

for (i = 0 i < vec.length i++)

printf("v%d] = %f\n", i, vec.parri])

return

}

/* Add two vectors together

*/

Vector add_Vec(Vector v1, Vector v2) {

int i

Vector vec

assert(v1.length == v2.length)

/* initialise memory for vec */

vec = Vec_init_memory(v1.length)

for (i = 0 i < vec.length i++)

vec.parri] = v1.parri]+v2.parri]

return vec

}

/* Subtract v2 from v1 (where v1 & v2 are vectors)

*/

Vector subtract_Vec(Vector v1, Vector v2) {

int i

Vector vec

assert(v1.length == v2.length)

vec = Vec_init_memory(v1.length)

for (i = 0 i < vec.length i++)

vec.parri] = v1.parri]-v2.parri]

return vec

}

/* Calculate the inner product of two vectors

*/

double in_prod(Vector v1, Vector v2) {

int i

double result = 0.0

/* check vectors are same length */

assert(v1.length == v2.length)

for (i = 0 i < v1.length i++) result += v1.parri]*v2.parri]

return result

}

16.5.4 Examination of

Vector.c

A substantial amount of work is involved with providing a set of exible interface functions, and this should be obvious from this example. This construction provides a fairly natural interface for the library user, except that after each call to Vec_add()orVec_subtract(), the memory must be explicitly deallocated with a call to Vec_destroy() before the same variable can be reused. This will now be illustrated.

Note

that the function Vec_init_memory() has been declared at the top of the source

le, rather than in the header le. This means that it can be called from within the source

le Vector.c, but other source les are not able to access it when the header le Vector.h is included. (Strictly speaking, we should preceed its declaration by the keyword static, because other les can still access it using the externkeyword.)

16.5.5 Example:

main()

#include <stdlib.h>

#include "Vector.h" /* include interface definitions */

int main() {

Vector vec1 = {0, NULL} /* default values */

Vector vec2 = {0, NULL}

Vector vec3 = {0, NULL}

/* initialise vec1 and vec2 */

vec1 = Vec_init_filename("vector1.txt")

vec2 = Vec_init_filename("vector2.txt")

/* add two vectors */

vec3 = Vec_add(vec1, vec2)

Vec_destroy(&vec3) /* reset memory for v3 */

vec3 = Vec_subtract(vec1, vec2) /* v1-v2 */

Vec_destroy(&vec1) /* clear memory at */

Vec_destroy(&vec2) /* end of program */

Vec_destroy(&vec3)

return EXIT_SUCCESS

}

16.6 Summary

 The struct keyword allows programmers to create user-dened data types which can hide unnecessary data complexity from the user of a software library.

 Structures are generally declared globally (in a header le, for instance) which allows variables of that type to be instantiated in other les if necessary.

 For a variable, the member of a structure is accessed using the .operator, whereas for a pointer to a structure, the member is accessed using the ->operator.

 A structure can be copied can assigned to another variable, and this can be extremely useful as a function may return a structure which contains several variables. Similarly, passing a structure (or a pointer to a structure) to a function can vastly simplify the argument list.

 Memory for structures can be allocated and deallocated using malloc() and free(), as the sizeofoperator can also be used for user-dened structures.

 A software library usually consists of one or more structures (data type) and a set of functions which act as an interface (creating, modifying, destroying) for these struc-tures. The structures and functions should be declared in the header le and dened in the source le.

In document 271Jorge Alonso Carné (página 112-128)