5.4 : A List Example

Let us look at another example of file modularization of a program. Consider the program of Section 3.6.1 that reads in, creates, and prints the information fields of each record on a list of stock records. That version is in a single file and is functionally modularized. The data abstraction list, with its operations next, setlink, setinfo, avail, getnextrecord, printrecord, and anotherrecord, appear together.

The version of the program that follows uses a module for the list data abstraction with the header file, list.h, and the operations file, list.c. The file, list.c, and the program file, listexample.c, are compiled separately.

The file list.h:

The File list.h

/* header for list */

#define MAXSIZE 5

#define NULL 0

#define SENTINEL -1

typedef struct

{

int month;

int day;

int year;

}date;

typedef struct

{

char name[MAXSIZE];

int shares;

float value;

date datebought;

}infofield;

typedef struct listrecord

{

infofield info;

struct listrecord *link;

}stockrecord,*listpointer;

extern listpointer next(/* listpointer */);

/* Returns a copy of listpointer in link field of

record pointed to by listpointer */

extern listpointer setnull();

/* Returns a null listpointer value */

extern setlink(/* listpointer_1,listpointer_2 */);

/* Sets the link field of the record pointed to

by listpointer_1 to the value of

listpointer_2

*/

extern setinfo(/* listpointer_1,listpointer_2 */);

/* Sets the info field of the record pointed to

by listpointer_1 to the contents of the

info field of the record pointed to by

listpointer_2

*/

extern listpointer avail();

/* Returns a pointer to storage for

a record of type struct stockrecord */

extern listpointer getnextrecord();

/* Returns a pointer to a record

containing the next input records'

information, or a null pointer if

the next input is the sentinel

*/

extern printrecord(/* listpointer */);

/* Prints the information in the record

pointed to by listpointer */

extern anotherrecord(/* listpointer */);

/* Returns true if there are no

more records and false otherwise */

The File list.c

/* operations allowed on a list */

>Comment

#include "list.h"

listpointer next(pointer)

/* Returns a copy of the

link field in the record

pointed to by pointer

*/

listpointer pointer;

{

return (pointer->link);

}

listpointer setnull()

/* Returns a null pointer */

{

return(NULL);

}

setlink(pointer1,pointer2)

/* Sets the link field of the

record pointed to by pointer1

to the contents of pointer2

*/

listpointer pointer1, pointer2;

{

pointer1->link = pointer2;

}

setinfo(pointer1,pointer2)

/* Sets the infofield of the record

pointed to by pointer1 to the

infofield of the record

pointed to by pointer2

*/

listpointer pointer1,pointer2;

{

int i;

for (i=0;i<MAXSIZE;i++)

pointer1->info.name[i] = pointer2->info.name[i];

pointer1->info.shares = pointer2->info.shares;

pointer1->info.value = pointer2->info.value;

pointer1->info.datebought.month = pointer2->info.datebought.

month;

pointer1->info.datebought.day = pointer2->info.datebought.day;

pointer1->info.datebought.year = pointer2->info.datebought.year;

}

listpointer avail()

*/ Returns a pointer to storage

allocated for a record of type

stockrecord

*/

{

listpointer malloc();

return(malloc(sizeof(stockrecord)));

}

anotherrecord(recordpointer)

/* Returns true if there is

another record

*/

listpointer recordpointer;

{

listpointer setnull();

return(recordpointer != setnull());

}

listpointer getnextrecord()

/* Inputs the data for the new

record and returns a pointer

to a record containing the data

in its infofield, or, if there

are no new records, returns

a null pointer

*/

{

listpointer setnull();

static stockrecord nextrecord;

printf(" Enter number of shares \n");

scanf("%d",&(nextrecord.info.shares));

if(nextrecord.info.shares != SENTINEL)

{

printf(" Enter the stock name - less than %d characters\n",

MAXSIZE);

scanf("%s",nextrecord.info.name);

printf(" Enter the price of one share of the stock \n");

scanf("%f",&(nextrecord.info.value));

printf(" Enter the month day year of the stock purchase

\n");

scanf("%d %d %d",&(nextrecord.info.datebought.month),

&(nextrecord.info.datebought.day),

&(nextrecord.info.datebought.year));

return(&nextrecord);

}

else

return(setnull());

}

printrecord(recordpointer)

/* Prints the contents of the infofield

of the record pointed to by recordpointer

*/

listpointer recordpointer;

{

printf(" The stock is %s \n",recordpointer->info.name);

print(" The number of shares is %d \n",recordpointer->info.

shares);

printf(" The value of a share is %f\n",recordpointer->info.

value);

printf(" The date of purchase is %d %d %d\n\n",

recordpointer->info.datebought.month,

recordpointer->info.datebought.day, recordpointer->

info.datebought.year);

}

Finally, here is the program file to create a list and print its contents. It treats the list as a data abstraction and uses file modularization for the data abstraction.

The File listexample.c

>Comment

#include "list.h"

>Comment

#include <stdio.h>

#define TRUE 1

#define FALSE 0

main()

/* Inputs a series of stockrecords,

creates a list of the records, and

prints the contents of each list

record's infofield

*/

{

listpointer stocks,recordpointer,next();

int done;

>Comment

initialize(&stocks);

recordpointer = stocks;

done = FALSE;

while(!done&&anotherrecord(recordpointer))

{

>Comment

addrecord(&stocks,recordpointer,&done);

recordpointer = next(recordpointer);

}

>Comment

recordpointer=stocks;

while (anotherrecord(recordpointer))

{

>Comment

printrecord(recordpointer);

recordpointer = next(recordpointer);

}

}

initialize(plistname)

/* Allocates storage for the first record

and sets listname to point to it

*/

listpointer *plistname;

{

listpointer avail();

*plistname = avail();

}

addrecord(plistname,recordpointer,pdone)

/* Fills in the current record's data, and

allocates storage for the next record and

adds it to the list. If there is no data for

the current record it sets the link field of

the last list record to null, or the list

head, to null, and done to true.

*/

listpointer *plistname,recordpointer;

int *pdone;

{

static listpointer predecessor;

listpointer setnull(),avail(),

getnextrecord(),pointer;

pointer = getnextrecord();

if (pointer != setnull())

{

>Comment

setinfo(recordpointer,pointer);

setlink(recordpointer,avail());

predecessor = recordpointer;

}

else if (*plistname != recordpointer)

{

>Comment

setlink(predecessor,setnull());

*pdone = TRUE;

}

else

{

>Comment

*plistname = setnull();

*pdone = TRUE;

}

}

The files list.h and list.c now embody the list data abstraction. Note that, should the format of the list change, these changes must be reflected in the header file and also in the operations file. In the later file, list.c, the changes would be localized to setinfo, getnextrecord, and printrecord. Instead, were the format to remain the same but the records stored in an array of records rather than the dynamic memory, more extensive changes would be required in both lists.h and list.c.