Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Advanced C 1992

.pdf
Скачиваний:
96
Добавлен:
17.08.2013
Размер:
4.28 Mб
Скачать

Part II • Managing Data in C

memory, usually with a linked list. In this situation, it may (or may not) be that the links are simply arranged in the order that the memory blocks are allocated. When a memory block is freed, it is removed from the linked list.

The example program in this section allocates memory blocks for each record that the user enters. These blocks are pointed to by links.

Disk-Based Lists

When you create a linked list as a disk-based file, the list’s members must be the same size. If your program has different sized members of a single linked list, the best solution is to use a single union to create a single record of the correct size. The size of the union is determined by its largest member, so the members will be the same size.

Double Linked Lists

In a double linked list, each member has a pointer not only to its successor in the list, but also to its predecessor. Figure 10.4 shows how a double linked list is created. Notice that the pointer to the end of the list is mandatory. This pointer is necessary so that the end of the list can be accessed.

Figure 10.4. A double linked list.

346

Data Management: Sorts, Lists, and Indexes

C C C

 

10C

 

C C C

 

C C

Figure 10.5 shows the structure’s list pointers. (Figure 10.5 and Figure 10.4 are the basis for Figures 10.6 through 10.9.)

Figure 10.5. The CUSTOMER structure’s linked list pointers.

You can perform a trick with a double linked list. When you add a member to a double linked list, the program can examine the key fields of the first and last members to determine whether the list should be traveled from the beginning or the end. This increases the program’s performance. (It doesn’t make sense to start at the first member if the new member will be added near the end of the list.)

Listing 10.4, the LINKLIST.C program, demonstrates the use of a double linked list with dynamically allocated members. The program is simple, without much optimization. The program always has sorted access to the items in the list.

Listing 10.4. LINKLIST.C.

/* LINKLIST, written 1992 by Peter D. Hipson

*A double linked list program. This program has

*better error checking than the CDB program.

*To improve the program, make the ZIP code field a

*character field. A character field is better for ZIP

*codes because many non-US ZIP codes also

*contain letters.

*/

continues

347

Part II • Managing Data in C

Listing 10.4. continued

#include <string.h> #include <ctype.h> #include <stdio.h> #include <process.h> #include <stdlib.h>

#define

TRUE

 

1

 

#define

FALSE

 

(!TRUE)

#define

INCREMENT_AMOUNT

1

/* Add one record at a time */

#define

CUSTOMER_RECORD

1

 

#define

SUPPLIER_RECORD

2

 

/* Define the structure for the customer database. */

struct

_CUSTNAME;

 

 

typedef

struct

_CUSTNAME {

 

 

int

nRecordType;

//

1 == Customer record.

struct _CUSTNAME *NextCustomer; // Link to next, or NULL if none

struct _CUSTNAME *PrevCustomer; // Link to previous, or NULL if none

char

szName[61];

//

60 chars for name; 1 for null at end

char

szAddr1[61];

//

60 chars for address; 1 for null at end

char

szAddr2[61];

//

60 chars for address; 1 for null at end

char

szCity[26];

//

25 chars for city; 1 for null at end

char

szState[3];

//

2-character state abbrev. plus null

int

lZip;

//

Print as %5.5ld for leading 0

int

nRecordNumber;

//

Which record number?

double dSalesTotal;

// Amount the customer has purchased

} CUSTNAME;

 

 

 

typedef

CUSTNAME

near *NPCUSTNAME;

typedef

CUSTNAME

*PCUSTNAME;

 

void

GiveHelp(void);

 

 

void

main()

 

 

 

348

Data Management: Sorts, Lists, and Indexes

