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

Advanced C 1992

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

Part II • Managing Data in C

A better solution is to take the offsetof() of the first member to write and the offsetof() of the member just after the last member to write. Subtract one from the other, and you have the number of bytes to save. As you can see, this method is quick and easy.

Pointers to Structures

A pointer to a structure is handled in the same way as a pointer to any other data type, except the syntax of the structure pointer operator differs. You can have a pointer to a structure, and use the pointer to access any member in the structure.

When calling functions that have structures as parameters, it is more efficient to pass a pointer to a structure rather than pass the entire structure. See Listing 7.8, STRUPTR.C.

Listing 7.8. STRUPTR.C.

/*

STRUPTR,

written 1992 by Peter D. Hipson

*

Pointers

and structures

*/

 

 

#include <stdio.h> // Make includes first part of file #include <string.h> // For string functions

#define MAX_SIZE 35

int main(void); // Define main(), and the fact that this program doesn’t // use any passed parameters.

int main()

{

int i;

typedef struct

{

char *szSaying[MAX_SIZE];

216

C Structures

int

nLength[MAX_SIZE];

} SAYING;

 

typedef struct

{

SAYING Murphy;

SAYING Peter; } OURSAYING;

OURSAYING OurSaying = {{

“Firestone’s Law of Forecasting:”,

Chicken Little has to be right only once.”, “”, “”,

“Manly’s Maxim:”,

Logic is a systematic method of coming to”,

the wrong conclusion with confidence.”,

“”,

“”,

“Moer’s truism:”,

The trouble with most jobs is the job holder’s”,

resemblance to being one of a sled dog team. No one”,

C C C

C7C C

C C C

gets a change of scenery except the lead dog.”, “”, “”,

“Cannon’s Comment:”,

If you tell the boss you were late for work because you”,

had a flat tire, the next morning you will have a flat tire.”, NULL /* Flag to mark the last saying */

}, {

“David’s rule:”,

Software should be as easy to use as a Coke machine.”,

“”,

“”,

“Peter’s Maxim:”,

To be successful, you must work hard, but”,

Hard work doesn’t guarantee success.”,

“”,

“”,

“Teacher’s truism:”,

continues

217

Part II • Managing Data in C

Listing 7.8. continued

Successful people learn.”, “”, “”,

“Player’s Comment:”,

If you don’t play to win,”,

you don’t win.”,

NULL /* Flag to mark the last saying */ }};

OURSAYING * pOurSaying;

 

SAYING

* pSaying;

 

pOurSaying = &OurSaying;

 

pSaying

= &OurSaying.Peter;

 

printf(

 

 

 

“sizeof(OURSAYING)

= %d\n”

 

“sizeof(OurSaying)

= %d\n”

 

“sizeof(SAYING)

= %d\n”

 

“sizeof(pOurSaying->Murphy)

= %d\n”

 

“sizeof(pOurSaying->Peter)

= %d\n”

 

“sizeof(pSaying)

= %d\n”

 

“sizeof(*(pSaying))

= %d\n”,

 

sizeof(OURSAYING),

 

 

sizeof(OurSaying),

 

 

sizeof(SAYING),

 

 

sizeof(pOurSaying->Murphy),

 

 

sizeof(pOurSaying->Peter),

 

 

sizeof(pSaying),

 

 

sizeof(*(pSaying)));

 

for (i = 0; pOurSaying->Murphy.szSaying[i]; i++)

{

pOurSaying->Murphy.nLength[i] = strlen(pOurSaying- >Murphy.szSaying[i]);

}

for (i = 0; pOurSaying->Murphy.szSaying[i]; i++)

{

218

C Structures

C C C

 

C7C

 

C C C

 

C

printf(“pOurSaying->Murphy %p %3d ‘%s’\n”, &pOurSaying->Murphy.szSaying[i], pOurSaying->Murphy.nLength[i], pOurSaying->Murphy.szSaying[i]);

}

printf(“\n\n”);

for (i = 0; pSaying->szSaying[i]; i++)

{

pSaying->nLength[i] = strlen(pSaying->szSaying[i]);

}

for (i = 0; pSaying->szSaying[i]; i++)

{

printf(“pOurSaying->Peter %p %3d ‘%s’\n”, &pSaying->szSaying[i], pSaying->nLength[i], pSaying->szSaying[i]);

}

printf(“\n\n”);

return (0);

}

When a structure is accessed with a pointer, theusual method of obtaining a value from memory (using the * operator) is unsatisfactory. To access a member of a structure pointed to by a pointer, you use the -> structure pointer operator rather than the . structure member operator. The -> operator is used as shown in Listing 7.8. You use the address of operator to assign the address of the structure to the pointer.

Understanding unions

If a structure is a group of related data objects, what is a union?

In a structure, each member is stored separately. Modifying one member of a structure does not change the contents of any other member.

219

Part II • Managing Data in C

In a union, all the members share the same block of storage. The block of storage is large enough to hold the largest member; smaller members use only as much storage as necessary. If you change what is stored in one member of a union, all other members are changed too.

Figure 7.1 shows the relationship between a structure and a union in memory. This figure shows the relationship between allocated memory and the members that are part of the data object.

