CHAPTER 7
STRUCTURE: PUTTING RELATED ITEMS TOGETHER
When writing a program, several variables (identifiers) are declared and used. Some of the names used as identifiers are related and can be grouped together (memory wise) in one location as one unit in memory. This grouping of related names, including several variables and functions is called a structure. In C, structures group only variables, while in C++ structures group variables as well as their related functions. Each variable and function is referred to as a member of the structure. In C++, the bundling of variables and functions adds the important concept of Object Oriented Programming (OOP), also known as class, to the C language. This incorporation of variables and functions makes C++ both a Procedural as well Object-Oriented language.
HOW TO CREATE A STRUCTURE IN C
The key word struct is used to create a structure. In C, there are three general formats to create a structure variable as shown in Figures 7.1a, b, and c. Notice in Figure 7.1a, the structure is defined with the use of a tag name followed by the definition of the structure and the actual structure variable name. In Figure 7.1b, the use of a tag name is eliminated and the rest of the definition and the structure declaration remain the same.
1. struct tagname {
2. datatype variablename;
3. datatype variablename;
4. .
5. .
6. } structurevariablename;
Figure 7.1a - The definition and declaration of a structure with the use of a tag name following the struct keyword.
1. struct {
2. datatype variablename;
3. datatype variablename;
4. .
5. .
6. } strucuturevariablename;
Figure 7.1b - The definition and declaration of a structure without the use of the tag name following the struct keyword.
1. struct tagname {
2. datatype variablename;
3. datatype variablename;
4. .
5. .
6. };
7. struct tagname structurevariablename;
Figure 7.1c - The definition and declaration of a structure with the use of the tag name following the struct keyword in both the definition and the declaration.
C++ STRUCTURE IS EQUIVALENT TO THE C STRUCTURE
In C, the name after the keyword struct indicates the structure tag that can be used later in the program with the keyword struct to declare a structure variable. However, in C++ the name after the keyword struct is considered a type and can be used to declare a structure variable. Therefore, when a structure variable is declared using C++, the struct keyword is no longer needed. Additionally, C++ structures can include functions as part of the structure. This introduces the concept of OOP and class, which is discussed in a later chapter.
In Figure 7.2a, notice the definition is exactly like that of Figure 7.1a. A structure variable declaration can always follow the definition of a structure in C and C++. In Figure 7.2b, an easier and more meaningful definition and declaration of a structure is given. The C++ declaration uses a tag name followed by the actual structure variable name. The reuse of the struct keyword is eliminated. This elimination leads to less redundancy. It isn’t necessary to retype the struct keyword because with C++ the tag name becomes the type of structure that you are declaring.
1. struct structuretype {
2. datatype variablename;
3. datatype variablename;
4. .
5. .
6. } structurevariablename;
Figure 7.2a - The C++ version of a structure. Notice that the definition is the same as that of Figure 7.1a. A structure can always be declared in this manner, whether in C or C++.
1. struct structuretype {
2. datatype variablename;
3. datatype variablename;
4. .
5. .
6. };
7. structuretype structurevariablename;
Figure 7.2b - A C++ version of a structure that uses the tagname as the type of structure to be declared. Line 7 shows the use of the tagname as the structure type.
The two examples that follow illustrate the differences between C and C++ structures. Figure 7.3a shows the C definition and declaration of a structure and 7.3b shows that of a C++ structure definition and declaration. Both examples define and declare the same type of structure. It is important to observe line 5 of Figure 7.3b, note the use of person, which is the type of structure defined, and is also used to declare an employee structure of type person.
1. struct persontag{
2. char name[20];
3. double salary;
4. };
5. struct persontag employee;
Figure 7.3a - The C version of a structure definition and declaration.
1. struct person{
2. char name[20];
3. double salary;
4. };
5. person employee;
Figure 7.3b - The C++ version of a structure definition and declaration.
C++ STRUCTURE AS A BETTER C STRUCTURE AND AS A CLASS
C++ is known to be superior to C. One reason for its superiority is that C++ simplifies the concepts of the C programming language. Some of these improvements are demonstrated in previous chapters with areas input and output (cin and cout of C++ versus scanf and printf of C) and the passing of parameters (pass by reference of C++ versus pass by pointer of C). Other major improvements are shown in the structure, such as:
- In C++, the name after the keyword struct defines the type of structure being defined, therefore, a tag name is not necessary. The use of a tag with C is an overhead particularly when a structure needs to be passed to a function. In C, the keyword typedef is used in conjunction with the structure to overcome this problem.
- In C++ a structure can contain functions related to the structure. This makes the structure a class. This transition to class is the gateway to Object-Oriented Programming (OOP). OOP can become tedious to learn but will be beneficial in the long run.
PROGRAMMING WITH STRUCTURES OR WITHOUT: PARALLEL ARRAYS
Programmer uses a structure to group related data under a common name. By doing so, all of the data is treated as one entity. Can you imagine a large program without a structure? A programmer without a structure has to remember, which scattered variables are related to each other. The other alternative is to use an index of parallel arrays to form a relationship between variables. For example name[ i ], phone[ i ], age[ i ] are related by the use of the same index, named i, for all the related variables. Figure 6.19a of Chapter 6 illustrates the use of parallel arrays: such as id[100], hoursworked[100], and hourlyrate[100]. Each value of i represents the ID, hours worked, and the hourly rate of one specific employee.
EXAMPLE OF C STRUCTURE
The examples of Figures 7.4a, b., and c. illustrate how C structures can be used in a program in various ways. Depending on the situation, one style may be preferable. The structures listed in the examples consist of three member variables: name, age, and salary. Each example program reads data into each variable and then displays the variable's value. The program examples also match the styles used in Figure 7.1a, b, and c respectively. Figure 7.4d shows the output of all three programs based on the same input data.
1. #include
2. using namespace std;
3. struct persontag {
4. char name[ 20 ];
5. int age;
6. float salary;
7. }employee;
8. main( ){
9. cout << " ENTER EMPLOYEE NAME: ";
10. cin >> employee.name;
11. cout << " ENTER EMPLOYEE AGE: ";
12. cin >> employee.age;
13. cout << " ENTER EMPLOYEE SALARY:";
14. cin >> employee.salary;
15. cout << " NAME IS " << employee.name s<< endl;
16. cout << "AGE IS " << employee.age << endl;
17. cout << " SALARY IS " << employee.salary << endl;
18. return 0;
19. }//MAIN
Figure 7.4a - The program illustrates the style used in Figure 7.1a to define and declare a C structure.
1. #include
2. using namespace std;
3. struct {
4. char name[ 20 ];
5. int age;
6. float salary; }employee;
7. main( ){
8. cout << "ENTER EMPLOYEE NAME: ";
9. cin >> employee.name;
10. cout << "ENTER EMPLOYEE AGE: ";
11. cin >> employee.age;
12. cout << "ENTER EMPLOYEE SALARY:";
13. cin >> employee.salary;
14. cout << " NAME IS " << employee.name << endl;
15. cout << "AGE IS " << employee.age << endl;
16. cout << " SALARY IS " << employee.salary << endl;
17. return 0;
18. }//MAIN
Figure 7.4b – The program illustrates the style used in Figure 7.1b to define and declare a C structure.
1. #include
2. using namespace std;
3. struct persontag {
4. char name[ 20 ];
5. int age;
6. float salary; };
7. struct persontag employee;
8. main( ){
9. cout << "ENTER EMPLOYEE NAME: ";
10. cin >> employee.name;
11. cout << "ENTER EMPLOYEE AGE: ";
12. cin >> employee.age;
13. cout << "ENTER EMPLOYEE SALARY:";
14. cin >> employee.salary;
15. cout << " NAME IS " << employee.name << endl;
16. cout << "AGE IS " << employee.age << endl;
17. cout << " SALARY IS " << employee.salary << endl;
18. return 0;
19. }//MAIN
Figure 7.4c – The program illustrates the style used in Figure 7.1c to define and declare a C structure.
ENTER EMPLOYEE NAME: Ebrahimi
ENTER EMPLOYEE AGE: 45
ENTER EMPLOYEE SALARY: 250000
NAME IS Ebrahimi
AGE IS 45
SALARY IS 250000
Figure 7.4d – The output of the programs of Figures 7.4a, b, and c, based on the same input data.
- #include <iostream>
- using namespace std;
- struct persontag {
- char name[ 20 ];
- int age;
- float salary; };
- struct persontag employee;
- main( ){
- cout << "ENTER EMPLOYEE NAME: ";
- cin >> employee.name;
- cout << "ENTER EMPLOYEE AGE: ";
- cin >> employee.age;
- cout << "ENTER EMPLOYEE SALARY:";
- cin >> employee.salary;
- cout << " NAME IS " << employee.name << endl;
- cout << "AGE IS " << employee.age << endl;
- cout << " SALARY IS " << employee.salary << endl;
- return 0;
- }//MAIN
Figure 7.4c - The program illustrates the style used in Figure 7.1c to define and declare a C structure.
ENTER EMPLOYEE NAME:Ebrahimi
ENTER EMPLOYEE AGE: 45
ENTER EMPLOYEE SALARY: 250000
NAME IS Ebrahimi
AGE IS 45
SALARY IS 250000
Figure 7.4d - The output of the programs of Figures 7.4a, b, and c, based on the same input data.
EXAMPLE OF C++ STRUCTURES
Figures 7.5a. and b. illustrates a C++ structure. Even though a C++ structure has its own style, any C structure shown above can be used in a C++ program. Since C++ is an improved C, it is recommended that you adhere to the C++ structure convention when using structures in a program.
The program examples listed next match the styles used in Figure 7.2a and b respectively. Figure 7.5c shows the output of the two programs based on the same input data.
1. #include
2. using namespace std;
3. struct person {
4. char name[ 20 ];
5. int age;
6. float salary; }employee;
7. main( ){
8. cout << " ENTER EMPLOYEE NAME: ";
9. cin >> employee.name;
10. cout << " ENTER EMPLOYEE AGE: ";
11. cin >> employee.age;
12. cout << " ENTER EMPLOYEE SALARY:";
13. cin >> employee.salary;
14. cout << " NAME IS " << employee.name << endl;
15. cout << " AGE IS " << employee.age << endl;
16. cout << " SALARY IS " << employee.salary << endl;
17. return 0;
18. }//MAIN
Figure 7.5a – The program illustrates the style used in Figure 7.2a to define and declare a C++ structure.
1. #include
2. using namespace std;
3. struct person {
4. char name[ 20 ];
5. int age;
6. float salary; };
7. person employee;
8. main( ){
9. cout << " ENTER EMPLOYEE NAME: ";
10. cin >> employee.name;
11. cout << " ENTER EMPLOYEE AGE: ";
12. cin >> employee.age;
13. cout << " ENTER EMPLOYEE SALARY:";
14. cin >> employee.salary;
15. cout << " NAME IS " << employee.name << endl;
16. cout << " AGE IS " << employee.age << endl;
17. cout << " SALARY IS " << employee.salary << endl;
18. return 0;
19. }//MAIN
Figure 7.5b – The program illustrates the style used in Figure 7.2b to define and declare a C++ structure
ENTER EMPLOYEE NAME: Ebrahimi
ENTER EMPLOYEE AGE: 45
ENTER EMPLOYEE SALARY: 250000
NAME IS Ebrahimi
AGE IS 45
SALARY IS 250000
Figure 7.5c – The output of the programs of Figures 7.5a and 7.5b, based on the same input data.
RECORD: ANOTHER NAME FOR A STRUCTURE
Some languages and databases call the structure a record, each record may contain several fields of data types such as an integer, float, character, bool (Boolean) or other types. The COBOL language frequently uses the concept of a record.
DOT OPERATOR: ACCESS MEMBERS OF A STRUCTURE
To refer to a variable of a structure, use the dot operator (character . period on the keyboard) between the structure name and the structure contained variable. For example, in Figure 7.5a, each of the variables listed below belongs to the structure named person.
- name is a 20 character long character array.
- age is an integer variable
- salary is a float variable
STRUCTURE INITIALIZATION
The data members of a structure can be initialized the following three ways:
1. At the time of declaration:
person employee = { "Ebrahimi", 35, 65000.00 };
Figure 7.6a shows an example program of a structure’s data elements that are initialized at declaration time.
1. #include
2. using namespace std;
3. struct person {
4. char name[ 20 ];
5. int age;
6. float salary; };
7. main( ){
8. person employee = { "Ebrahimi", 35, 350000.00 };
9. cout << " NAME IS " << employee.name << endl;
10. cout << " AGE IS " << employee.age << endl;
11. cout << " SALARY IS " << employee.salary << endl;
12. return 0;
13. }//MAIN
Figure 7.6a – The initialization of a structure’s data elements at structure declaration time.
2. Manually initializing the members ( You simply assign a value to the members of a structure):
employee.age = 35;
employee.salary = 350000.00;
How do we assign a name to a character array variable named name? There is no problem assigning a single character to a non-character array and adding it to the structure named person:
char initial;
Then the following line of code would assign the value of capital ‘A’ to the character variable named initial of the structure variable named employee:
employee.initial = 'A';
When full names need to be inserted into character arrays, the built-in function named strcpy( ) ( found in the header file #include ) must be used to copy the value of a name to the name variable. The following line of code accomplishes the task of initializing the name variable of the structure named employee to the value of "Ebrahimi".
strcpy( employee.name, "Ebrahimi" );
In C++ the addition of the STL (Standard Template Library) facilitates string assignment. If the library named string (not to be confused with string.h) is added using the following line of code:
#include
The character array of the person structure is replaced with a string data type declared as follows:
string name;
Then the following line of code assigns the name of Ebrahimi to the string variable named name:
employee.name = “Ebrahimi”;
The programs of Figures 7.6b and c show the manual initialization of a structures data elements. Figure 7.6b shows the initialization using the string.h library and the string copy (strcpy( ) built-in function ) and Figure 7.6c shows the use of the STL’s string
library. We will discuss the STL and strings in more detail in a later chapter.
1. #include
2. #include // string library old version
3. using namespace std;
4. struct person{
5. char name[ 20 ];
6. int age;
7. float salary; };
8. main( ){
9. person employee;
10. strcpy( employee.name , "Ebrahimi" );
11. employee.age = 35;
12. employee.salary = 350000;
13. cout << " NAME IS " << employee.name << endl;
14. cout << " AGE IS " << employee.age << endl;
15. cout << " SALARY IS " << employee.salary << endl;
16. return 0;
17. }//MAIN
Figure 7.6b - The manual initialization of a structure’s data elements. Also observe the use of the strcpy( )function of the string.h library to assign a name to a character array.
1. #include // new version of iostream with STL, not the .h version
2. #include // the STL string library new version
3. using namespace std; // needed when using the STL
4. struct person{
5. string name;
6. int age;
7. float salary;
8. };
9. main( ){
10. person employee;
11. employee.name = ”Ebrahimi”; // NO string copy function is needed
12. employee.age = 35;
13. employee.salary = 350000;
14. cout << " NAME IS " << employee.name << endl;
15. cout << " AGE IS " << employee.age << endl;
16. cout << " SALARY IS " << employee.salary << endl;
17. return 0;
18. }//MAIN
Figure 7.6c- The manual initialization of a structure’s data elements. Notice the use of the STL string library which eliminates the need for the strcpy( ) function to assign a name to a variable.
NAME IS Ebrahimi
AGE IS 35
SALARY IS 350000
Figure 7.6d - Output for Figures 7.6a, 7.6b, and 7.6c
3. Through the input routines:
cin >> employee.name >> employee.age >> employee.salary; // C++
scanf( "%s%d%f", &employee.name, &employee.age, &employee.salary ); // C
The program in Figure 7.6e shows the initialization of a structure’s variables using the C++ cin statement. The output is listed in Figure 7.6f.
1. #include
2. using namespace std;
3. struct person {
4. char name[ 20 ];
5. int age;
6. float salary; };
7. person employee;
8.
9. main() {
10. cout << "ENTER EMPLOYEE NAME: ";
11. cin >> employee.name;
12. cout << "ENTER EMPLOYEE AGE: ";
13. cin >> employee.age;
14. cout << "ENTER EMPLOYEE SALARY:";
15. cin >> employee.salary;
16. cout << "NAME IS " << employee.name << endl;
17. cout << "AGE IS " << employee.age << endl;
18. cout << "SALARY IS " << employee.salary << endl;
19. return 0;
20. }//MAIN
Figure 7.6e - The initialization of a structure’s variables using the cin statement of C++.
ENTER EMPLOYEE NAME: Ebrahimi
ENTER EMPLOYEE AGE: 35
ENTER EMPLOYEE SALARY: 350000
NAME IS Ebrahimi
AGE IS 35
SALARY IS 350000
Figure 7.6f – Sample output of the program in Figure 7.6e.
ARRAY OF STRUCTURES
Several occurrences of the same structure, an array of structures, may be needed to store or retrieve information for a multitude of people. For example, if there are several employees in a department, each employee should have an occurrence of the structure. The index used to move through the array of structures will point to a specific occurrence in the array of structures. In Figure 7.7a, each employee entered has a location, or occurrence, which contains the employee’s name and phone number.
1. #include< iostream>
2. using namespace std;
3. struct person{
4. char name[ 20 ];
5. char phone[ 16 ]; };
6. main( ){
7. person employee[ 100 ];
8. int n = 0;
9. cout << "Enter an employee name and phone number (Ctrl + Z to end): ";
10. while( cin >> employee[ n ].name >> employee[ n ].phone ) {
11. n++;
12. cout << "Enter an employee name and phone number (Ctrl + Z to end): ";
13. }//WHILE
14. cout << endl << endl << endl;
15. for( int i = 0 ; i < n ; i++ ){
16. cout << "employee.name[" << i << " ] = " << employee[ i ].name << endl;
17. cout << "employee.phone[ " << i << " ] = " << employee[ i ].phone
18. << endl << endl; }//FOR
19. return 0;
20. }//MAIN
Figure 7.7a - Program showing the use of an array of structures to package together information related to each individual employee.
Enter an employee name and phone number (Ctrl + Z to end):
Ebrahimi 1(516)555-1212
Enter an employee name and phone number (Ctrl + Z to end):
Ehrlinger 1(631)555-1212
Enter an employee name and phone number (Ctrl + Z to end):
Smith 1(718)555-1212
Enter an employee name and phone number (Ctrl + Z to end):
Jones 1(212)555-1212
Enter an employee name and phone number (Ctrl + Z to end):
employee.name[ 0 ] = Ebrahimi
employee.phone[ 0 ] = 1(516)555-1212
employee.name[ 1 ] = Ehrlinger
employee.phone[ 1 ] = 1(631)555-1212
employee.name[ 2 ] = Smith
employee.phone[ 2 ] = 1(718)555-1212
employee.name[ 3 ] = Jones
employee.phone[ 3 ] = 1(212)555-1212
Figure 7.7b - Output based on sample data provided to the program of Figure 7.7a.
ARRAY OF STRUCTURES VERSUS AN ARRAY OF ARRAYS
What is the alternative to an array of structures? A choice is several arrays of arrays. In fact, early languages did not have the ability to create structure arrays. The array of arrays (multi-dimensional array) was a means to represent different but related data types. Disadvantages of an array of arrays versus an array of structures are:
- Several variable names and declarations are scattered throughout a program. As a result, the program becomes difficult to read and comprehend.
- In order to pass the arrays to functions every array needed must be passed to the function when using an array of arrays. While using an array structure, just the name of the structure is sufficient. Then, within the function, the appropriate data members can be accessed.
POINTER TO A STRUCTURE
It is possible to declare a variable that points to a structure just as an ordinary pointer points to an integer, double or character variable. A pointer to a structure is used as a way to change the value of a structure member variable when it is passed to a function. To access a member variable of a structure using a pointer to the structure, use one of the following syntaxes:
(*ptr).memberdata; // note the parenthesis around the pointer variable
ptr->memberdata;
The above two lines accomplish the same task and allow for reading or writing of values from or to the structure member variables. You may ask, "Where did the arrow operator (consisting of a minus sign followed by a greater than sign) come from?". The arrow operator de-references a pointer so that the value located at the memory address represented by the pointer may be accessed. Since the dot operator has precedence over the de-reference operator ( * ) the pointer named ptr must be de-referenced before the memberdata variable can be accessed. Parentheses force the pointer, named ptr, to be de-referenced first. Then the dot operator can be used to access the memberdata variable. The choice of which syntax to use is based on style; however, the use of the arrow operator reduces keystrokes and gives a less cryptic feel.
Understanding these concepts can be difficult. In a future chapter pointers will be discussed in greater detail.
PASSING A C/C++ STRUCTURE TO A FUNCTION
By default, in C/C++, parameters are passed to a function by value. This means that any change to the value of a parameter's variable will not alter the original value of the variable. In other words, the change to the variable of the called function will not affect the value of the variable of the calling function. Therefore, a structure variable will be passed to a function by value just like any other integer or float variable. When there is a need to change a value or values of a structure data member, C's pass by pointer or C++ pass by reference is used. The program listed in Figure 7.8a shows a simple pass by value of a structure to a function. The output is shown in figure 7.8b.
The program listed in Figure 7.8c illustrates C’s pass by pointer while Figure 7.8d illustrates the C++ pass by reference. The identical output based on the same input to both programs is shown in Figure 7.8e.
Figure 7.8a - Passing a structure by value.
employee.name = Ebrahimi
employee.phone = 1(516)555-1212
Figure 7.8b - Output of the program of figure 7.8a.
1. #include
2. #include
3. using namespace std;
4. struct person{
5. char name[ 20 ];
6. char phone[ 16 ]; };
7. // function prototype
8. void printfromstruct( person );
9. main( ){
10. person employee;
11. strcpy( employee.name, "Ebrahimi " );
12. strcpy( employee.phone, "1(516)555-1212 " );
13. printfromstruct( employee );
14. return 0;
15. }//MAIN
16. void printfromstruct( person employee ){
17. // Notice there is no need to pass the person structure by pointer
18. // or by reference. No data is being changed, rather data is just
19. // being printed to the screen.
20. cout << "employee.name = " << employee.name << endl;
21. cout << "employee.phone = " << employee.phone << endl;
22. }//PRINTFROMSTRUCT
Figure 7.8a - Passing a structure by value.
employee.name = Ebrahimi
employee.phone = 1(516)555-1212
Figure 7.8b - Output of the program of figure 7.8a.
1. #include
2. using namespace std;
3. struct person{
4. char name[ 20 ];
5. char phone[ 16 ]; };
6. // function prototype
7. // The function prototype below tells the compiler that later in the program a
8. // function named readtostruct will be called and defined that will not return a
9. // a value, but expects the memory address of a person structure. The name of
10. // the variable that will be used as the pointer to person does not have to be
11. // defined at this time. The compiler just wants to know that a structure
12. // pointer is coming to the called function.
13. void readtostruct( person* );
14. main( ){
15. person employee;
16. readtostruct( &employee ); // send the memory address of employee
17. cout << "employee.name = " << employee.name << endl;
18. cout << "employee.phone = " << employee.phone << endl;
19. return 0;
20. }//MAIN
21. void readtostruct( person *employee){
22. // Notice the use of the arrow operator( -> ) to access a structures
23. // member when a pointer to a structure is used. Here the parameter
24. // name of the pointer to the person structure must be declared in the
25. // functions header as it will be accessed in the function definition.
26. cout << "Enter an employee name: ";
27. cin >> employee->name;
28. cout << "Enter an employee phone number: ";
29. cin >> employee->phone;
30. }//READTOSTRUCT
Figure 7.8c – This program shows the C version of passing a structure by pointer.
1. #include
2. using namespace std;
3. struct person{
4. char name[ 20 ];
5. char phone[ 16 ]; };
6. // function prototype
7. void readtostruct( person& );
8. main( ){
9. person employee;
10. readtostruct( employee );
11. cout << "employee.name = " << employee.name << endl;
12. cout << "employee.phone = " << employee.phone << endl;
13. return 0;
14. }//MAIN
15. void readtostruct( person &employee){
16. cout << "Enter an employee name: ";
17. cin >> employee.name;
18. cout << "Enter an employee phone number: ";
19. cin >> employee.phone;
20. }//READTOSTRUCT
Figure 7.8d – This program shows the C++ version of passing a structure by reference.
Enter an employee name: Ebrahimi
Enter an employee phone number: 1(516)555-1212
employee.name = Ebrahimi
employee.phone = 1(516)555-1212
Figure 7.8e – Sample output of the programs in Figures 7.8c and 7.8d based on the same input parameters.
CHANGING A MEMBER VALUE OF A STRUCTURE IN A FUNCTION
The address of a structure must be sent to a function in order to change the value of a structure’s members. As seen in the prior section, this can be accomplished in two ways: pass by pointer or pass by reference. The programs illustrated in Figures 7.9a and b respectively illustrate this. Once again the output of both programs is identical and displayed in Figure 7.9c.
It is important to note that in both of the following examples, the employee structure member variables are initially set. After the function named changevalues( ) is called, the values held by the employee structure have changed.
1. #include
2. using namespace std;
3. struct person {
4. int age;
5. float salary; };
6. //function prototype
7. void changevalue( person* );
8. main( ){
9. person employee;
10. employee.age = 30;
11. employee.salary = 65000.00;
12. changevalue( &employee );
13. cout << "employee.age = " << employee.age << endl;
14. cout << "employee.salary = " << employee.salary << endl;
15. return 0;
16. }//MAIN
17. void changevalue( person *p ){
18. // p is an alias for employee. p has the same memory address as the
19. // employee variable listed in main and therefore has access to change
20. // the values of the member variables of the employee structure.
21. cout << "changevalue function -> Changing structure values…" << endl;
22. p->age = 32;
23. p->salary = 72000.00;
24. }//CHANGEVALUE
Figure 7.9a - C style pass by pointer of a structure. The function changevalue changes the initial member variables of the employee structure.
1. #include
2. using namespace std;
3. struct person {
4. int age;
5. float salary; };
6. //function prototype
7. void changevalue( person& );
8. main( ){
9. person employee;
10. employee.age = 30;
11. employee.salary = 65000.00;
12. changevalue( employee );
13. cout << "employee.age = " << employee.age << endl;
14. cout << "employee.salary = " << employee.salary << endl;
15. return 0;
16. }//MAIN
17. void changevalue( person &p ){
18. // p is an alias of employee with direct access to the real values
19. // of the employee structure.
20. cout << "changevalue function -> Changing structure values…" << endl;
21. p.age = 32;
22. p.salary = 72000.00;
23. }//CHANGEVALUE
Figure 7.9b - C++ style pass by reference of a structure. The function changevalue changes the initial member variables of the employee structure.
changevalue function -> Changing structure values...
employee.age = 32
employee.salary = 72000
Figure 7.9c – Output of the programs in Figures 7.9a and 7.9b.
RETURNING A STRUCTURE
A function can return a structure data member or return an entire structure. In the program listed in Figure 7.10a, after data has been assigned to structure member variables, the entire structure is returned to the function main. The output of the program can be seen in Figure 7.10b.
1. #include
2. using namespace std;
3. struct person {
4. char name[ 20 ];
5. int age;
6. float salary; };
7. // function prototype
8. person readtostruct( person );
9.
10. void main( ){
11. person employee;
12. employee = readtostruct( employee );
13. cout << "employee.name = " << employee.name << endl;
14. cout << "employee.age = " << employee.age << endl;
15. cout << "employee.salary = " << employee.salary << endl;
16. }//MAIN
17.
18. person readtostruct( person employee ){
19. cout << "Enter a name: ";
20. cin >> employee.name;
21. cout << "Enter an age for the name: ";
22. cin >> employee.age;
23. cout << "Enter a salary for the name: ";
24. cin >> employee.salary;
25. return employee;
26. }//READTOSTRUCT
Figure 7.10a – The program above illustrate the ability to return not only the standard C/C++ data type, but also user defined data types such as structures.
Enter a name: Ebrahimi
Enter an age for the name: 40
Enter a salary for the name: 325000
employee.name = Ebrahimi
employee.age = 40
employee.salary = 325000
Figure 7.10b – The output of Figure 7.10a.
Figure 7.10b - The output of Figure 7.10a.
typedef: CREATING A SHORTHAND
As the name typedef suggests it defines a type from an existing one, or in other words creates an alias. typedef is useful when the C structure is passed to a function. The use of typedef reduces the amount of typing the programmer does.
typedef struct persontag{
char name[20];
double salary;
} person;
person employee;
However, the use of typedef in C++ structures has become limited because the name of the structure is a type in C++ and can be used in the declaration of a structure. Another use of the typedef definition is to replace a lengthy definition or to provide a meaningful name to a type as illustrated below.
typedef unsigned long int ULI;
ULI x;
ULI replaces the long unsigned int. In the next example, time_t is a shorthand type of a long. Therefore the variable timeseconds can be declared as a type of time_t, which in reality is type long.
typedef long time_t;
time_t timeseconds;
EXAMPLE OF C++ STRUCTURE
A C++ structure differs from a C structure in two ways:
1. The name after the struct keyword can be used for a declaration as shown below.
struct coordinate {
int x;
int y;
};
coordinate center;
2. The structure may contain functions. A brief introduction to functions within structures will come later in the chapter.
PREDEFINED LIBRARY OF USEFUL C STRUCTURES
There are various structures that are pre-defined and are part of the C libraries that are worth remembering and using. Among the C structures are time and date. Before using these structures within a program, their respective libraries must be included. For example in order to use the time functions, the #include <ctime>header must be included at the top of your source code.
In order to use the time structure, the member variables of the time structure should be understood. Table 7.1 shows the time structure member variables.
System Defined Time Structure Variable Members
|
Member Variable
|
Description
|
tm_sec
|
Holds the second of the time contained by the system clock ( 0 - 59 ).
|
tm_min
|
Holds the minute of the time contained by the system clock. ( 0 - 59 ).
|
tm_hour
|
Holds the hour of the time contained by the system clock. ( 0 - 23 ).
|
tm_mday
|
Holds the current day in the current month ( 1 - days in month ).
|
tm_wday
|
Holds the number of the day of the week ( 0 - 6, Sunday - Saturday ). The day of the week is zero based. To see the correct day of the week the following would be necessary:
tm_wday + 1
|
tm_yday
|
Holds the day of year. ( 0 - 364, 365 in leap years ). The day of the year is zero based. If the date was February 1, in order to see the day as the 32nd day of the year the following would be necessary:
tm_yday + 1
|
tm_mon
|
Holds the current month of the year ( 0 - 11, January - December ). The number of the month is zero based. If the current month were December, in order to see December as the 12th month of the year the following would be necessary:
tm_mon + 1
|
tm_year
|
Holds the number of years from the year 1900. Therefore if the year was 2002, in order obtain the year 2002, the following would be necessary:
tm_year + 1900.
|
Table 7.1 - The time structure variable members that C++ uses to give programmers access to the system time.
The program listed in Figure 7.11 shows an example of how to access the system clock using C/C++.
1. #include
2. #include /*** Location of time functions. ***/
3. using namespace std;
4. main( ){
5. struct tm *timeptr;
6. time_t timeval; // unsigned long integer
7. time(&timeval); // brings back time value in seconds
8. timeptr = localtime(&timeval);
9. cout << " DATE: "
10. << " MONTH " << timeptr->tm_mon + 1 // month is zero based
11. << " DAY " << timeptr->tm_mday
12. << " YEAR " << timeptr->tm_year + 1900 << endl;
13. cout << " LOCAL TIME: "
14. << " HOURS " << timeptr->tm_hour
15. << " MINUTES " << timeptr->tm_min
16. << " SECONDS " << timeptr->tm_sec <tm_mday
18. << endl << " DAY OF THE WEEK: " << timeptr->tm_wday + 1
19. << endl << " DAY SINCE JANUARY 1: "
20. << timeptr->tm_yday + 1 << endl;
21. timeptr = gmtime (&timeval);
22. cout << " GREENWICH MEAN TIME: "
23. << timeptr->tm_hour << ":" << timeptr->tm_min
24. << ":" << timeptr->tm_sec <
Figure 7.11a – The above program demonstrates the use of the C predefined time structure.
DATE: MONTH 7 DAY 15 YEAR 2000
LOCAL TIME: HOURS 0 MINUTES 59 SECONDS 39
DAY OF THE CURRENT MONTH: 15
DAY OF THE WEEK: 7
DAY SINCE JANUARY 1: 197
GREENWICH MEAN TIME: 4:59:39
Figure 7.11b - Sample output of the program listed in Figure 7.11a.
STRUCTURE WITHIN STRUCTURE ( NESTED )
A structure may contain one or more other structures. For example you may define a structure called date, which contains another structure called time. The structure date may consist of the month, day, and year. Similarly, the time structure may consist of hour, minutes, and seconds. Figure 7.12a illustrates nested structures. In the example, the time structure is defined within the date structure making the time structure a member variable of the date structure.
1. #include
2. using namespace std;
3. struct date{
4. int day;
5. int month;
6. int year;
7. struct time {
8. int hour;
9. int minutes;
10. int seconds;
11. }clock;
12. };
13. main( ){
14. // declaration of the structure
15. date advisingappointment;
16. // assignment of the structure
17. advisingappointment.month = 7;
18. advisingappointment.day = 12;
19. advisingappointment.year = 2000;
20. advisingappointment.clock.hour = 10;
21. advisingappointment.clock.minutes = 30;
22. advisingappointment.clock.seconds = 30;
23. // displaying of the structures information
24. cout << "You have an appointment for advisement at the following time: "
25. << endl << advisingappointment.month << "/"
26. << advisingappointment.day << "/" << advisingappointment.year
27. << " at " << advisingappointment.clock.hour << ":"
28. << advisingappointment.clock.minutes << ":"
29. << advisingappointment.clock.seconds << "." << endl;
30. return 0; }//MAIN
Figure 7.12a -Program showing the declaration and use of a nested structure.
You have an appointment for advisement at the following time:
7/12/2000 at 10:30:30.
Figure 7.12b - Output of the program listed in Figure 7.12a, the nesting of structures.
In the preceding example of Figure 7.12a, notice how a structure member variable is accessed through the use of the dot operator ( a period on the keyboard ). The following line assigns the value of seven to the month member value of the advisingappointment structure:
advisingappointment.month = 7;
advisingappointment.month = 7;
Next, notice that for the nested structure, defined as time and declared as clock, a dot operator is needed to access the clock member variables. For example, in order to assign an hour to the clock structure nested within the date structure, we must use the advisingappointment structure variable name followed by the dot operator. After doing so, we can access the date structure member variables, which include day, month, year, and the nested structure defined as time, and declared as clock. Therefore, in order to access the member variables of the declared structure named clock, another dot operator must be used followed by the structure variable clock. Finally, access is granted to the three variables of the clock structure which include hour, minutes, and seconds. The following line of code sets the hour variable to 10:
advisingappointment.clock.hour = 10;
SELF-REFERENTIAL STRUCTURE
There are times when a structure member variable is used to reference a structure of the same type, this is called a self-referential variable. This concept will be expanded upon in the Chapter on Data Structures later in the book. The next example shows the basics needed to create a dynamic data type called the linked list. The next member variable is a pointer that points to the next node of the same structure.
struct node {
int info;
node *next;
} dynamicarray;
UNIONS
Union is an aggregate of elements of usually different data types such as int, double, char or even other unions (nested unions). However, unlike the structure, members of the union share the same memory location, that of the largest type of all of the members of the union. The following definition and declaration of a union shows two union member variables named fulltimesalary and parttimehoursworked. During the execution of the program, only one of the variables of the union may hold data.
union employeestatus{
double fulltimesalary;
int parttimehoursworked;
};
DIFFERENCE BETWEEN UNION AND STRUCTURE
A union is the same as a structure in that several member variables can be defined. You can think of a union as a structure that doesn’t require all members to be present at all times, only one member is needed. The compiler will set aside the memory for the largest field so that every other field can fit within the one memory location. A union is known as variant record in the Pascal language. Therefore, aside from saving memory, it also helps the programmer realize that only one member will be used at a time. Figure 7.13a shows an example of the use of a union.
1. #include
2. using namespace std;
3. union employeestatus{
4. double fulltimesalary;
5. int parttimehoursworked; }employee;
6. main( ){
7. char status;
8. cout << "Enter an employee status ( F or P ): ";
9. cin >> status;
10. if(status == 'F'){
11. employee.fulltimesalary = 35000.00;
12. cout << "Full time salary = " << employee.fulltimesalary << endl;
13. }//IF
14. else if(status == 'P'){
15. employee.parttimehoursworked = 20;
16. cout << "Part time salary = " << employee.parttimehoursworked << endl;
17. }//ELSE IF
18. else cout << "error" <
Figure 7.13a - The above program shows the declaration and use of a union.
Enter an employee status ( F or P ): F
Full time salary = 35000
Enter an employee status ( F or P ): P
Part time salary = 20
Enter an employee status ( F or P ): L
error
Figure 7.13b – Output of Figure 7.13a.
PUBLIC AND PRIVATE ACCESS OF A STRUCTURE
A key issue to working with a structure in C++ is the accessibility of data to the outside user. By default, access to a member of a structure is public which means that the main program and all other functions can access and change a structure’s member data. The keyword public can be used to explicitly denote public access. However, in order to restrict the access of the structure member to the outside of a structure the keyword private can be used as follows:
struct person {
private:
char name[20];
double salary;
public:
void setname( char [ ] );
char* getname( void );
void setsalary( double );
double getsalary( void );
};
The above structure with the data members name and salary are only accessible by using the member functions setname(), getname(), setsatlary(), and getsalary(). The keyword public preceding the functions in the above structure indicates that the entire program can access the functions. Therefore, any change to the private data has to be done through the structure’s associated functions, and not through direct access of the data through the dot operator.
BUNDLE FUNCTIONS TO DATA MEMBERS
Data and functions can be scattered and declared here and there throughout a program, however, by placing them together we provide meaning and relationship. It would be difficult for a programmer to relate which data goes together and which functions go with the appropriate data. The concept of structures bundle the related data, with the functions necessary, to handle the tasks associated with the data. The example in Figure 7.14a demonstrates the use of the private and public data and functions respectively.
1. #include < iostream>
2. #include < string.h >
3. using namespace std;
4. struct person{
5. private:
6. char name [20];
7. double salary;
8. public:
9. void setname( char[ ] );
10. char* getname( void );
11. void setsalary( double );
12. double getsalary( void );
13. };
14. void person::setname( char n[ ] ){
15. strcpy( name, n ); }//SETNAME
16. char* person::getname( void ){
17. return name; }//GETNAME
18. void person::setsalary( double s ){
19. salary = s; }//SETSALARY
20. double person::getsalary( void ){
21. return salary; }//GETSALARY
22. main( ){
23. person employee;
24. employee.setname( "Ebrahimi" );
25. employee.setsalary( 300000.00 );
26. cout << employee.getname( ) << " salary is "
27. << employee.getsalary( ) << "." << endl;
28. return 0; }//MAIN
Figure 7.14a – The program demonstrates the use of the keywords public and private within the structure as an illustration of data encapsulation. The program above is the first step toward OOP programming.
Ebrahimi salary is 300000.
Figure 7.14b - Output of the program listed in Figure 7.14a.
Although the syntax to the program listed in Figure 7.14a may seem confusing, the program provides the first serious step toward OOP. OOP combines data variables with functions to encapsulate data. With private structure data members, public functions need to be utilized to set and get data members.
Do not be concerned with the syntax provided in Figure 7.14a, just try to understand the concepts of private and public. If you can nail down these concepts now, the transition to OOP will be much smoother.
C++ STRUCTURE AND DATA ENCAPSULATION
The C++ structure encapsulates data and its related functions (methods) as a unit under a name that can be accessed publicly by default. Encapsulation is one of the fundamental concepts of OOP programming and will be discussed in further detail in the Chapter on Class Programming.
STRUCTURE TOPICS NOT COVERED HERE
A structure may contain many members thus creating a tedious job when inputting, assigning, and outputting every structure member variable. There is a way to handle all of these tasks at once by using operator and function overloading, which will be discussed, in a later chapter.
In this chapter we briefly discussed self-referential structures. These structures are the backbone of dynamic data structures. Data Structures will be discussed in a later chapter.
REVISITING THE PAYROLL PROGRAM WITH THE STRUCTURE
Located at the end of Chapter 6, in Figure 6.20a, is the complete Payroll Program that incorporated functions along with the concept of arrays. The program uses parallel arrays to keep track of an employee’s information such as hours worked, gross pay, and net pay. In each parallel array, the value of index i represents a specific employee. If the value of i is equal to zero ( 0 ), then we understand that for each array, the index zero will refer to the first employee. Therefore we can relate the array location of id[0], hoursworked[0], and hourlyrate[0] to the same employee even though each array represents and stores a different type of data.
Although all the parallel arrays store different types of data, all of the data stored in these arrays is related. An employee’s ID is not the same as an employee’s hours worked or hourly rate, however, each of these variables make up elements, or attributes, of a single employee’s record. Looking back to Figure 6.20a, notice multiple arrays are sent as parameters to functions for processing. The program is cluttered with multiple function parameters.
With the introduction of the structure, Figure 7.15a shows how better organized the Payroll Program becomes with the grouping of all related variables. Notice that there are no more than two parameters for each function call, a far cry from the program of Figure 6.20a. The input file and output are listed in Figure 7.15b and c respectively.
1. #include
2. #include // file input output stream
3. using namespace std;
4. struct person{
5. long int id;
6. int hoursworked;
7. int overtimehours;
8. int regularhours;
9. float hourlyrate;
10. float regularpay;
11. float overtimepay;
12. float grosspay;
13. float taxrate;
14. float taxamount;
15. float netpay; }; // structure declaration
16. int readalldata( person[ ], const int ); // function prototypes
17. void findovertimehours( person[ ], int );
18. void findovertimepay( person[ ], int );
19. void findregularhours( person[ ], int );
20. void findregularpay( person[ ], int );
21. void findgrosspay( person[ ], int );
22. void findtaxrate( person[ ], int );
23. void findtaxamount( person[ ], int );
24. void findnetpay( person[ ], int );
25. void printalldata( person[ ], int );
26. int main( ){
27. const int MAXSIZE = 100; // for maximum of 100 employees
28. int n; //declaration of variables
29. person employee[ MAXSIZE ];
30. n = readalldata( employee, MAXSIZE ); //functions calls
31. findovertimehours( employee, n );
32. findovertimepay( employee, n );
33. findregularhours( employee, n );
34. findregularpay( employee, n );
35. findgrosspay( employee, n );
36. findtaxrate( employee, n );
37. findtaxamount( employee, n );
38. findnetpay( employee, n );
39. printalldata( employee, n );
40. return 0;
41. }//MAIN
Figure 7.15a ( Part 1 ) – The Payroll Program using an array of structures and function calls.
42. // function definitions
43. int readalldata( person emp[ ], int n ){
44. ifstream fin( "payroll.in" );
45. n = 0;
46. while( fin >> emp[ n ].id >> emp[ n ].hoursworked >> emp[ n ].hourlyrate ){
47. n++; }//WHILE
48. fin.close( );
49. return n;
50. }//READALLDATA
51. void findovertimehours( person emp[ ], int n ){
52. for( int i = 0 ; i < n ; i++){
53. if( emp[ i ].hoursworked > 40 )
54. emp[ i ].overtimehours = emp[ i ].hoursworked - 40;
55. else
56. emp[ i ].overtimehours = 0;
57. }//FOR
58. }//FINDOVERTIMEHOURS
59. void findovertimepay( person emp[ ], int n ){
60. for( int i = 0 ; i < n ; i++){
61. emp[ i ].overtimepay = emp[ i ].overtimehours * emp[ i ].hourlyrate * 1.5;
62. }//FOR
63. }//FINDOVERTIMEPAY
64. void findregularhours( person emp[ ], int n ){
65. for( int i = 0 ; i < n ; i++){
66. if( emp[ i ].hoursworked > 40 ) emp[ i ].regularhours = 40;
67. else emp[ i ].regularhours = emp[ i ].hoursworked;
68. }//FOR
69. }//FINDREGULARHOURS
70. void findregularpay( person emp[ ], int n ){
71. for( int i = 0 ; i < n ; i++ ){
72. emp[ i ].regularpay = emp[ i ].regularhours * emp[ i ].hourlyrate;
73. }//FOR
74. }//FINDREGULARPAY
75. void findgrosspay( person emp[ ], int n ){
76. for( int i = 0 ; i < n ; i++){
77. emp[ i ].grosspay = emp[ i ].regularpay + emp[ i ].overtimepay;
78. }//FOR
79. }//FINDGROSSPAY
Figure 7.15a ( Part 2 ) - The Payroll Program using an array of structures and function calls.
80. void findtaxrate( person emp[ ], int n ){
81. for( int i = 0 ; i < n ; i++){
82. if( emp[ i ].grosspay > 4000.00 ) emp[ i ].taxrate = 0.40;
83. else if( emp[ i ].grosspay > 3000.00 ) emp[ i ].taxrate = 0.30;
84. else if( emp[ i ].grosspay > 1000.00 ) emp[ i ].taxrate = 0.20;
85. else emp[ i ].taxrate = 0.10;
86. }//FOR
87. }//FINDTEXRATE
88. void findtaxamount( person emp[ ], int n ){
89. for( int i = 0 ; i < n ; i++){
90. emp[ i ].taxamount = emp[ i ].grosspay * emp[ i ].taxrate;
91. }//FOR
92. }//FINDTAXAMOUNT
93.void findnetpay( person emp[ ], int n ){
94. for( int i = 0 ; i < n ; i++){
95. emp[ i ].netpay = emp[ i ].grosspay - emp[ i ].taxamount;
96. }//FOR
97. }//FINDNETPAY
98. void printalldata( person emp[ ], int n ){
99. cout << "EMP ID" << "\t" << "HOURS" << "\t" << "RATE " << "\t "
100. << "OVERPAY " << "\t" << "GROSSPAY" << "\t" << "TAX " << "\t"
101. << " NETPAY " << endl;
102. for( int i = 0 ; i < n; i++){
103. cout << " " << emp[ i ].id << "\t " << emp[ i ].hoursworked
104. << "\t" << emp[ i ].hourlyrate << "\t " << emp[ i ].overtimepay
105. << "\t\t" << emp[ i ].grosspay << "\t\t" << emp[ i ].taxamount
106. << "\t " << emp[ i ].netpay << endl;
107. }//FOR
108. }//PRINTALLDATA
109. // end source code
Figure 7.15a ( Part 3 ) - The Payroll Program using an array of structures and function calls.
1234 43 100.00
2345 40 120.75
3456 35 110.50
4567 52 20.25
5678 34 45.00
6789 44 30.50
7890 31 115.25
8901 35 34.23
9012 38 70.75
1221 45 90.50
Figure 7.15b – Input file used for the program of Figure 7.15a named payroll.in.
EMP ID HOURS RATE OVERPAY GROSSPAY TAX NETPAY
1234 43 100 450 4450 1780 2670
2345 40 120.75 0 4830 1932 2898
3456 35 110.5 0 3867.5 1160.25 2707.25
4567 52 20.25 364.5 1174.5 234.9 939.6
5678 34 45 0 1530 306 1224
6789 44 30.5 183 1403 280.6 1122.4
7890 31 115.25 0 3572.75 1071.83 2500.92
8901 35 34.23 0 1198.05 239.61 958.44
9012 38 70.75 0 2688.5 537.7 2150.8
1221 45 90.5 678.75 4298.75 1719.5 2579.25
Figure 7.15c - Output based on input file named payroll.in shown in Figure 7.15b.
Finally, notice how an array of a structure defined as person and declared as employee makes the program more readable and understandable. Instead of having parallel arrays, we now have one array. Located within each structure array location, are the related employee attributes that make up the employee record. The index i now refers to a record, and each attribute of the record can be accessed with the dot operator.
CLOSING REMARKS AND LOOKING AHEAD
A C structure is a collection of related variables, possibly of different data types. Each of these data variables is called a member. A dot operator ( period character on the keyboard, . ) is used to refer to a member of a structure. A good example of a structure is an employee record, where all the information regarding an employee can be bundled together as one unit. With the introduction of the structure, data and functions are now intermingled. The functions of a structure act upon the member data of the structure. As a result, a programmer now needs to spend a considerable amount of time to structure and organize related data.
In the next chapter, pointers and strings, we will take an in depth tour of memory allocation and manipulation. We’ll also study the basic character array, also known as a string. Passing pointers to functions will be discussed in detail and will clear up any problems that have arisen while looking over the example programs of the past two chapters.
|