{

FILE *DataFile;

PCUSTNAME

FirstCustomer = NULL;

PCUSTNAME

LastCustomer = NULL;

PCUSTNAME

Customer = NULL;

PCUSTNAME

TempCustomer = NULL;

char

szFileName[257];

char

szBuffer[257];

int

nNotDone = TRUE;

int

nRecord = 0;

int

nDebug = FALSE;

int

nNeedSaving = FALSE;

C C C

C10C C

C C C

double

dSales = 0.0; /* Forces loading of floating-point support */

printf(“Please enter customer save file name: “);

gets(szFileName);

DataFile = fopen(szFileName, “wt”);

if (DataFile == NULL)

{/* Test for file open. If the file can’t be opened, exit with message. */

printf(“ERROR: File ‘%s’ couldn’t be opened.\n”, szFileName);

exit(4);

}

fclose(DataFile);

printf(“Demo of a linked list concepts\n” “\n”

“ Commands are:\n”

A

-

Add a customer/supplier record.\n”

D

-

Display current list.\n”

X

-

Exit from program.\n”

continues

349

Part II • Managing Data in C

Listing 10.4. continued

Z

-

Toggle debug mode.\n”

?

- Display the command list.”

H

- Display the command list.”

S

-

Save the list.\n”

“\n”

 

 

 

);

 

 

 

nRecord = 0;

while (nNotDone)

{

printf(“Enter command (A, D+, D-, S)?”);

gets(szBuffer);

switch(szBuffer[0])

{

case ‘H’: /* Give some help */ case ‘h’:

case ‘?’:

GiveHelp();

break;

case ‘A’: /* Add a record */ case ‘a’:

Customer = (PCUSTNAME)calloc(sizeof(CUSTNAME),

INCREMENT_AMOUNT);

printf(“Enter name %d: “, ++nRecord); gets(szBuffer);

szBuffer[sizeof(Customer->szName) - 1] = ‘\0’; strcpy(Customer->szName, szBuffer);

if (strlen(Customer->szName) > 0)

{/* Insert this record in the list, sorted by name. */ nNeedSaving = TRUE;

350

Data Management: Sorts, Lists, and Indexes

if (FirstCustomer == NULL)

{

printf(“It is first record \n”); Customer->NextCustomer = NULL; Customer->PrevCustomer = NULL;

FirstCustomer = Customer;

LastCustomer = Customer; TempCustomer = NULL;

}

else

{

TempCustomer = FirstCustomer;

}

while (TempCustomer)

{

if (nDebug)

{

C C C

C10C C

C C C

printf(“TESTING FOR ADD: ‘%s’ ‘%s’\n”, Customer->szName, TempCustomer->szName);

}

if (strcmp(Customer->szName, TempCustomer->szName) < 0 || TempCustomer == LastCustomer)

{

if (strcmp(Customer->szName, TempCustomer->szName) < 0 && TempCustomer == FirstCustomer)

{

if (nDebug)

{

printf(“Assigning as first\n”);

}

Customer->NextCustomer = FirstCustomer;

FirstCustomer = Customer;

Customer->PrevCustomer = NULL;

continues

351

Part II • Managing Data in C

Listing 10.4. continued

TempCustomer = Customer->NextCustomer; TempCustomer->PrevCustomer = Customer;

}

else

{

if (strcmp(Customer->szName, TempCustomer->szName) > 0 && TempCustomer == LastCustomer)

{

if (nDebug)

{

printf(“Assigning as last\n”);

}

Customer->PrevCustomer = LastCustomer; LastCustomer = Customer;

Customer->NextCustomer = NULL; TempCustomer = Customer- >PrevCustomer; TempCustomer->NextCustomer = Customer;

}

else

{

if (nDebug)

{

printf(“Assigning inside \ list\n”);

}

Customer->PrevCustomer =

TempCustomer->PrevCustomer;

Customer->NextCustomer =

TempCustomer;

TempCustomer->PrevCustomer =

Customer;

TempCustomer = Customer-

>PrevCustomer;

TempCustomer->NextCustomer =

Customer;

352

Data Management: Sorts, Lists, and Indexes

C C C

 

10C

 

C C C

}

C C

 

}

 

TempCustomer = NULL;

 

}

else

{

TempCustomer = TempCustomer->NextCustomer;

}

}

Customer->nRecordNumber = nRecord;

if (!nDebug)

{

do

{

printf(“Enter 1 for customer, 2 for supplier \ “);

gets(szBuffer);

sscanf(szBuffer, “%d”, &Customer ->nRecordType);

}

while (Customer->nRecordType != CUSTOMER_RECORD

&&

Customer->nRecordType != SUPPLIER_RECORD);

printf(“Enter address line 1: “); gets(szBuffer); szBuffer[sizeof(Customer->szAddr1) - 1] = ‘\0’; strcpy(Customer->szAddr1, szBuffer);

printf(“Enter address line 2: “); gets(szBuffer); szBuffer[sizeof(Customer->szAddr2) - 1] = ‘\0’; strcpy(Customer->szAddr2, szBuffer);

printf(“Enter City: “); gets(szBuffer);

szBuffer[sizeof(Customer->szCity) - 1] = ‘\0’; strcpy(Customer->szCity, szBuffer);

continues

353

Part II • Managing Data in C

Listing 10.4. continued

printf(“Enter state postal abbreviation: “); gets(szBuffer); szBuffer[sizeof(Customer->szState) - 1] = ‘\0’; strcpy(Customer->szState, szBuffer);

printf(“Enter ZIP code: “); gets(szBuffer);

sscanf(szBuffer, “%ld”, &Customer->lZip);

printf(“Enter total sales: “); gets(szBuffer);

sscanf(szBuffer, “%f”, &Customer->dSalesTotal);

}

}

else

{

printf(“\aSorry, name must not be blank!\n”);

}

break;

case ‘Z’: /* Debug mode toggle */ case ‘z’:

nDebug = !nDebug; break;

case ‘D’: /* Display all records */ case ‘d’:

TempCustomer = FirstCustomer;

printf(“Display customers\n”);

while (TempCustomer)

{

if (nDebug)

{

printf(

“Name ‘%10s’ Me %lp Next %lp Prev %lp\n”, TempCustomer->szName,

TempCustomer,

354

Data Management: Sorts, Lists, and Indexes

TempCustomer->NextCustomer,

TempCustomer->PrevCustomer);

}

else

{

printf(

“Name ‘%10s’ City ‘%10s’ State ‘%2s’ “ “ZIP ‘%5.5ld’\n”, TempCustomer->szName, TempCustomer->szCity, TempCustomer->szState, TempCustomer->lZip);

}

TempCustomer = TempCustomer->NextCustomer;

}

break;

case ‘X’: /* Exit; prompt for save if needed */ case ‘x’:

nNotDone = FALSE;

szBuffer[0] = ‘\0’;

while (nNeedSaving && szBuffer[0] == ‘\0’)

{

printf(“\nSave the data? (y|n)”);

gets(szBuffer);

if (szBuffer[0] == ‘n’ || szBuffer[0] == ‘N’)

{

nNeedSaving = FALSE;

}

else

{

if (szBuffer[0] != ‘y’ && szBuffer[0] != ‘Y’)

{

C C C

C10C C

C C C

continues

355