Figure 7.1. A structure and a union in memory.

The UNION.C program in Listing 7.9 reads the database file created with the CREATEDB.C program (Listing 7.6). UNION.C places the result of the read into a union. It then checks what type of record was read and calls the correct function to process the record.

Listing 7.9. UNION.C.

/* UNION, written 1992 by Peter D. Hipson

*This program reads the CREATEDB.C database. The

*program has minimal error checking; it will fail

*if you provide a field value that is too long for the

*structure member that holds it. Use with caution!

*/

220

C Structures

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

#define CUSTOMER_RECORD 1 #define SUPPLIER_RECORD 2

// Define the structure for the customer database.

C C C

C7C C

C C C

typedef

struct

_CUSTNAME {

 

 

 

 

 

 

int

nRecordType;

 

 

 

 

 

 

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 characters for city;

1 for null at end

char

szState[3];

//

2-character state abbreviation +

null

int

nZip;

//

Use integer;

print as %5.5d for leading 0

int

nRecordNumber;

//

Which record number?

 

 

double dSalesTotal;

// Amount the customer has purchased

 

} CUSTNAME;

 

 

 

 

 

 

 

typedef

CUSTNAME near *NPCUSTNAME;

 

 

 

typedef

CUSTNAME

*PCUSTNAME;

 

 

 

 

 

typedef

struct

_SUPPLIERNAME {

 

 

 

 

int

nRecordType;

 

 

 

 

 

 

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 characters for city;

1 for null at end

char

szState[3];

//

2-character state abbreviation +

null

int

nZip;

//

Use integer. Print as %5.5d for leading 0

int

nRecordNumber;

//

Which record number?

 

 

double dSalesTotal; // Amount the customer has purchased

} SUPPLIERNAME;

continues

221

Part II • Managing Data in C

Listing 7.9. continued

typedef SUPPLIERNAME near *NPSUPPLIERNAME; typedef SUPPLIERNAME *PSUPPLIERNAME;

typedef union _DBRECORD { CUSTNAME Customer; SUPPLIERNAME Supplier; } DBRECORD;

/*

Local prototypes (use the typedef’ed names,

*

so must follow typedefs):

*/

 

 

SUPPLIERNAME

ProcessSupplier(NPSUPPLIERNAME);

CUSTNAME

ProcessCustomer(NPCUSTNAME);

// main() function, the called functions

void main()

{

DBRECORD dbRecord;

FILE

*DataFile;

char

szFileName[25];

char

szBuffer[129];

int

i;

int

nResult[3];

double

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

printf(“Please enter customer database name: “);

gets(szFileName);

DataFile = fopen(szFileName, “rb”);

222

C Structures

C C C

 

C7C

 

C C C

 

C

if (DataFile == NULL)

{

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

exit(4);

}

nResult[0] = 1;

while (nResult[0] == 1)

{

nResult[0] = fread((char *)&dbRecord, sizeof(DBRECORD), 1, DataFile);

if (nResult[0] != 1)

{

if (!feof(DataFile))

{

printf(“ERROR: File ‘%s’, read error.\n”, szFileName);

fclose(DataFile);

exit(4);

}

else

{

printf(“End of database file ‘%s’.\n”, szFileName);

}

}

else

{

//You could test dbRecord.Supplier.nRecordType, or

switch(dbRecord.Customer.nRecordType)

{

case CUSTOMER_RECORD:

ProcessCustomer(&dbRecord.Customer);

break;

case SUPPLIER_RECORD:

continues

223

Part II • Managing Data in C

Listing 7.9. continued

ProcessSupplier(&dbRecord.Supplier);

break;

default:

printf(“ERROR: Invalid record type read from \ database \n”);

break;

}

}

}

fclose(DataFile);

}

SUPPLIERNAME ProcessSupplier(

NPSUPPLIERNAME npSupplier)

{

SUPPLIERNAME WorkSupplier;

WorkSupplier = *npSupplier;

printf(“Supplier name: %s\n”, npSupplier->szName);

//Do other processing for Supplier...

//.

//.

//.

//Return WorkSupplier to caller.

return(WorkSupplier);

}

CUSTNAME ProcessCustomer(

NPCUSTNAME npCustomer)

224

C Structures

{

CUSTNAME WorkCustomer;

WorkCustomer = *npCustomer;

printf(“Customer name: %s\n”, npCustomer->szName);

//Do other processing for customer...

//.

//.

//.

//Return WorkCustomer to caller.

return(WorkCustomer);

}

C C C

C7C C

C C C

An integer that determines the record type is the first field of each of the two structures that make up the union. Another common way to refer to a field like this is to code the definitions as

typedef union _DBRECORD {

int

nRecordType;

CUSTNAME

Customer;

SUPPLIERNAME

Supplier;

} DBRECORD;

 

In this definition, you also have a record type variable as part of the union. You can check the value of the record type variable by simply using the following format,

rather than Customer or Supplier:

DBRECORD dbRecord;

/* Read a database record into dbRecord */

switch(dbRecord.nRecordType) // Rather than //

//dbRecord.Customer.nRecordType

{

With this format, the first field of each structure must still be an integer that will hold the record type. However, you can refer to the first field directly, which makes the code easier to read.

225