Section 7 - structs (not in book)

-most data objects we've used so far have been scalar - a single type

-structs give you the ability to have a variable which contains more than one data type

-very useful for grouping related data into a more real-world object

-a struct contains a varying number of individual components called members

-each member is accessed via its member name

-C++ syntax for declaring structs:

struct nameofstruct

{

type objectlist1;

type objectlist2;
. . .

type objectlistn;

}; //note semicolon at end!!

-then we can declare objects of type nameofstruct

-for example, keeping information about employees of a company requires certain info about each person:
ID
Name
Gender
Number of Dependents
Hourly rate of pay
Total wages (per pay period)

-the C++ struct definition would look like this:

struct Employee

{

int ID;

Strings Name;

char Gender;

int NumDepends;

float PayRate, TotalWages;

};

(The struct definition is usually placed in the header library file, so as to be a global definition for the entire project)

-and then we could declare data objects of type Employee:

Employee

Secretary1,

Secretary2,

Custodian;

-To access the members of the struct, use the member access operator, which is a period

-e.g.

Custodian.ID = 1234; //an integer variable

Custodian.Name = "Kris Rudin"; //a string variable

Custodian.Gender = 'F'; //a character variable

Custodian.PayRate = 6.5; //a real variable

Custodian.TotalWages = Custodian.PayRate * 40.0; //math w/real vars

cout << "ID of custodian is " << Custodian.ID << endl;

cout << "Enter the pay rate of secretary #1 ";

cin >> Secretary1.PayRate;

-Note that the member names alone are not defined:

ID

Name

Gender

--all of the above are undefined identifiers w/o the variable name and member operator

-Assigning/copying structs:

-you can use the assignment operator (=) with structs of the same type:
-e.g.

Secretary1 = Secretary2;

-This copies all member data from secretary2 into secretary1

-comparing structs:

-you can't use the

-Passing structs as arguments to functions:

-works like any other variable

-can pass by value or reference

-e.g.,

void PrintEmployeeInfo(Employee Emp)//pass by value

{

cout << "ID: " << Emp.ID << endl;

cout << "Name: " << Emp.Name << endl;

etc.

}

-to pass a specific employee object to the print function, do this:

PrintEmployeeInfo(Secretary2);

-to pass by reference, use '&' in formal list, as usual:

void GetEmployeeInfo(Employee& Emp)

{

cout << "Enter the ID number\n";

cin >> Emp.ID;

etc.

}

-For efficiency reasons, if the struct is very large, you can pass by reference using 'const' to protect changing the data:
void PrintEmployeeInfo(const Employee& Emp)
{
etc.
}

-It is possible to have an array as a member of a struct:

typedef float ScoreArray[5];

struct Student

{

Strings Name;

ScoreArray Scores;

float AvgScore;

}

Student

Student1,Student2;

. . .

Student1.Scores[0] = 97; //the 1st student's 1st score

Student1.Scores[4] = 0; //the 1st student's last score

. . .

//a function to find the average of a student's scores:

float Avg(ScoreArray Sc) //pass in only the array

{

float

Sum = 0.0;

for (int x=0; x<5; x++)

Sum += Sc[x];

return Sum/5;

}

//the call to the above function:

Student1.AvgScore = Avg(Student1.Scores);

-You can also have an array of structs:

typedef Student ClassType[50]; //an array of 50 students

ClassType

CS225, CS226; //two arrays of type ClassType

. . .

CS225[1] --this is one variable of type Student

CS225[1].Name --this is the name of one student (type strings)

CS226[5].Scores[0] --this is the 1st score of one student in 226 (float)

CS226[5].Scores[1] -- the 2nd score of the same student in 226 (float)

-Given that we can have an array of structs (not just single dimension, either), we can SORT such an array, BUT-we must sort on ONE of the members (the key field), by comparing values of individual members

-That is, we pass in the array of structs to be sorted, but the comparison is done on the key field, such as name.

-Remember, however, that the SWAP or SHIFT must occur on the whole struct element, not just the key field member! If you forget this, you'll end up with the wrong data in the wrong structs!

-example (sorting by Name):

void Insert(ClassType TheList, int N)

{

int

Searcher, //moves thru array

Shifter; //used to shift array elements

Student

Temp, //holds value to insert

for(Searcher=1; Searcher<N; Searcher++) //start at 2nd element!

if (TheList[Searcher-1].Name > TheList[Searcher].Name)

{

Temp = TheList[Searcher]; //smaller WHOLE element saved

//start shifting elements until you find the spot for temp:

Shifter = Searcher - 1;

while (Shifter > -1 && TheList[Shifter] > Temp)

{

TheList[Shifter+1] = TheList[Shifter]; //shift right

Shifter--;

}//end while

TheList[Shifter+1] = Temp; //insert temp in position

}//end if

}//end function

-Note the comparison is on the Name member, but the shifting and inserting is with the entire struct!

-Think about a swap routine for struct types - would go into the struct definition library, along with any other functions

-STRUCTS within STRUCTS:

-since a struct contains members of some data type, it is possible for a struct to have as one of its members another struct (of a different type)

-for example:

struct Address

