Lesson 6 Data Structure Overview This lesson introduces structures. The designers of C++ evolved structures into the notion of a class. Like a class, C++ structures can contain access specifiers, member functions, constructors and destructors. In fact, the only difference between structures and classes in C++ is that structure members default to public access and class members default to private access when no access specifiers are used. In this lesson we focus on their use where structures contain only public data members. We will learn how to declare structures, initialize structures and pass structures to functions. Lessons 1. Introduction to Structures in C++ 2. Dealing with Structures 3. Accessing the members of Structures 4. Structures Operation 5. Arrays of Structures 6. Pointers to Structures 7. Hierarchical or Nested Structures 8. Structures and functions 9. Union of structures Lesson 1 – Introduction to Structures in C++ Objectives: At the end of this lesson you will be able to: Describe Structures Structures form a very large building block with which to collect one or more variables, possibly of different types, grouped together into one collective unit using a single name for easy handling. They are a versatile data structure in which to clump data together in convenient little packages. Variables can be of any type: int, float, char or other struct etc. Structure is commonly used to define records to be stored in files. Structure, combined with pointers, can create linked lists, stacks, queues, and trees. The main difference between structure and array is that arrays are collections of the same data type and structure is a collection of variables under a single name. Contrast between arrays and structures Aggregate Operation Array Struct 1 Arithmetic No No 2 Assignment No Yes 3 Input/output No (except strings) No 4 Comparison No No 5 Parameter passing By reference only By value or by reference 6 Function returning a value No Yes Structures and classes are syntactically identical, except in the default accessibility of their members and their inheritance. By default, members of structures have public accessibility and public inheritance from their parent(s), while members of classes are private and inherit privately from their parent(s). Individual members' accessibility can be specified by using the public, protected and private keywords. Following the conventions of object-oriented programming, class is the more commonly used term for referring to these object data types in C++. The semantics of classes, by making members private by default, encourages encapsulation. They are essentially classes with all members defined as public access with no private or protected access modes available. They are most commonly used for conglomerating data and also support member functions, but that attribute is rarely used. The reason is because when multiple functions are involved, the need for private and protected variables and functions increases. Lesson 2 – Dealing with Structures Objectives: At the end of this lesson you will be able to: use structure Declaring and Creating a Structure Structures are declared in C++ using the following syntax:. struct structure name{ member_type1 member_name1; member_type2 member_name2; member_type3 member_name3; } object_name; where structure_name is a name for the structure type, object_name can be a set of valid identifiers for objects that have the type of this structure. Within braces { } there is a list with the data members, each one is specified with a type and a valid identifier as its name. The above structure declaration is also called Structure Specifier. The first thing we have to know is that a structure creates a new type: Once a structure is declared, a new type with the identifier specified as structure_name is created and can be used in the rest of the program as if it was any other type. Declaring structures does not mean that memory is allocated. Structure declaration gives a skeleton or template for the structure. It is important to clearly differentiate between what is the structure type name, and what is an object (variable) that has this structure type. We can instantiate many objects (i.e. variables, like apple, banana and orange) from a single structure type (product). The above structures declaration can be used for the below sample: struct Product{ int weight; float price; }; // end struct product The keyword struct introduce the definition for structure Product. The identifier Product is the structure name and is used in C++ to declare variables of the structure type. In this example, the structure type is Product. Data (and possibly functions) declared within the braces of the structure definition are the structure’s members. Members of the same structure must have unique names, but two different structures may contain members of the same name without conflict. Each structure definitions must end with a semicolon. The definition of Product contains two members of type int* - weight and float* price. Structure members can be variables of the fundamental data types (e.g., int, double, etc.) or aggregates such as arrays, other structures and or classes. Data members in a single structure definitions can be of many data types. For example, a Student structure might contain character-string members for the first and last names, an int member for the student’s age, a char member containing ‘M’ or ‘F’ for the student’s gender and so on. A structure cannot contain an instance of itself. For example, a structure variable Product cannot be declared in the definition for structure Product. A pointer to a Product structure however can be included. A structure containing a member that is a pointer to the same structure type is referred to as a self-referential structure. Declaring Structure Variables The Product structure declaration above does not reserve any space in memory; rather; it creates a new data type that is used to declare structure variables. Structure variables are declared like variables of other types. The following declarations Product apple; Product mango; Product orange; declare apple, mango and orange to be a structure variable of type Product, Variables of a given structure type can also be declared by placing a commaseparated list of the variable names between the closing brace of the structure definition and the semicolon that ends the structure definition. For example, the preceding declarations could have been incorporated into the Product structure definitions as follows: struct Product{ int *weight; float *price; }apple, mango, orange; Once declared, product has become a new valid type name like the fundamental ones int, char or short and from that point on we are able to declare objects (variables) of this compound new type, like we have done with apple, mango and orange. When structure is defined, it allocates or reserves space in memory. The memory space allocated will be cumulative of all defined structure members. In the above example, there are 3 structure members: custnum, salary and commission. Of these, two are of type in and one is of type float. If integer space allocated by a system is 2 bytes and float four bytes the above would allo9acter 2bytes for custnum, 2 bytes for salary and 4 bytes for commission. The structure name is optional. If a structure definition does not contain a structure name, variables of the structures type may be declared only between the closing right brace of the structure definition and the semicolon that terminates the structure definition. The only valid built-in operations that may be performed on structure variable are assigning a structure variable to a structure variable of the same type, taking the address (&) of a structure object, accessing the members of a structure object (int the same manner as members of a class are accessed) and using the sizeof operatpr to determine the size of a structure. As with classes, most operators can be overloaded to work with objects of a structure type. Structure Members Initialization As with arrays and variables, structure members can also be initialized. The initializer is preceded by an equal sign (=). There are two ways to do the initialization of structures. 1. Structures can be initialized field by field as below: struct Product{ int *weight; float *price; }apple, mango, orange; Product Product1; Product1.weight = 1000; Product1.price=2.25; 2. Structures can also be initialized by a list at declaration (similar to an array). This is performed by enclosing the values to be initialized inside the braces { and } after the structure variable name while it is defined. struct Product{ int *weight; float *price; }apple, mango, orange; Product Product1={1000,2.25}; Example 6.1: #include struct Customer { int custnum; int salary; float commission; }; void main( ) { Customer cust1={100,2000,35.5}; Customer cust2; cout <<”\n Customer Number: “< cout <<”; Salary: Rs.“< cout <<”; Commission: Rs.“< cust2=cust1; cout <<”\n Customer Number: “< cout <<”; Salary: Rs.“< cout <<”; Commission: Rs.“< } The output of the above program is Customer Number: 100; Salary: Rs.2000; Commission: Customer Number: 100; Salary: Rs.2000; Commission: Rs.35.5 Rs.35.5 In the above example, the structure variable can be assigned to each by using assignment operator ‘=’. The programmer must consider that only structure variables of the same type can be initialized. If a programmer tries to initialize two structure variables of different types to each other it would result in compiler error. It is wrong to initialize as: Customer cust1; cust1= {100,2000,35.5}; X Lesson 3 – Accessing the members of Structures Objectives: At the end of this lesson you will be able to: Show and modify the structure members The operator used to access structure members are dot operator and arrow operator. Using dot (.) operator To access structure members, the operator used is the dot operator denoted by (.). The dot operator for accessing structure members is used thusly: Consider the example below: struct product { int weight; float price; } apple, banana, melon; Once we have declared our three objects of a determined structure type (apple, banana and melon) we can operate directly with their members. To do that we use a dot (.) inserted between the object name and the member name. For example, we could operate with any of these elements as if they were standard variables of their respective types: apple.weight apple.price banana.weight banana.price melon.weight melon.price Each one of these has the data type corresponding to the member they refer to: apple.weight, banana.weight and melon.weight are of type int, while apple.price, banana.price and melon.price are of type float. For example: A programmer wants to assign 2000 for the structure member weight in the above example of structure Product with object name apple this is written as: apple.weight=2000; Structure variable name / object name Dot operator Member name Let's see a real example where you can see how a structure type can be used in the same way as fundamental types: Example 6.2 : Example about structure #include <iostream> #include <string> #include <sstream> using namespace std; Enter title: Alien Enter year: 1979 My favorite movie is: 2001 A Space Odyssey (1968) And yours is: Alien (1979) struct movies_t { string title; int year; } mine, yours; void printmovie (movies_t movie); int main () { string mystr; mine.title = "2001 Odyssey"; mine.year = 1968; A Space cout << "Enter title: "; getline (cin,yours.title); cout << "Enter year: "; getline (cin,mystr); stringstream(mystr) >> yours.year; cout << "My favorite movie is:\n "; printmovie (mine); cout << "And yours is:\n "; printmovie (yours); return 0; } void printmovie (movies_t movie) { cout << movie.title; cout << " (" << movie.year ")\n"; } << The example shows how we can use the members of an object as regular variables. For example, the member yours.year is a valid variable of type int, and mine.title is a valid variable of type string. The objects mine and yours can also be treated as valid variables of type movies_t, for example we have passed them to the function printmovie as we would have done with regular variables. Therefore, one of the most important advantages of data structures is that we can either refer to their members individually or to the entire structure as a block with only one identifier. Using Arrow Operator When using a pointer to a struct, the "->" (arrow) operator is typically used as a more readable way to both dereference the pointer and select a member. Assume the following declaration //-- Define a new struct type struct Point { int x; int y; }; //-- Declare some variables of type Point. Point p1; Point p2; Point * paddr; // declare pointer to a Point struct The following are equivalent with above. int h = paddr // using arrow notation. int h = (*paddr).x; // using deref plus dot. Lesson 4 – Structures Operations Objectives: At the end of this lesson you will be able to: Use operations with structure members Assume the following declaration //--- Define a new struct type struct Point { int x; int y; }; //--- Declare some variables of type Point Point p1; Point p2; Point paddr; // declare to a Point struct Assignment A struct variable can be assigned to/from. p1 = p2; Comparison - NO The comparison operators do not work on structs. To compare structs, compare individual fields. if (p1.x==p2.x && p1.y==p2.y)……. It is not possible to write p1==p2. There are good reasons to forbid comparison. What would a greater than comparison even mean on a Point for example. A bit-by-bit equal comparison is not feasible in general because there may be padding or unfilled elements (eg in a C-string). Arithmetic operators - NO By default none of the arithmetic operators work on structs. I/O - NO The I/O operators >> and << do not work for structs; you must read/write the fields individually. Solutions You may redefine operators so that they do work with your structs. When providing functions and overloaded operators for your struct, use the class keyword instead -- it's what programmers expect. Lesson 5 – Array of Structures Objectives: At the end of this lesson you will be able to: Use array of Structures Data structures are a feature that can be used to represent databases, especially if we consider the possibility of building arrays of them. Array elements can be structures. Array of structures solves the parallel array problem. struct movies_t { string title; int year; } films [N_MOVIES]; References: films[2].title // title of 3rd item films[4].year //year of 5th item Example 6.3: Array of Structures #include <iostream> #include <string> #include <sstream> using namespace std; #define N_MOVIES 3 Enter Enter Enter Enter Enter Enter title: Blade Runner year: 1982 title: Matrix year: 1999 title: Taxi Driver year: 1976 struct movies_t { string title; int year; You have entered these movies: Blade Runner (1982) Matrix (1999) } films [N_MOVIES]; Taxi Driver (1976) void printmovie (movies_t movie); int main () { string mystr; int n; for (n=0; n<N_MOVIES; n++) { cout << "Enter title: "; getline (cin,films[n].title); cout << "Enter year: "; getline (cin,mystr); stringstream(mystr) >> films[n].year; } cout << "\nYou have entered these movies:\n"; for (n=0; n<N_MOVIES; n++) printmovie (films[n]); return 0; } void printmovie (movies_t movie) { cout << movie.title; cout << " (" << movie.year ")\n"; } << Lesson 6 – Pointers to Structures Objectives: At the end of this lesson you will be able to: Use pointers to structures Like any other type, structures can be pointed by its own type of pointers: struct movies_t { string title; int year; }; movies_t amovie; movies_t * pmovie; Here amovie is an object of structure type movies_t, and pmovie is a pointer to point to objects of structure type movies_t. So, the following code would also be valid: pmovie = &amovie; The value of the pointer pmovie would be assigned to a reference to the object amovie (its memory address). We will now go with another example that includes pointers, which will serve to introduce a new operator: the arrow operator (->): Example 6.4: Pointers to structures #include <iostream> #include <string> #include <sstream> using namespace std; struct movies_t { string title; int year; }; Enter title: Invasion of the body snatchers Enter year: 1978 You have entered: Invasion of the (1978) body snatchers int main () { string mystr; movies_t amovie; movies_t * pmovie; pmovie = &amovie; cout << "Enter title: "; getline (cin, pmovie->title); cout << "Enter year: "; getline (cin, mystr); (stringstream) mystr >> pmovie>year; cout << "\nYou have entered:\n"; cout << pmovie->title; cout << " (" << pmovie->year << ")\n"; return 0; } The previous code includes an important introduction: the arrow operator (->). This is a dereference operator that is used exclusively with pointers to objects with members. This operator serves to access a member of an object to which we have a reference. In the example we used: pmovie->title Which is for all purposes equivalent to: (*pmovie).title Both expressions pmovie->title and (*pmovie).title are valid and both mean that we are evaluating the member title of the data structure pointed by a pointer called pmovie. It must be clearly differentiated from: *pmovie.title which is equivalent to: *(pmovie.title) And that would access the value pointed by a hypothetical pointer member called title of the structure object pmovie (which in this case would not be a pointer). The following panel summarizes possible combinations of pointers and structure members: Expression What is evaluated Equivalent a.b Member b of object a a->b Member b of object pointed by a (*a).b *a.b Value pointed by member b of object a *(a.b) Lesson 7 – Hierarchical or Nested Structures Objectives: At the end of this lesson you will be able to: Use nested Structures Structures can also be nested so that a valid element of a structure can also be in its turn with another structure. Nesting of structures is placing structures within structure. You can nest a structure within another structure, and therefore keep associated elements together. The declaration syntax is what you would expect, as you can see in the following structure, which implements a push-down stack as a very simple linked list so it “never” runs out of memory. Members in different structure can have the same name, since they are at different position. Nested structures encapsulate structure definitions and make them an integral part of an enclosing structure definition. Use the . or -> operators in succession to access the member you want from a nested structure. struct movies_t { string title; int year; }; struct friends_t { string name; string email; movies_t favorite_movie; } charlie, maria; friends_t * pfriends = &charlie; After the previous declaration we could use any of the following expressions: charlie.name maria.favorite_movie.title charlie.favorite_movie.year pfriends->favorite_movie.year (where, by the way, the last two expressions refer to the same member). Lesson 8 –Structures and Functions Objectives: At the end of this lesson you will be able to: pass structures by value It is certainly possible to pass structures by value, which passes a copy of the original structure to a function. The disadvantage to this process is evident when dealing with large structures which will increase memory requirements and slow the system down. Consequently, passing by reference is the most economical method of dealing with structures and functions. The function will access the actual address locations of where the structures are stored as opposed to working with copies of the structures. Example 6.5: Structures and Functions //shows global nature of structure, passed by REFERENCE, use of ARRAY. # include <iostream.h> # include "apstring.cpp" # include <apvector.h> struct STUDENT_TYPE { apstring name, course; double average, finalExam; }; //function prototypes STUDENT_TYPE get_student( ); void print_student(STUDENT_TYPE & pupil); int main(void) { //declare the array of students apvector <STUDENT_TYPE> list(10); // input the list of students for(int i = 0; i < 10; i++) { cout<<"Please enter information for student " << i+1 << endl << endl; list[ i ] = get_student( ); //use function to get individual info } // print the array of students one struct at a time for(int j = 0; j < 10; j++) { print_student(list [ j ] ); } return 0; } //function to read in structure information (returns a structure) STUDENT_TYPE get_student( ) { STUDENT_TYPE pupil; apstring dummy; cout << "Enter the name (last name, first name): "; getline( cin, pupil.name); cout << "Enter the course name: "; getline( cin, pupil.course); cout << "Enter the course average: "; cin>>pupil.average; cout << "Enter the final exam grade: "; cin>> pupil.finalExam; getline(cin,dummy); cout<<endl <<endl; return pupil; } //function to print structure void print_student(STUDENT_TYPE &pupil) { cout << "Name: " <<pupil.name<< endl; cout << "Course: " <<pupil.course <<endl; cout << "Average: " << pupil.average << endl; cout << "Final Exam: " << pupil.finalExam << endl <<endl; return; } Lesson 9 –Unions of Structures Objectives: At the end of this lesson you will be able to: Use unions A union is a struct, contains only one object from its list of members (although that object can be an array or a class type) during the program execution. union Qty_type { int count; float linear_ft; long cu_in; }; At run time, how_many contains either Qty_type •a float how_many; •an int •a long ... But … never all three At run time memory allocated to the variable how_many does NOT include room for all three components. Instead, how_many can contain only one of the following: either a long value or an int value or a float value. The primary purpose pf the union of the construction is to save memory. Because the compiler does not track which union field is currently selected, the use of unions is somewhat dangerous. References: 1. Paul J. Deitel & H.M. Deitel () C++ How to Program (6th Edition). Prentise Hall 2. C++ Structrures and Classes http://en.wikipedia.org/wiki/C%2B%2B_structures_and_classes 3. Using Structures in C++ http://www.inversereality.org/files/structures.pdf 4. Structures and Unions http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/ com.ibm.xlcpp8a.doc/language/ref/strct.htm 5. C++ Notes : Struct Operations http://www.fredosaurus.com/notes-cpp/structs/struct-ops.html 6. C++ Structures http://www.exforsys.com/tutorials/c-plus-plus/cstructures.html 7. Structure http://www.cs.uregina.ca/Links/classinfo/cplusplus/Structure.html 8. Structures in C++ http://mathbits.com/mathbits/compsci/Structures/Init.htm 9. More on pointers in C http://www.cse.lehigh.edu/~brian/course/2007/cunix/notes/more pointers.html