ANÁLISIS DE LAS OBRAS REPRESENTATIVAS DE SOLEDAD CÓRDOVA
3.10. ANÁLISIS DEL ÁLBUM ILUSTRADO INFANTIL: Paloma Blanca
In Section 9.5, we examined an expandable array that grows on demand as new elements are added to it. The code presented was modular and flexible, but has two major limitations. First, it permits a program to have only one vector object and, second, the vector may only contain items of type int. Using structures andtypedef, we can overcome these two problems, allowing us to create any number of vectors, and use the same code to produce vectors of different types.
The header filevector.hfor the expandable vector is shown below. It is similar to the original code, but includes atypedef ValueTypefor the contained type and astruct Vectordefining the format of the vector type. By simply changing line 4 to
typedef char ValueType;
the vector can be made to contain elements of typechar, and similarly for other types. The structure Vectorgroups together the three essential variables to represent a vector object: its size, capacity, and a pointer to the allocated array itself.
It is important to realise that becauseVectorobjects are manipulated exclusively by the asso-ciated functions declared in lines 13 to 25, the user does not actually need to know how theVector type is composed.4 All that the client needs to understand is what task each function in the public interface performs. Access to the Vector internals is managed by functions like get_element()
4In Section 14.2.1, we show how to hide the composition ofVectorby making it anopaquetype, which enforces correct use.
andget_size(), etc. Because of this decoupling, the internal make up ofstruct Vector may be changed and, similarly, the function algorithms may be changed, all without affecting client code.
1 /* Vector: an expandable vector type that contains elements of type ValueType.
2 */
3
4 typedef doubleValueType; 5
6 typedef struct{
7 ValueType*data;/* pointer to vector elements */
8 int size; /* current size of vector */
9 int capacity; /* current reserved memory for vector */
10 }Vector; 11
12 /* Vector creation and destruction. */
13 Vector create vector(intcapacity);
14 voidrelease vector(Vector*v);
15
16 /* Vector access operations. */
17 intpush back(Vector*v,ValueType item);
18 ValueType pop back(Vector*v);
19 ValueType* get element(Vector*v,int index);
20
21 /* Manual resizing operations. */
22 intget size(Vector*v);
23 intset size(Vector*v,int size);
24 intget capacity(Vector*v);
25 intset capacity(Vector*v,intsize);
The operations performed by the public interface are essentially the same as for the original vector implementation. Two new functions
Vector create_vector(int capacity);
void release_vector(Vector *v);
are used to initialise the internal data of a vector object and to release the data of a vector object, respectively. Having created a vector object, it may be passed to the other functions (via a pointer) to perform various operations.
The implementation of the expandable vector involves only minor modifications from the original implementation. All references toint-type elements have been changed to ValueType, and opera-tions are carried out using a pointer to a vector object. The code of source filevector.cis shown below.
1 #include"vector.h"
2 #include<stdlib.h>
3 #include<assert.h>
4
5 staticconstintStartSize= 5; /* initial vector capacity */
6 staticconstfloatGrowthRate= 1.6f; /* geometric growth of vector capacity */
7
8 Vector create vector(intcapacity)
9 /* Initialise a vector with the specified capacity. */
10 {
11 Vector v; 12 v.size= 0;
13 v.data= (ValueType*)malloc(capacity*sizeof(ValueType));
14 v.capacity= (v.data==NULL) ? 0 :capacity; 15 returnv;
16 } 17
18 voidrelease vector(Vector*v)
19 /* Release memory owned by vector. */
20 {
21 free(v−>data);
22 v−>size= 0;
23 v−>capacity= 0;
24 } 25
26 intpush back(Vector*v,ValueType item)
27 /* Add element to back of vector. Return index of new element if successful, and -1 if fails. */
28 {
29 /* If out-of-space, allocate more. */
30 if (v−>size==v−>capacity){
31 int newsize= (v−>capacity== 0) ?StartSize: (int)(v−>capacity*GrowthRate + 1.0);
32 ValueType*p= (ValueType*)realloc(v−>data,newsize*sizeof(ValueType));
33 if (p==NULL)
34 return−1;
35
36 v−>capacity =newsize;/* allocate succeeds, update data-structure */
37 v−>data=p;
38 }
39
40 /* We have enough room. */
41 v−>data[v−>size] =item; 42 returnv−>size++;
43 } 44
45 ValueType pop back(Vector*v)
46 /* Return element from back of vector, and remove it from the vector. */
47 {
48 assert(v−>size>0);
49 returnv−>data[−−v−>size];
50 } 51
52 ValueType* get element(Vector*v,int index)
53 /* Return pointer to the element at the specified index. */
54 {
55 assert(index>= 0 &&index<v−>size);
56 returnv−>data+index; 57 }
58
59 /* Manual size operations. */
60 intget size(Vector*v){ returnv−>size;}
61 intget capacity(Vector*v){ returnv−>capacity;} 62
63 intset size(Vector*v,int size)
64 /* Set vector size. Return 0 if successful, -1 if fails. */
65 {
66 if (size>v−>capacity){
67 ValueType*p= (ValueType*)realloc(v−>data,size*sizeof(ValueType));
68 if (p==NULL)
69 return−1;
70
71 v−>capacity =size;/* allocate succeeds, update data-structure */
72 v−>data=p;
73 }
74
75 v−>size=size; 76 return0;
77 } 78
79 intset capacity(Vector*v,intsize)
80 /* Shrink or grow allocated memory reserve for array.
81 * A size of 0 deletes the array. Return 0 if successful, -1 if fails. */
82 {
83 if (size!=v−>capacity){
84 ValueType*p= (ValueType*)realloc(v−>data,size*sizeof(ValueType));
85 if (p==NULL&&size>0)
86 return−1;
87
88 v−>capacity =size; 89 v−>data=p;
90 }
91
92 if (size<v−>size) 93 v−>size=size; 94 return0;
95 }
The result of this code is an expandable vector library that can create and operate on any number of vector objects. These vectors can contain elements of typeValueTypewhich is specified at compile time.
The code has an object-oriented style, where a high-level data type is defined using a structure (Vector), and operations on the structure are performed exclusively by a set of associated functions.
The client is shielded from the data representation and algorithmic details; these aspects may be changed without affecting client code. The synergy of structures, functions and file-modularity permits highly modular and flexible code design.
This code still has one limitation remaining. Vectors can be made to contain elements of different types, but not at the same time. In a given program, all vectors must contain the same type. This limitation can be overcome using the facility of the generic object pointervoid*. We return to the topic of generic programming in Chapter 14.