{

Strings

Street,

City,

State,

Zip;

};

struct Dimensions

{

double

Length,

Width,

Height;

};

struct ParcelData

{

double

Weight;

Dimensions

Measurement; //a struct!!

};

//****main struct definition:

struct Parcel

{

Address

Destination; //a struct!!

double

Postage;

int

Delivered; //boolean flag

ParcelData

Data; //a struct (w/struct inside it!)

double

Volume;

};

typedef Parcel ParcelList[100]; //type definition of array of parcels

Parcel

Package1,Package2; //two Parcel variables (structs)

ParcelList

Packages; //an array variable of parcels (structs)

VARIABLE DESCRIPTION

Package1 a struct (5 members)

Packages an array of structs

Packages[4] a struct (5 members)

Package2.Postage a real number variable

Packages[9].Volume a real number variable

Package1.Delivered an integer variable

Package1.Data a struct (2 members)

Package1.Data.Measurement a struct (3 members)

Package1.Data.Measurement.Length a real number

Package1.Data.Weight a real number

Package[6].Destination a struct (4 members)

Package[6].Destination.Street a String

Package[6].Destination.City a string

Package[6].Destination.State a string

Package[6].Destination.Zip a string

**Remember to use the name of the member, not its data type!!

-that is, don't do this:

Package1.Address

-because "Address" is the name of a data type (a struct), not a member!

-can't "skip" a member name:

Package1.Zip

Package2.Measurement

Package[4].Length

-suppose we had this declaration also:

Address

Address1; //a variable of type address

-then we could do this:

Package2.Destination = Address1; //both are structs of same type

Package2.Destination.City = Address1.City;

Address1.Street = Packages[7].Destination.Street

-but we couldn't do this:

Package1 = Address; //2 completely different data types!

-Sample functions:

-a function to fill array of packages (with members that aren't computed by program):

void GetPackages(ParcelList Packs, int& WL, fstream& inf)

{

WL = -1;

while (!inf.eof() && WL < SIZE) //SIZE is global array length

{

WL++;

//read in address strings:

Packs[WL].Destination.Street.GetLine(inf);

Packs[WL].Destination.City.GetLine(inf);

Packs[WL].Destination.State.GetLine(inf);

Packs[WL].Destination.Zip.GetLine(inf);

//read in size data:

inf >> Packs[WL].Data.Weight;

inf >> Packs[WL].Data.Measurement.Length;

inf >> Packs[WL].Data.Measurement.Width;

inf >> Packs[WL].Data.Measurement.Height;

}//end while

}//end function

-a function to print one package info:

void PrintPack(Parcel Pack)

{

cout << "ADDRESS:\n";

cout << Pack.Destination.Street << endl;

cout << Pack.Destination.City << endl;

cout << Pack.Destination.State << endl;

cout << Pack.Destination.Zip << endl;

cout << "POSTAGE: " << Pack.Postage << endl; //not formatted!

cout << "SIZE:\n";

cout << "\tWEIGHT: " << Pack.Data.Weight << endl;

cout << "\tLENGTH: " << Pack.Data.Measurement.Length << endl;

cout << "\tWIDTH: " << Pack.Data.Measurement.Width << endl;

cout << "\tHEIGHT: " << Pack.Data.Measurement.Height << endl;

cout << "\tVOLUME: " << Pack.Volume << endl;

cout << "DELIVERED? ";

if (Pack.Delivered)

cout << "yes\n";

else

cout << "no\n";

}//end function

//calling this function to print each package in list:

for (c=0; c<WL; c++)

{

cout << "PACKAGE # " << c+1 << ":" << endl;

cout << "=============\n";

PrintPack(Packages[c]);

cout << endl;

}

-a function to find the volume of a package:

double PackVol(Dimensions PackDim)

//a struct parameter containing 3 members: l,w,h

{

return PackDim.Length * PackDim.Width * PackDim.Heigth;

}

//calling the function to find volume of all packages in array:

for (k=0; k<Size; k++)

Packages[k].Vol = PackVol(Packages[k].Data.Measurement);

//don't need to pass in whole struct, just the "inner" one

-a function to compute the total weight of all packages going to a particular zip code:

double TotalWeight(ParcelList Pack, int Size, Strings ZCode)

{

double

Sum=0.0;

for (int c=0; c<Size; c++)

if (Pack[c].Destination.Zip == ZCode)

Sum += Pack.Data.Weight;

return Sum;

}

//calling the function:

Wt = TotalWeight(Packages, WorkingLength, ZipCode);

-find index of package with largest volume:

int LocMaxVol(ParcelList Pack, int Size)

{

double

Max = Pack[0]; //initialize to 1st package

for (int c=0; c < Size; c++)

if (Pack[c].Vol > Max)

Max = Pack[c].Vol;

return Max;

}

//calling the function:

M = LocMaxVol(Packages, WorkLength);

-count how many packages have NOT been delivered:

int NumNotDel(ParcelList Pack, int Size)

{

int

Tot = 0;

for(int c=0; c<Size; c++)

if (!Pack[c].Delivered)

Tot++;

return Tot;

}

-other exercises: