Arrays o f Structures
This chapter builds on the previous one by showing you how to create many structures for your data. After creating an array of structures, you can store many occurrences of your data values.
Arrays of structures are good for storing a complete employee file, inventory file, or any other set of data that fits in the structure format. Whereas arrays provide a handy way to store several values that are the same type, arrays of structures store several values of different types together, grouped as structures.
This chapter introduces the following concepts:
-
Creating arrays of structures
-
Initializing arrays of structures
-
Referencing elements from a structure array
-
Arrays as members
Many C++ programmers use arrays of structures as a prelude to storing their data in a disk file. You can input and calculate your disk data in arrays of structures, and then store those structures in memory. Arrays of structures also provide a means of holding data you read from the disk.
Declaring Array s of Structure s
It is easy to declare an array of structures. Specify the number of reserved structures inside array brackets when you declare the structure variable. Consider the following structure definition:
st r uct st or es
{ i nt empl oyees;
i nt r egi st er s; doubl e sal es;
} st or e1, st or e2, st or e3, st or e4, st or e5;
This structure should not be difficult for you to understand because there are no new commands used in the structure declara- tion. This structure declaration creates five structure variables. Figure 29.1 shows how C++ stores these five structures in memory. Each of the structure variables has three members—two integers followed by a double floating-point value.
Figure 29.1. The structure of St or e 1 , St or e 2 , St or e 3 , St or e 4 , and
St or e 5 .
If the fourth store increased its employee count by three, you could update the store’s employee number with the following assignment statement:
st or e4. empl oyees += 3; / / Add t hr ee t o t hi s st or e’ s
/ / empl oyee count.
Suppose the fifth store just opened and you want to initialize its members with data. If the stores are a chain and the new store is similar to one of the others, you can begin initializing the store’s data by assigning each of its members the same data as another store’s, like this:
Arrays of structures make working with large numbers of structure variables manageable.
st or e5 = st or e2; / / Def i ne i ni t i al val ues f or
/ / t he member s of st or e5.
Such structure declarations are fine for a small number of structures, but if the stores were a national chain, five structure variables would not be enough. Suppose there were 1000 stores. You would not want to create 1000 different store variables and work with each one individually. It would be much easier to create an array of store structures.
Consider the following structure declaration:
st r uct st or es
{ i nt empl oyees;
i nt r egi st er s; doubl e sal es;
} st or e[ 1000];
In one quick declaration, this code creates 1000 store structures, each one containing three members. Figure 29.2 shows how these structure variables appear in memory. Notice the name of each individual structure variable: st or e[ 0] , st or e[ 1] , st or e[ 2] , and so on.
Figure 29.2. An array of the st or e structures.
The element st or e[ 2] is an array element. This array element, unlike the others you have seen, is a structure variable. Therefore, it contains three members, each of which you can reference with the dot operator.
The dot operator works the same way for structure array elements as it does for regular structure variables. If the number of employees for the fifth store (st or e[ 4] ) increased by three, you could update the structure variable like this:
st or e[ 4]. empl oyees += 3; / / Add t hr ee t o t hi s st or e’ s
/ / empl oyee count.
You can assign complete structures to one another also by using array notation. To assign all the members of the 20th store to the 45th store, you would do this:
st or e[ 44] = st or e[ 19] ; / / Copy all member s f r om t he
/ / 20t h st or e t o t he 45t h.
The rules of arrays are still in force here. Each element of the array called st or e is the same data type. The data type of st or e is the structure st or es . As with any array, each element must be the same data type; you cannot mix data types in the same array. This array’s data type happens to be a structure you created containing three members. The data type for st or e[ 316] is the same for st or e[ 981] and st ore[ 74] .
The name of the array, st or e , is a pointer constant to the starting element of the array, st or e[ 0] . Therefore, you can use pointer nota- tion to reference the stores. To assign st or e[ 60] the same value as st or e[ 23] , you can reference the two elements like this:
* ( st or e+60) = * ( st or e+23) ;
You also can mix array and pointer notation, such as
st or e[ 60] = * ( st or e+23) ;
and receive the same results.
You can increase the sales of st or e[ 8] by 40 percent using pointer or subscript notation as well, as in
st or e[ 8]. sal es = ( * ( st or e+8)) . sal es * 1. 40;
The extra pair of parentheses are required because the dot operator has precedence over the dereferencing symbol in C++’s hierarchy of operators (see Appendix D, “C++ Precedence Table”). Of course, in this case, the code is not helped by the pointer notation. The following is a much clearer way to increase the sal es by 40 percent:
st or e[ 8]. sal es *= 1. 40;
The following examples build an inventory data-entry system for a mail-order firm using an array of structures. There is very little new you have to know when working with arrays of structures. To become comfortable with the arrays of structure notation, concen- trate on the notation used when accessing arrays of structures and their members.
Examples
- Suppose
you work for a mail-order company that sells disk drives. You are given the task of writing a tracking program for the 125 different drives you sell. You must keep track of the following information:
Storage capacity in megabytes Access time in milliseconds Vendor code (A, B, C, or D) Cost
Price
Because there are 125 different disk drives in the inventory, the data fits nicely into an array of structures. Each array element is a structure containing the five members described in the list.
The following structure definition defines the inventory:
st r uct i nvent or y
{
l ong i nt st or age; i nt access_t i me; char vendor _code; doubl e code; doubl e pr i ce;
} dr i ve[ 125] ; / / Def i nes 125 occurr ences of t he st r uct ur e.
- When working with a large array of structures, your first concern
should be how the data inputs into the array ele- ments. The best method of data-entry depends on the application.
For example, if you are converting from an older computer- ized inventory system, you have to write a conversion program that reads the inventory file in its native format and saves it to a new file in the format required by your C++ programs. This is no easy task. It demands that you have extensive knowledge of the system from which you are converting.
If you are writing a computerized inventory system for the first time, your job is a little easier because you do not have to convert the old files. You still must realize that someone has to type the data into the computer. You must write a data-entry program that receives each inventory item from the keyboard and saves it to a disk file. You should give the user a chance to edit inventory data to correct any data he or she originally might have typed incorrectly.
One of the reasons disk files are introduced in the last half of the book is that disk-file formats and structures share a common bond. When you store data in a structure, or more often, in an array of structures, you can easily write that data to a disk file using straightforward disk I/ O commands.
The following program takes the array of disk drive struc- tures shown in the previous example and adds a data-entry function so the user can enter data into the array of struc- tures. The program is menu-driven. The user has a choice, when starting the program, to add data, print data on- screen, or exit the program. Because you have yet to see disk I/ O commands, the data in the array of structures goes away
when the program ends. As mentioned earlier, saving those structures to disk is an easy task after you learn C++’s disk I/ O commands. For now, concentrate on the manipulation of the structures.
This program is longer than many you previously have seen in this book, but if you have followed the discussions of structures and the dot operator, you should have little trouble following the code.
Identify the program and include the necessary header files. Define a structure that describes the format of each inventory item. Create an array of structures called di sk .
Display a menu that gives the user the choice of entering new inventory data, displaying the data on-screen, or quitting the pro- gram. If the user wants to enter new inventory items, prompt the user for each item and store the data into the array of structures. If the user wants to see the inventory, loop through each inventory item in the array, displaying each one on-screen.
/ / Fil ename: C29DSI NV. CPP
/ / Dat a- ent r y pr ogr am f or a di sk dr i ve company. #i ncl ude <i ost r eam. h>
#i ncl ude <st dli b. h> #i ncl ude <i omani p. h> #i ncl ude <st di o. h>
st r uct i nvent or y / / Gl obal st r uct ur e def i ni t i on.
{
l ong i nt st or age; i nt access_t i me; char vendor _code; f l oat cost;
f l oat pr i ce;
} ; / / No st r uct ur e var i abl es def i ned gl oball y.
voi d di sp_menu( voi d) ;
st r uct i nvent or y ent er _dat a() ;
voi d see_dat a( i nvent or y di sk[ 125] , i nt num_i t ems) ; voi d mai n()
{
i nvent or y di sk[ 125] ; / / Local arr ay of st r uct ur es. i nt ans;
i nt num_i t ems=0; / / Number of t ot al i t ems
/ / i n t he i nvent or y.
do
{
do
{ di sp_menu() ; / / Di spl ay menu of user choi ces.
ci n >> ans; / / Get user ’ s r equest.
} whil e (( ans<1) | | ( ans>3)) ;
swi t ch ( ans)
{ case ( 1) : { di sk[ num_i t ems] = ent er _dat a() ; / / Ent er
/ / di sk dat a. num_i t ems++; / / I ncr ement number of i t ems. br eak; }
case ( 2) : { see_dat a( di sk, num_i t ems) ; / / Di spl ay
/ / di sk dat a.
br eak; } def aul t : { br eak; }
}
} whil e ( ans! =3) ; / / Qui t pr ogr am
/ / when user i s done.
r et ur n;
}
voi d di sp_menu( voi d)
{
cout << “ \ n\ n*** Di sk Dr i ve I nvent or y Syst em *** \ n\ n” ; cout << “ Do you want t o:\ n\ n” ;
cout << “ \t 1. Ent er new i t em i n i nvent or y\ n\ n” ; cout << “ \t 2. See i nvent or y dat a\ n\ n” ;
cout << “ \t 3. Exi t t he pr ogr am\ n\ n” ; cout << “ What i s your choi ce? “ ;
r et ur n;
}
i nvent or y ent er _dat a()
{
i nvent or y di sk_i t em; / / Local var i abl e t o f ill
/ / wi t h i nput.
cout << “ \ n\ nWhat i s t he next dr i ve’ s st or age i n byt es? “ ; ci n >> di sk_i t em. st or age;
cout << “ What i s t he dr i ve’ s access t i me i n ms? “ ; ci n >> di sk_i t em. access_t i me;
cout << “ What i s t he dr i ve’ s vendor code ( A, B, C, or D) ? “ ; ff l ush( st di n) ; / / Di scar d i nput buff er
/ / bef or e accept i ng char act er . di sk_i t em. vendor _code = get char() ;
get char() ; / / Di scar d carr i age r et ur n cout << “ What i s t he dr i ve’ s cost ? “ ; ci n >> di sk_i t em. cost;
cout << “ What i s t he dr i ve’ s pr i ce? “ ; ci n >> di sk_i t em. pr i ce;
r et ur n ( di sk_i t em) ;
}
voi d see_dat a( i nvent or y di sk[ 125] , i nt num_i t ems)
{
i nt ct r ;
cout << “ \ n\ nHer e i s t he i nvent or y li st i ng:\ n\
n” ; f or ( ct r =0; ct r <num_i t ems; ct r ++)
{
cout << “ St or age: “ << di sk[ ct r ]. st or age << “ \t ” ;
cout << “ Access t i me: “ << di sk[ ct r ]. access_t i me << “ \ n” ; cout << “ Vendor code: “ << di sk[ ct r ]. vendor _code << “ \t ” ; cout << set pr eci si on( 2) ;
cout << “ Cost : $” << di sk[ ct r ]. cost << “ \t ” ; cout << “ Pr i ce: $” << di sk[ ct r ]. pr i ce << “ \ n” ;
}
r et ur n;
}
Figure 29.3 shows an item being entered into the inventory file. Figure 29.4 shows the inventory listing being displayed to the screen. There are many features and error-checking functions you can add, but this program is the foundation of a more comprehensive inventory system. You can easily
adapt it to a different type of inventory, a video tape collec- tion, a coin collection, or any other tracking system by changing the structure definition and the member names throughout the program.
Figure 29.3. Entering inventory information.
Arrays as Member s
Members of structures can be arrays. Array members pose no new problems, but you have to be careful when you access indi- vidual array elements. Keeping track of arrays of structures that contain array members might seem like a great deal of work on your part, but there is nothing to it.
Consider the following structure definition. This statement declares an array of 100 structures, each structure holding payroll information for a company. Two of the members, name and depar t - ment , are arrays.
st r uct payr oll
{ char name[ 25] ; / / Empl oyee name arr ay.
i nt dependent s;
char depar t ment[ 10] ; / / Depar t ment name arr ay. f l oat sal ar y;
} empl oyee[ 100] ; / / An arr ay of 100 empl oyees.
Figure 29.4. Displaying the inventory data.
Figure 29.5 shows what these structures look like. The first and third members are arrays. name is an array of 25 characters, and depar t ment is an array of 10 characters.
Suppose you must save the 25th employee’s initial in a charac- ter variable. Assuming initial is already declared as a character variable, the following statement assigns the employee’s initial to the varible i ni t i al :
i ni t i al = empl oyee[ 24]. name[ 0];
The double subscripts might look confusing, but the dot opera- tor requires a structure variable on its left (empl oyee[ 24] ) and a member on its right (name’s first array element). Being able to refer to member arrays makes the processing of character data in structures simple.
Figure 29.5. The payroll data.
Examples
- Suppose
an employee got married and wanted her name changed in the payroll file. (She happens to be the 45th employee in the array of structures.) Given the payroll structure described in the previous section, this would assign a new name to her structure:
st r cpy( empl oyee[ 44]. name, “ Mar y Lar son”) ; / / Assi gn
/ / a new name.
When you refer to a structure variable using the dot opera- tor, you can use regular commands and functions to process the data in the structure members.
- A
bookstore wants to catalog its inventory of books. The following program creates an array of 100 structures. Each structure contains several types of variables, including arrays. This program is the data-entry portion of a larger inventory system. Study the references to the members to see how member-arrays are used.
/ / Fil ename: C29BOOK. CPP
/ / Bookst or e dat a- ent r y pr ogr am. #i ncl ude <i ost r eam. h>
#i ncl ude <st di o. h> #i ncl ude <ct ype. h>
st r uct i nvent or y
{ char t i t l e[ 25] ; / / Book’ s t i t l e.
char pub_dat e[ 19] ; / / Publi cat i on dat e.
char aut hor [ 20] ; / / Aut hor ’ s name.
i nt num; / / Number i n st ock.
i nt on_or der ; / / Number on or der .
f l oat r et ail ; / / Ret ail pr i ce.
} ;
voi d mai n()
{
i nvent or y book[ 100];
i nt t ot al =0; / / Tot al books i n i nvent or y. i nt ans;
do / / Thi s pr ogr am ent er s dat a i nt o t he st r uct ur es.
{ cout << “ Book #” << ( t ot al +1) << “ :\ n” , ( t ot al +1) ; cout << “ What i s t he t i t l e? “ ;
get s( book[t ot al ].t i t l e) ;
cout << “ What i s t he publi cat i on dat e? “ ; get s( book[t ot al ]. pub_dat e) ;
cout << “ Who i s t he aut hor ? “ ; get s( book[t ot al ]. aut hor) ;
cout << “ How many books of t hi s t i t l e ar e t her e? “ ; ci n >> book[t ot al ]. num;
cout << “ How many ar e on or der ? “ ; ci n >> book[t ot al ]. on_or der ;
cout << “ What i s t he r et ail pr i ce? “ ; ci n >> book[t ot al ]. r et ail ;
ff l ush( st di n) ;
cout << “ \ nAr e t her e mor e books? ( Y/ N) “ ; ans=get char() ;
ff l ush( st di n) ; / / Di scar d carr i age r et ur n.
ans=t oupper( ans) ; / / Conver t t o upper case. i f ( ans==’ Y’ )
{ t ot al ++; cont i nue; }
} whil e ( ans==’ Y’ ) ; r et ur n;
}
You need much more to make this a usable inventory pro- gram. An exercise at the end of this chapter recommends ways you can improve on this program by adding a printing routine and a title and author search. One of the first things you should do is put the data-entry routine in a separate function to make the code more modular. Because this example is so short, and because the program performs only one task (data-entry), there was no advantage to putting the data-entry task in a separate function.
- Here
is a comprehensive example of the steps you might go through to write a C++ program. You should begin to understand the C++ language enough to start writing some advanced programs.
Assume you have been hired by a local bookstore to write a magazine inventory system. You have to track the following:
Magazine title (at most, 25 characters) Publisher (at most, 20 characters) Month (1, 2, 3,...12)
Publication year
Number of copies in stock Number of copies on order
Price of magazine (dollars and cents)
Suppose there is a projected maximum of 1000 magazine titles the store will ever carry. This means you need 1000 occurrences of the structure, not 1000 magazines total. Here is a good structure definition for such an inventory:
st r uct mag_i nf o
{ char t i t l e[ 25]; char pub[ 25]; i nt mont h;
i nt year ;
i nt st ock_copi es; i nt or der _copi es; f l oat pr i ce;
} mags[ 1000] ; / / Def i ne 1000 occurr ences.
Because this program consists of more than one function, it is best to declare the structure globally, and the structure variables locally in the functions that need them.
This program needs three basic functions: a mai n() control- ling function, a data-entry function, and a data printing function. You can add much more, but this is a good start for an inventory system. To keep the length of this example reasonable, assume the user wants to enter several maga- zines, then print them. (To make the program more “us- able,” you should add a menu so the user can control when she or he adds and prints the information, and should add more error-checking and editing capabilities.)
Here is an example of the complete data-entry and printing program with prototypes. The arrays of structures are passed between the functions from mai n() .
/ / Fil ename: C29MAG. CPP
/ / Magazi ne i nvent or y pr ogr am f or addi ng and di spl ayi ng
/ / a bookst or e’ s magazi nes. #i ncl ude <i ost r eam. h>
#i ncl ude <ct ype. h> #i ncl ude <st di o. h>
st r uct mag_i nf o
{ char t i t l e[ 25]; char pub[ 25]; i nt mont h;
i nt year ;
i nt st ock_copi es; i nt or der _copi es; f l oat pr i ce;
} ;
mag_i nf o f ill _mags( st r uct mag_i nf o mag) ;
voi d pr i nt _mags( st r uct mag_i nf o mags[ ] , i nt mag_ct r) ;
voi d mai n()
{
mag_i nf o mags[ 1000];
i nt mag_ct r =0; / / Number of magazi ne t i t l es. char ans;
do
{ / / Assumes t her e i s
/ / at l east one magazi ne f ill ed. mags[ mag_ct r ] = f ill _mags( mags[ mag_ct r ] ) ;
cout << “ Do you want t o ent er anot her magazi ne? “ ; ff l ush( st di n) ;
ans = get char() ;
ff l ush( st di n) ; / / Di scar ds carr i age r et ur n. i f ( t oupper( ans) == ‘ Y’ )
{ mag_ct r ++; }
} whil e ( t oupper( ans) == ‘ Y’ ) ; pr i nt _mags( mags, mag_ct r) ;
r et ur n; / / Ret ur ns t o oper at i ng syst em.
}
voi d pr i nt _mags( mag_i nf o mags[ ] , i nt mag_ct r)
{
i nt i ;
f or ( i =0; i <=mag_ct r ; i ++)
{ cout << “ \ n\ nMagazi ne “ << i +1 << “ :\ n” ; / / Adj ust s f or
/ / subscr i pt.
cout << “ \ nTi t l e: “ << mags[ i ].t i t l e << “ \ n” ; cout << “ \t Publi sher : “ << mags[ i ]. pub << “ \ n” ;
cout << “ \t Pub. Mont h: “ << mags[ i ]. mont h << “ \ n” ; cout << “ \t Pub. Year : “ << mags[ i ]. year << “ \ n” ;
cout << “ \tI n- st ock: “ << mags[ i ]. st ock_copi es << “ \ n” ; cout << “ \t On or der : “ << mags[ i ]. or der _copi es << “ \ n” ; cout << “ \t Pr i ce: “ << mags[ i ]. pr i ce << “ \ n” ;
}
r et ur n;
}
mag_i nf o f ill _mags( mag_i nf o mag)
{
put s(“ \ n\ nWhat i s t he t i t l e? “) ; get s( mag.t i t l e) ;
put s(“ Who i s t he publi sher ? “) ; get s( mag. pub) ;
put s(“ What i s t he mont h ( 1, 2, . . . , 12) ? “) ; ci n >> mag. mont h;
put s(“ What i s t he year ? “) ; ci n >> mag. year ;
put s(“ How many copi es i n st ock? “) ; ci n >> mag. st ock_copi es;
put s(“ How many copi es on or der ? “) ; ci n >> mag. or der _copi es;
put s(“ How much i s t he magazi ne? “) ; ci n >> mag. pr i ce;
r et ur n ( mag) ;
}
Review Question s
The answers to the review questions are in Appendix B.
-
True
or false: Each element in an array of structures must be the same type.
-
What is the advantage of creating an array of structures rather than
using individual variable names for each struc- ture variable?
-
Given
the following structure declaration:
st r uct i t em
{ char par t _no[ 8]; char descr [ 20]; f l oat pr i ce;
i nt i n_st ock;
} i nvent or y[ 100];
-
How would you assign a price of 12.33 to the 33rd item’s in-stock
quantity?
-
How would you assign the first character of the 12th item’s part
number the value of X?
-
How would you assign the 97th inventory item the same values as the
63rd?
- Given
the following structure declaration:
st r uct i t em
{ char desc[ 20]; i nt num;
f l oat cost;
} i nvent or y[ 25];
- What is wrong with the following statement?
i t em[ 1]. cost = 92. 32;
- What is wrong with the following statement?
st r cpy( i nvent or y. desc, “ Wi dget s”) ;
- What is wrong with the following statement?
i nvent or y. cost[ 10] = 32. 12;
Review Exercise s
-
Write
a program that stores an array of friends’ names, phone numbers, and addresses and prints them two ways: with their name, address, and phone number, or with only their name and phone number for a phone listing.
-
Add
a sort function to the program in Exercise 1 so you can print your friends’ names in alphabetical order. (Hint: You have to make the member holding the names a character pointer.)
-
Expand
on the book data-entry program, C29BOOK.CPP, by adding features to make it more usable (such as search book by author, by title, and print an inventory of books on order).
Summary
You have mastered structures and arrays of structures. Many useful inventory and tracking programs can be written using struc- tures. By being able to create arrays of structures, you can now create several occurrences of data.
The next step in the process of learning C++ is to save these structures and other data to disk files. The next two chapters explore the concepts of disk file processing.