|As we begin the study of C++ and object oriented programming, a few comments are in order to help you get started. Since the field of object oriented programming is probably new to you, you will find that there is a significant amount of new terminology for you to grasp. This is true of any new endeavor and you should be warned not to be intimidated by all of the new concepts. We will add a few new topics in each chapter and you will slowly grasp the entire language.
Chapters one through four of this tutorial will concentrate on the non object oriented additions to C++. We will not begin the discussion of any object oriented programming techniques until chapter five.
EVEN COMMENTS ARE IMPROVED IN C++
Example program ------> CONCOM.CPP
Examine the file named CONCOM.CPP for an example of several new things in C++. We will take the new constructs one at a time beginning with the comments.
A C++ comment begins with the double slash "//", starts anywhere on a line, and runs to the end of that line where it is automatically terminated. The old method of comment definition used with ANSI-C can also be used with C++ as illustrated in lines 11 through 14, among other places in this program. The new method is the preferred method of comment definition because it is impossible to inadvertently comment out several lines of code. This can be done by forgetting to include the end of comment notation when using the older C method of comment notation. Good programming practice would be to use the new method for all comments and reserve the old method for use in commenting out a section of code during debugging since the two methods can be nested.
It would be well to caution you at this point however, that you should not use comments when the same sense of program definition can be obtained by using meaningful names for variables, constants, and functions. The careful selection of variable and function names can make nearly any code self documenting and you should strive to achieve this in your code.
THE KEYWORDS const AND volatile
There are two new keywords used in lines 9 through 11 which were not part of the original K&R definition of C, but are part of the ANSI-C standard. The keyword const is used to define a constant. In line 9 the constant is of type int, it is named START, and is initialized to the value 3. The compiler will not allow you to accidentally or purposefully change the value of START because it has been declared a constant. If you had a variable named STARTS in this program, the system would not allow you to slightly misspell STARTS as START and accidentally change it. The compiler would give you an error message so you could fix the error. Since it is not permissible to change the value of a constant, it is imperative that you initialize it when it is declared so it will have a useful value.
You will note that the keyword const is also used in the function header in line 23 to indicate that the formal parameter named data_value is a constant throughout the function. Any attempt to assign a new value to this variable will result in a compile error. This is a small thing you can add to your programs to improve the compiler's ability to detect errors for you.
The keyword volatile is also part of the ANSI-C standard but was not included in the original K&R definition of C. Even though the value of a volatile variable can be changed by you, the programmer, there may be another mechanism by which the value could be changed, such as by a hardware interrupt timer causing the value to be incremented. The compiler needs to know that this value may be changed by some external force when it optimizes the code. A study of code optimization methods is very interesting, but beyond the scope of this tutorial. Note that a constant can also be volatile, which means that you cannot change it, but the system can modify it through some hardware function.
Ignore the output statement given in line 25 for a few minutes. We will study it in some detail later in this chapter. If you are experienced in the K&R style of programming, you may find line 5 and 23 a little strange. This illustrates prototyping and the modern method of function definition as defined by the ANSI-C standard. Prototyping is optional in C but absolutely required in C++. For that reason, chapter 4 of this tutorial is devoted entirely to prototyping.
It would be advantageous for you to compile and execute this program with your C++ compiler to see if you get the same result as given in the comments at the end of the listing. One of the primary purposes of compiling it is to prove that your compiler is loaded and executing properly.
THE SCOPE OPERATOR
Example program ------> SCOPEOP.CPP
The example program named SCOPEOP.CPP illustrates another construct that is new to C++. There is no corresponding construct in either K&R or ANSI-C. This allows access to the global variable named index even though there is a local variable of the same name within the main() function. The use of the double colon in front of the variable name, in lines 11, 13, and 16, instructs the system that we are interested in using the global variable named index, defined in line 4, rather than the local variable defined in line 8.
The use of this technique allows access to the global variable for any use. It could be used in calculations, as a function parameter, or for any other purpose. It is not really good programming practice to abuse this construct, because it could make the code difficult to read. It would be best to use a different variable name instead of reusing this name, but the construct is available to you if you find that you need it sometime.
Be sure to compile and execute this program before proceeding on to the next example program where we will discuss the cout operator used in lines 10, 11, 15, and 16.
THE iostream LIBRARY
Example program ------> MESSAGE.CPP
Examine the example program named MESSAGE.CPP for our first hint of object oriented programming, even though it is a very simple one. In this program, we define a few variables and assign values to them for use in the output statements illustrated in lines 17 through 20, and in lines 23 through 26. cout is used to output data to the standard device, the monitor, but it works a little differently from our old familiar printf() function, because we do not have to tell the system what type we are outputting. Note that cout is not actually an output function, but we can sort of think of it as one until we fully define it later in this tutorial. For the time being, we will simply state that cout is an object used to send output data to the monitor.
C++, like the C language, has no input or output operations as part of the language itself, but defines the stream library to add input and output functions in a very elegant manner. A portion of the stream library is included in this program in line 2.
The operator <<, sometimes called the "put to" operator but more properly called the insertion operator, tells the system to output the variable or constant following it, but lets the system decide how to output the data. In line 17, we first tell the system to output the string, which it does by copying characters to the monitor, then we tell it to output the value of index. Notice however, that we fail to tell it what the type is or how to output the value. Since we don't tell the system what the type is, it is up to the system to determine what the type is and to output the value accordingly. After the system finds the correct type, we also leave it up to the system to use the built in default as to how many characters should be used for this output. In this case, we find that the system uses exactly as many characters as needed to output the data, with no leading or trailing blanks, which is fine for this output. Finally, the newline character is output as a single character string, and the line of code is terminated with a semicolon.
When we told the cout object to output some data in line 17, we actually called two different functions because we used it to output two strings and a variable of type int. This is the first hint at object oriented programming because we simply broadcast a message to the system to print out a value, and let the system find an appropriate function to do so. We are not required to tell the system exactly how to output the data, we only tell it to output it. This is a very weak example of object oriented programming, and we will study it in much more depth later in this tutorial.
In line 18, we tell the system to output a different string, followed by a floating point number, and another string of one character, the newline character. In this case, we told it to output a floating point number without telling it that it was a floating point number, once again letting the system choose the appropriate output means based on its type. We did lose a bit of control in the transaction, however, because we had no control over how many significant digits to print before or after the decimal point. We chose to let the system decide how to format the output data.
The variable named letter is of type char, and is assigned the value of the uppercase X in line 14, then printed as a letter in line 19 because the cout object knows it is a character and outputs it accordingly
Because C++ has several other operators and functions available with streams, you have complete flexibility in the use of the stream output functions. You should refer to your compiler documentation for details of other available formatting commands. Because it is expected to be mandated by the upcoming ANSI-C++ standard, the cout and printf() statements can be mixed in any way you desire. However all compilers do not yet conform to this standard and some use different forms of buffering for the two kinds of output. This could result in scrambled output, but it should be easy for the student to repair the output in such a way that only one form is used, either the cout or the printf().
MORE ABOUT THE stream LIBRARY
The stream library was defined for use with C++ in order to add to the execution efficiency of the language. The printf() function was developed early in the life of the C language and is meant to be all things to all programmers. As a result, it became a huge function with lots of extra baggage, most of which is used by only a few programmers. By defining the special purpose stream library, the design of C++ allows the programmer to use full formatting capabilities, but only load what is needed for the current programming job. Although it is not all illustrated here, there is a full set of formatting functions available in the C++ stream library. Check your compiler documentation for the complete list.
Lines 23 through 26 illustrate some of the additional features of the stream library which can be used to output data in a very flexible yet controlled format. The value of index is printed out in decimal, octal, and hexadecimal format in lines 23 through 25. When one of the special stream operators, dec, oct, or hex, is output, all successive output will be in that number base. Looking ahead to line 30, we find the value of index printed in hex format due to the selection of the hexadecimal base in line 25. If none of these special stream operators are output, the system defaults to decimal format.
THE cin OPERATOR
In addition to the predefined stream object, named cout, there is a predefined cin stream object which is used to read data from the standard input device, usually the keyboard. The cin stream uses the >> operator, usually called the "get from" operator but properly called the extraction operator. It has most of the flexibility of the cout stream. A brief example of the use of the cin stream is given in lines 28 through 30. The special stream operators, dec, oct, and hex, also select the number base for the cin stream separately from the cout stream. If none is specified, the input stream also defaults to decimal.
In addition to the cout stream object and the cin stream object there is one more standard stream object, cerr, which is used to output to the error handling device. This device cannot be redirected to a file on some systems, like the output to the cout stream object can be. The three streams, cout, cin, and cerr, correspond to the stdout, the stdin, and the stderr stream pointers of the C programming language. Their use will be illustrated throughout the remainder of this tutorial.
The stream library also has file I/O capability which will be briefly illustrated in the next example program.
Be sure to compile and execute this program before going on to the next one. Remember that the system will ask you to enter an integer value which will be echoed back to the monitor, but changed to the hexadecimal base.
FILE STREAM OPERATIONS
Example program ------> FSTREAM.CPP
Examine the example program named FSTREAM.CPP for examples of the use of streams with files. We will be using a few C++ objects in this program but we hAve not yet studied them, so you will not understand them at this point. Don't spend too much time trying to understand them yet.
In this program a file is opened for reading, another for writing, and a third stream is opened to the printer to illustrate the semantics of stream operations on a file. Both input and output files are of type FILE in C programs, but the ifstream type is used for file input and the ofstream is used for output files. This is illustrated in lines 8 through 10 of this example program. Actually ifstream is a C++ class and infile is an object of that class as we will see later in this tutorial.
The only difference between the streams in the last program and the streams in this program is the fact that in the last program, the streams were already opened for us by the system. You will note that the stream object named printer is used in the same way we used the cout stream object in the last program. Finally, because we wish to exercise good programming practice, we close all of the files we have opened prior to ending the program.
This is our first example of object oriented programming because we are actually using objects in this program. The object named infile is told to open itself in line 17, then it is told to get one character at a time in line 44, and finally it is told to close itself in line 52. The "dot" notation is used with objects in a similar manner that structures are used in C. The name of the object is mentioned, followed by a "dot", and followed by the name of the action that the object is to execute. This terminology will be used in great profusion later in this tutorial, so don't worry about it at this time. The objects outfile and printer are manipulated in exactly the same manner.
For more information on the stream file I/O library, see Bjarne Stroustrup's book which is listed in the introduction to this tutorial, or refer to your compiler documentation. Don't worry too much about it yet, after you learn the terminology by studying the rest of this tutorial, you will be able to return to a personal study of the stream library, and profit greatly from the study.
Be sure to compile and execute this program. When you execute it, it will request a file to be copied. You can enter the name of any ASCII file that resides in the current directory.
Example program ------> VARDEF.CPP
Examine the file named VARDEF.CPP for a few more additions to the C++ language which aid in writing a clear and easy to understand program. In C++, as in ANSI-C, global and static variables are automatically initialized to zero when they are declared. The variables named index in line 4, and goofy in line 27 are therefore automatically initialized to zero. Of course, you can still initialize either to some other value if you so desire. Global variables are sometimes called external since they are external to any functions.
Automatic variables, those declared inside of any function, are not automatically initialized but will contain the value that happens to be in the location where they are defined, which must be considered a garbage value. The variable named stuff in line 8, therefore does not contain a valid value, but some garbage value which should not be used for any meaningful purpose. In line 11, it is assigned a value based on the initialized value of index and it is then displayed on the monitor for your examination.
THE C++ REFERENCE
Notice the ampersand in line 9. This defines another_stuff as a reference which is a new addition to C++. The reference should not be used very often, if ever, in this context, but this is a very simple example used to introduce the reference and discuss its use and operation. The reference is not the same as any other entity used in C because it operates like a self dereferencing pointer. Following its initialization, the reference becomes a synonym for the variable stuff, and changing the value of stuff will change the value of another_stuff because they are both actually referring to the same variable. The synonym can be used to access the value of the variable stuff for any legal purpose in the language. It should be pointed out that a reference must be initialized to reference some variable when it is defined or the compiler will respond with an error. Following initialization, the reference cannot be changed to refer to a different variable. The reference is difficult to discuss because we want to call it a reference variable, but it is not a variable since it cannot be changed. Whether we like the name or not it is simply called a reference.
The use of the reference in this way can lead to very confusing code, but it has another use where it can make the code very clear and easy to understand. We will study the proper use of the reference in chapter 4 of this tutorial.
DEFINITIONS ARE EXECUTABLE STATEMENTS
Coming from your background of C, you will find the statement in line 16 very strange, but this is legal in C++. Anyplace it is legal to put an executable statement, it is also legal to define a new variable because a data definition is an executable statement according to the definition of C++. In this case, we define the new variable named more_stuff and initialize it to the value of 13. It has a scope from the point where it is defined to the end of the block in which it is defined, so it is valid throughout the remainder of the main() program. The variable named goofy is defined even later in line 27.
It is significant that the variable is declared near its point of usage. This makes it easier to see just what the variable is used for, since it has a much more restricted scope of validity. When you are debugging a program, it is convenient if the variable declaration is located in close proximity to where you are debugging the code.
WHAT ABOUT definition AND declaration?
The words definition and declaration refer to two different things in C++, and in ANSI-C also for that matter. They really are different and have different meanings, so we should spend a little time defining exactly what the words mean in C++. A declaration provides information to the compiler about the characteristics of something such as a type or a function but it doesn't actually define any code to be used in the executable program. A definition, on the other hand, actually defines something that will exist in the executable program, either some useful variables, or some executable code. You are required to have one and only one definition of each entity in the program. In short, a declaration introduces a name into the program and a definition introduces some code and requires memory space to store something.
If we declare a struct, we are only declaring a pattern to tell the compiler how to store data later when we define one or more variables of that type. But when we define some variables of that type, we are actually declaring their names for use by the compiler, and defining a storage location to store the values of the variables. Therefore, when we define a variable, we are actually declaring it and defining it at the same time.
C permits multiple definitions of a variable in any given namespace, provided the definitions are the same and it generates only a single variable for the multiple definitions. C++, however, does not permit redefinition of a variable or any other entity for a very definite reason that we will discuss later.
We will refer to these definitions many times throughout the course of this tutorial so if this is not clear now, it will clear up later.
A BETTER for LOOP
Take careful notice of the for loop defined in line 20. This loop is a little clearer than the for loop that is available in ANSI-C, because the loop index is defined in the for loop itself. The scope of this loop index depends on how new your compiler is.
If your compiler is a little old, the scope of the loop index is from its definition to the end of the enclosing block. In this case its scope extends to line 32 since the closing brace in line 32 corresponds to the most recent opening brace prior to the definition of the variable. Since the variable is still available, it can be used for another loop index or for any other purpose which an integer type variable can legally be used for.
If your compiler is relatively new, the scope of the loop index is from its definition to the end of the loop. In this case its scope extends to line 25 because that is where the loop ends. This is a very new extension to the C++ language by the standards committee, and will only be available with the newest compilers.
Regardless of the age of your compiler, the variable named count2 is defined and initialized during each pass through the loop because it is defined within the block controlled by the for loop. Its scope is only the extent of the loop, lines 23 to 25, so that it is automatically deallocated each time the loop is completed. It is therefore defined, initialized, used and deallocated five times, once for each pass through the loop.
You will notice that the variable count2 is assigned a numerical value in line 23 but when it is printed out, a character value is actually output. This is because C++ is careful to use the correct type for output. If you have a very old compiler, it may output a numerical value here.
Finally, as mentioned earlier, the static variable named goofy is defined and automatically initialized to zero in line 27. Its scope is from the point of its definition to the end of the block in which it is defined, line 32.
Be sure to compile and execute this program.
Operator precedence is identical to that defined for ANSI-C so no attempt will be made here to define it. There is a small difference when some operators are overloaded which we will study later in this tutorial. Some of the operators act slightly different when overloaded than the way they operate with elements of the predefined language.
Do not worry about the previous paragraph, it will make sense later in this tutorial after we have studied a few more topics
- Write a program that displays your name and date of birth on the monitor three times using the cout stream object. Define any variables you use as near as possible to their point of usage.
- Write a program with a few const values and volatile variables and attempt to change the value of the constants to see what kind of error message your compiler gives you.
- Write a program that uses stream objects to interactively read in your birthday with three different cin statements. Print your birthday in octal, decimal, and hexadecimal notation just for the practice.
Example program ------> ENUM.CPP
Examine the file named ENUM.CPP for an example that uses an enumerated type variable. The enumerated type is used in C++ in a similar way that it was used in ANSI-C, but there are a lot of differences. The keyword enum is not required to be used again when defining a variable of that type, but it can be used if desired. The name game_result is defined as an enumerated type making the use of the keyword enum optional. However, it may be clearer for you to use the keyword when defining a variable in the same manner that it is required to be used in C, and you may choose to do so.
The example program uses the keyword enum in line 9, but omits it in line 8 to illustrate to you that it is indeed optional, but that is a trivial difference. There is a bigger difference in the way an enumerated type is used in C++. In C, the enumerated type is simply an int type variable, but in C++ it is not an int, but its own type. Mathematical operations can not be performed on it, nor can an integer be assigned to it. It cannot be incremented or decremented as it can be in C. In the example program, an integer is used as the loop index for the for loop because it can be incremented, then the value of the loop index named count is assigned to the enumerated variable by using a cast. The cast is required or a compile error is reported. The mathematical operations and the increment and decrement operators can be defined for the enumerated type, but they are not automatically available. Operator overloading will be studied later, and the last sentence will make much more sense at that time.
If you have an older compiler, the enumerated variable game_result can be used for the loop variable but your code would not be portable to a newer compiler.
The remainder of this program should be no problem for you to understand. After studying it, be sure to compile and execute it and examine the output.
A SIMPLE STRUCTURE
Example program ------> STRUCTUR.CPP
Examine the example program named STRUCTUR.CPP for an illustration using a very simple structure. This structure is no different from that used in ANSI-C except for the fact that the keyword struct is not required to be used again when defining a variable of that type. Lines 12 and 13 illustrate the definition of variables without the keyword, and line 14 indicates that the keyword struct can be included if desired. It is up to you to choose which style you prefer to use in your C++ programs.
Once again, be sure to compile and execute this program after studying it carefully, because the next example program is very similar but it introduces a brand new construct not available in standard C, the class.
A VERY SIMPLE CLASS
Example program ------> CLASS1.CPP
Examine the example program named CLASS1.CPP for our first example of a class in C++. This is the first class example, but it will not be the last, since the class is the major reason for using C++ over ANSI-C or some other programming language. You will notice the keyword class used in line 4, in exactly the same way that the keyword struct was used in the last program, and they are in fact very similar constructs. There is a definite difference, as we will see, but for the present time we will be concerned more with their similarities.
The word animal in line 4 is the name of the class, and when we define variables of this type in lines 13 through 15, we can either omit the keyword class or include it if desired as illustrated in line 15. In the last program, we declared 5 variables of a structure type, but in this program we declare 5 objects. They are called objects because they are of a class type. The differences are subtle, and as we proceed through this tutorial, we will see that the class construct is indeed very important and valuable. The class was introduced here only to give you a glimpse of what is to come later in this tutorial.
The class is a type which can be used to define objects in much the same way that a structure is a type that can be used to define variables. Your dog named King is a specific instance of the general class of dogs, and in a similar manner, an object is a specific instance of a class. It would be well to take note of the fact that the class is such a generalized concept that there are libraries of prewritten classes available in the marketplace. You can purchase classes which perform some generalized operations such as managing stacks, queues, or lists, sorting data, managing windows, etc. This is because of the generality and flexibility of the class construct.
The new keyword public in line 6, followed by a colon, is necessary in this case because the variables in a class are defaulted to a private type and we could not access them at all without making them public. Don't worry about this program yet, we will cover all of this in great detail later in this tutorial. Be sure to compile and run this example program to see that it does what we say it does with your compiler. Keep in mind that this is your first example of a class and it illustrates essentially nothing concerning the use of this powerful C++ construct.
THE FREE UNION OF C++
Example program ------> UNIONEX.CPP
Examine the program named UNIONEX.CPP for an example of a free union. In ANSI-C, all unions must be named in order to be used, but this is not true in C++. When using C++ we can use a free union, a union without a name. The union is embedded within a simple structure and you will notice that there is not a variable name following the declaration of the union in line 13. In ANSI-C, we would have to name the union and give a triple name (three names dotted together) to access the members. Since it is a free union, there is no union name, and the variables are accessed with only a doubly dotted name as illustrated in lines 20, 24, 28, and others.
You will recall that a union causes all the data contained within the union to be stored in the same physical memory locations, such that only one variable is actually available at a time. This is exactly what is happening here. The variable named fuel_load, bomb_load, and pallets are stored in the same physical memory locations and it is up to the programmer to keep track of which variable is stored there at any given time. You will notice that the transport is assigned a value for pallets in line 28, then a value for fuel_load in line 30. When the value for fuel_load is assigned, the value for pallets is corrupted and is no longer available since it was stored where fuel_load is currently stored. The observant student will notice that this is exactly the way the union is used in ANSI-C except for the way components are named.
The remainder of the program should be easy for you to understand, so after you study and understand it, compile and execute it.
C++ TYPE CONVERSIONS
Example program ------> TYPECONV.CPP
Examine the program named TYPECONV.CPP for a few examples of type conversions in C++. The type conversions are done in C++ in exactly the same manner as they are done in ANSI-C, but C++ gives you another form for doing the conversions.
Lines 10 through 17 of this program use the familiar "cast" form of type conversions used in ANSI-C, and there is nothing new to the experienced C programmer. You will notice that lines 10 through 13 are all the same. The only difference is that we are coercing the compiler to do the indicated type conversions prior to doing the addition and the assignment in some of the statements. In line 13, the int type variable will be converted to type float prior to the addition, then the resulting float will be converted to type char prior to being assigned to the variable c.
Additional examples of type coercion are given in lines 15 through 17 and all three of these lines are essentially the same.
The examples given in lines 19 through 26 are unique to C++ and are not valid in ANSI-C. In these lines the type coercions are written as though they are function calls instead of the more familiar "cast" method as illustrated earlier. Lines 19 through 26 are identical to lines 10 through 17.
You may find this method of type coercion to be clearer and easier to understand than the "cast" method and in C++ you are free to use either, or to mix them if you so desire, but your code could be very difficult to read if you indescriminantly mix them.
Be sure to compile and execute this example program.
Starting with the program ENUM.CPP, add the enumerated value of FORFEIT to the enumerated type game_result, and add a suitable message and logic to get the message printed in some way.
Add the variable height of type float to the class of CLASS1.CPP and store some values in the new variable. Print some of the values out. Move the new variable ahead of the keyword public: and see what kind of error message results. We will cover this error in chapter 5 of this tutorial
Because pointers are so important in C and C++, this chapter will review some of the more important topics concerning pointers. Even if you are extremely conversant in the use of pointers, you should not completely ignore this chapter because some new material unique to C++ is presented here.
Example program ------> POINTERS.CPP
Examine the program named POINTERS.CPP for a simple example of the use of pointers. This is a pointer review and if you are comfortable with the use of pointers, you can skip this example program completely.
A pointer in either ANSI-C or C++ is declared with an asterisk preceding the variable name. The pointer is then a pointer to a variable of that one specific type and should not be used with variables of other types. Thus pt_int is a pointer to an integer type variable and should not be used with any other type. Of course, an experienced C programmer knows that it is simple to coerce the pointer to be used with some other type by using a cast, but he must then assume the responsibility for its correct usage.
In line 12 the pointer named pt_int is assigned the address of the variable named pig and line 13 uses the pointer named pt_int to add the value of dog to the value of pig because the asterisk dereferences the pointer in exactly the same manner as standard C. Figure 3-1 is a graphical representation of the data space following execution of line 13. Note that a box containing a dot represents a pointer. The address is used to print out the value of the variable pig in line 14 illustrating the use of a pointer with the output stream object cout. Likewise, the pointer to float named pt_float is assigned the address of x, then used in a trivial calculation in line 18.
CONSTANT POINTERS AND POINTERS TO CONSTANTS
The definition of C++ allows a pointer to a constant to be defined such that the value to which the pointer points cannot be changed but the pointer itself can be moved to another variable or constant. The method of defining a pointer to a constant is illustrated in line 22. In addition to a pointer to a constant, you can also declare a constant pointer, one that cannot be changed. Line 23 illustrates this. Note that neither of these pointers are used in illustrative code.
Either of these constructs can be used to provide additional compile time checking and improve the quality of your code. If you know a pointer will never be moved due to its nature, you should define it as a constant pointer. If you know that a value will not be changed, it can be defined as a constant and the compiler will tell you if you ever inadvertently attempt to change it.
A POINTER TO VOID
The pointer to void is actually a part of the ANSI-C standard but is relatively new so it is commented upon here. A pointer to void can be assigned the value of any other pointer type. You will notice that the pointer to void named general is assigned an address of an int type in line 15 and the address of a float type in line 20 with no cast and no complaints from the compiler. This is a relatively new concept in C and C++. It allows a programmer to define a pointer that can be used to point to many different kinds of things to transfer information around within a program. A good example is the malloc() function which returns a pointer to void. This pointer can be assigned to point to any entity, thus transferring the returned pointer to the correct type.
A pointer to void is aligned in memory in such a way that it can be used with any of the simple predefined types available in C++, or in ANSI-C for that matter. They will also align with any compound types the user can define since compound types are composed of the simpler types.
If you are not completely comfortable with this trivial program using pointers, you should review the use of pointers in any good C programming book or Coronado Enterprises C tutorial before proceeding on because we will assume that you have a thorough knowledge of pointers throughout the remainder of this tutorial. It is not possible to write a C program of any significant size or complexity without the use of pointers.
Be sure to compile and execute this program.
DYNAMIC ALLOCATION AND DEALLOCATION
Example program ------> NEWDEL.CPP
Examine the program named NEWDEL.CPP for our first example of the new and delete operators. The new and delete operators do dynamic allocation and deallocation in much the same manner that the malloc() and free() functions do in your old favorite C implementation.
During the design of C++, it was felt that since dynamic allocation and deallocation are such a heavily used part of the C programming language and would also be heavily used in C++, it should be
This document provides some basic information that you may need to fully understand the topical documents provided at this web site.
Figure 1 is used to define the memory elements of any program via a graphical representation. This diagram is a depiction of memory and will be used to illustrate how the various entities of a C or C++ program are stored within the computer memory.
The entire area of figure 1 represents the memory in the computer, including the area to the right that looks like a ladder. All of the executable code and all of the variables within any given program are stored within the area illustrated by this diagram. The big question is, "How are the various entities stored in this space?"
There are three areas of memory that have special capabilities assigned by the compiler and linker. They are listed as follows;
Stack - The area that looks like a ladder on the right part of the diagram is the stack. The stack is allocated by the system to be a fixed size and is filled as needed from the bottom to the top one element at a time. Elements are removed from the top to the bottom one element at a time. Thus the last element added to the stack is the first element that is removed when no longer needed. Any element on the stack is potentially available for reference or modification by the executing code, but elements are added and removed only from the top.
Heap - This is the area within the box named the heap. This is allocated by the system to be of a fixed size and is used by the system as needed in a random fashion. By random, it does not mean that there is any disorder to the way this area is used, it means the memory is not assigned in any particular order. It can in fact be assigned in blocks as needed from anyplace within the heap. Any memory within the heap that is not currently allocated for use by the program is stored in the "free list", a list of memory blocks that can be assigned to the program as needed.
Global Memory - This is all of the memory on the machine that is not assigned to the stack or the heap.
As an aid to clarity, all keywords, identifiers, and function names used in the text portion of these documents will be given in bold type.
WHAT ABOUT A MULTI-USER ENVIRONMENT?
We are assuming a single user computer for simplicity. In the case of a multi-user system, each user is assigned a block of memory which is carved up as shown here so that the same principles apply to each user.
HOW IS GLOBAL MEMORY ASSIGNED
The block of code that is the main() program is stored in global memory and every function that is required for the program to execute is also stored somewhere in global memory. Even though the system will assign the various blocks of code in a very orderly manner, we must assume that they are actually assigned in no particular order. In fact we should assume that they are randomly assigned all over the global storage area and that any particular function is not contiguous to any other function.
Note that some compilation/linking systems permit you to locate code and variables where you want them in memory, but that is beyond the scope of this document.
Figure 1 contains a box with the title main(). This box represents the block of code for the main() program. Even though all of the functions in any program appear as code blocks within the global memory, we will not include them in any of the remaining figures since they don't interact in a manner that is conducive to this discussion. You can therefore assume that the code is there, ready to be executed, but since it will clutter up the drawings, we will not show it or discuss it any further.
A GLOBAL VARIABLE
We are very interested in the small boxes near the top of figure 1 because they represent global variables which are stored in global memory. The system carves out enough memory to store the variable in question and assigns that memory to the variable. The global variable exists for the entire time of program execution.
Note that a char type variable usually uses only one byte of storage, but a double type variable will use about 8 bytes of storage. Even though they use different amounts of memory, we will not be concerned with that in this discussion since we are not interested in that level of detail. Therefore, the box labeled variable can store a char, an int, a double, or any other simple variable and the system will assure that there is enough room to store the entity that we have requested. Even though the boxes are all the same size in this graphical representation, they may be referring to different amounts of physical memory.
We may have several global variables declared in our program, but we will not assume that they are stored contiguously, since the compiler is not compelled to store them in any order convenient to us. We will assume that they are randomly stored throughout the available global memory even though we know that every C or C++ compiler will probably assign them in some contiguous manner.
A GLOBAL POINTER
The box labeled pointer has the ability to store any one pointer of any type. Pointers are generally the same size for all data types on any given combination of hardware and run-time system, so they are probably all allocated the same number of bytes. The dot is the authors convention to indicate that the box is a pointer rather than a simple variable, and when the dot is unadorned as shown here, the pointer has not yet been assigned to point to anything in particular. In fact it may contain any value which means it may be pointing anywhere within the entire memory space of the computer, although by definition, a global pointer is initialized to NULL. When the pointer has been assigned an address, it will have an arrow pointing from the dot to the entity to which it is pointing. This will be clear when you see it used in the discussions.
Any number of pointers and variables can be stored in the global memory up to the limit of available memory.
HOW IS THE STACK USED?
As variables or pointers are needed by the system, they will be assigned to the stack sequentially starting at the bottom with each successive element being "stacked" on top of the others, or assigned the next location towards the top of the diagram. Each box in the pictorial of the stack can store any one of the simple variables in the same manner as we defined for global memory storage, independent of the size of the variable. (The system knows how many bytes it takes to store each type of variable and it will take care of the various sizes automatically.) Once a variable is stored on the stack, it can be referred to by the code that put it on the stack, so it is a variable available for use in much the same manner as the global variables are available. However, when the program is done using the data on the stack, it can be discarded to allow the stack to be used for other data when needed. This is probably unclear at this point, but it will make more sense when we get to the actual usage.
Think of the stack as growing upward as needed and shrinking downward when some of the data is discarded because it is no longer needed.
HOW IS THE HEAP USED?
The heap is a contiguous block of memory that is available for use by any part of the program whenever it needs it and for as long as it needs it. When the program requests a block of data, the dynamic allocation scheme carves out a block from the heap and assigns it to the user by returning a pointer to the beginning of the block. When the system is finished using the block, it returns the block to the heap where it is returned to the pool of available memory called the free list. This is called deallocation.
IS THERE MORE INFO ABOUT MEMORY?
We have just scratched the surface on what actually goes on within the memory allocation scheme. There is virtual memory, cache memory, registers, and other kinds of memory that someone dreams up to make your system run a little faster or appear to have more memory. The blocks returned to the program from the heap have additional housekeeping memory associated with them and there are byte alignment considerations for both the heap and the stack. Global memory also has some byte alignment considerations. For example, your compiler may require that all float and double type variables start on an even numbered byte boundary, or on a byte boundary that is modulo four. This may require some bytes added as padding to get to the boundary when one of these is encountered. The compiler/linker will take care of these details for you, so you can pretty much ignore them.
Since we are interested only in the logical assignment of memory, we can ignore all of these extra considerations, and still write efficient, robust programs. The compiler writer has a big job to do because he must keep track of all of these entities in order to make our job easier.