home *** CD-ROM | disk | FTP | other *** search
- Chapter 12 - Dynamic Allocation
-
-
- WHAT IS DYNAMIC ALLOCATION?
-
- Dynamic allocation is very intimidating to a person the
-
- first time he comes across it, but that need not be. Simply
-
- relax and read this chapter carefully and you will have a
-
- good grounding in a very valuable programming resource. All
-
- of the variables in every program up to this point have been
-
- static variables as far as we are concerned. (Actually,
-
- some of them have been "automatic" and were dynamically
-
- allocated for you by the system, but it was transparent to
-
- you.) In this chapter, we will study some dynamically
-
- allocated variables. They are simply variables that do not
-
- exist when the program is loaded, but are created
-
- dynamically as they are needed. It is possible, using these
-
- techniques, to create as many variables as needed, use them,
-
- and deallocate their space for use by other variables. As
-
- usual, the best teacher is an example, so load and display
-
- the program named DYNLIST.C.
-
- We begin by defining a named structure "animal" with a
-
- few fields pertaining to dogs. We do not define any
-
- variables of this type, only three pointers. If you search
-
- through the remainder of the program, you will find no
-
- variables defined so we have nothing to store data in. All
-
- we have to work with are three pointers, each of which point
-
- to the defined structure. In order to do anything, we need
-
- some variables, so we will create some dynamically.
-
- DYNAMIC VARIABLE CREATION
-
- The first program statement, which assigns something to
-
- the pointer "pet1" will create a dynamic structure
-
- containing three variables. The heart of the statement is
-
- the "malloc" function buried in the middle of the statement.
-
- This is a "memory allocate" function that needs the other
-
- things to completely define it. The "malloc" function, by
-
- default, will allocate a piece of memory on a "heap" that is
-
- "n" characters in length and will be of type character. The
-
- "n" must be specified as the only argument to the function.
-
- We will discuss "n" shortly, but first we need to define a
-
- "heap".
-
- WHAT IS A HEAP?
-
- Every compiler has a set of limitations on it as to how
-
- big the executable file can be, how many variables can be
-
- used, how long the source file can be, etc. One limitation
-
- placed on users by many compilers for the IBM-PC and
-
- compatibles is a limit of 64K for the executable code. This
-
- is because the IBM-PC uses a microprocessor with a 64K
-
- segment size, and it requires special calls to use data
-
-
-
- Page 83
-
-
-
-
-
-
-
-
-
- Chapter 12 - Dynamic Allocation
-
-
- outside of a single segment. In order to keep the program
-
- small and efficient, these calls are not used, and the
-
- program is limited but still adequate for most programs.
-
- A heap is an area outside of this 64K boundary which
-
- can be accessed by the program to store data and variables.
-
- The data and variables are put on the "heap" by the system
-
- as calls to "malloc" are made. The system keeps track of
-
- where the data is stored. Data and variables can be
-
- deallocated as desired leading to holes in the heap. The
-
- system knows where the holes are and will use them for
-
- additional data storage as more "malloc" calls are made.
-
- The structure of the heap is therefore a very dynamic
-
- entity, changing constantly.
-
- MORE ABOUT SEGMENTS
-
- Some of the more expensive compilers give the user a
-
- choice of memory models to use. Examples are Lattice and
-
- Microsoft, which allow the programmer a choice of using a
-
- model with a 64K limitation on program size but more
-
- efficient running, or using a model with a 640K limitation
-
- and requiring longer address calls leading to less efficient
-
- addressing. Using the larger address space requires inter
-
- segment addressing resulting in the slightly slower running
-
- time. The time is probably insignificant in most programs,
-
- but there are other considerations.
-
- If a program uses no more than 64K bytes for the total
-
- of its code and memory and if it doesn't use a stack, it can
-
- be made into a .COM file. Since a .COM file is already in a
-
- memory image format, it can be loaded very quickly whereas a
-
- file in a .EXE format must have its addresses relocated as
-
- it is loaded. Therefore a small memory model can generate a
-
- program that loads faster than one generated with a larger
-
- memory model. Don't let this worry you, it is a fine point
-
- that few programmers worry about.
-
- Using dynamic allocation, it is possible to store the
-
- data on the "heap" and that may be enough to allow you to
-
- use the small memory model. Of course, you wouldn't store
-
- local variables such as counters and indexes on the heap,
-
- only very large arrays or structures.
-
- Even more important than the need to stay within the
-
- small memory model is the need to stay within the computer.
-
- If you had a program that used several large data storage
-
- areas, but not at the same time, you could load one block
-
- storing it dynamically, then get rid of it and reuse the
-
- space for the next large block of data. Dynamically storing
-
- each block of data in succession, and using the same storage
-
-
-
- Page 84
-
-
-
-
-
-
-
-
-
- Chapter 12 - Dynamic Allocation
-
-
- for each block may allow you to run your entire program in
-
- the computer without breaking it up into smaller programs.
-
- BACK TO THE "MALLOC" FUNCTION
-
- Hopefully the above description of the "heap" and the
-
- overall plan for dynamic allocation helped you to understand
-
- what we are doing with the "malloc" function. It simply
-
- asks the system for a block of memory of the size specified,
-
- and gets the block with the pointer pointing to the first
-
- element of the block. The only argument in the parentheses
-
- is the size of the block desired and in our present case, we
-
- desire a block that will hold one of the structures we
-
- defined at the beginning of the program. The "sizeof" is a
-
- new function, new to us at least, that returns the size in
-
- bytes of the argument within its parentheses. It therefore,
-
- returns the size of the structure named animal, in bytes,
-
- and that number is sent to the system with the "malloc"
-
- call. At the completion of that call, we have a block on
-
- the heap allocated to us, with pet1 pointing to the first
-
- byte of the block.
-
- WHAT IS A CAST?
-
- We still have a funny looking construct at the
-
- beginning of the "malloc" function call. That is called a
-
- "cast". The "malloc" function returns a block with the
-
- pointer pointing to it being a pointer of type "char" by
-
- default. Many times, if not most, you do not want a pointer
-
- to a "char" type variable, but to some other type. You can
-
- define the pointer type with the construct given on the
-
- example line. In this case we want the pointer to point to
-
- a structure of type "animal", so we tell the compiler with
-
- this strange looking construct. Even if you omit the cast,
-
- most compilers will return a pointer correctly, give you a
-
- warning, and go on to produce a working program. It is
-
- better programming practice to provide the compiler with the
-
- cast to prevent getting the warning message.
-
- USING THE DYNAMICALLY ALLOCATED MEMORY BLOCK
-
- If you remember our studies of structures and pointers,
-
- you will recall that if we have a structure with a pointer
-
- pointing to it, we can access any of the variables within
-
- the structure. In the next three lines of the program, we
-
- assign some silly data to the structure for illustration.
-
- It should come as no surprise to you that these assignment
-
- statements look just like assignments to statically defined
-
- variables.
-
-
-
-
-
- Page 85
-
-
-
-
-
-
-
-
-
- Chapter 12 - Dynamic Allocation
-
-
- In the next statement, we assign the value of "pet1" to
-
- "pet2" also. This creates no new data, we simply have two
-
- pointers to the same object. Since "pet2" is pointing to
-
- the structure we created above, "pet1" can be reused to get
-
- another dynamically allocated structure which is just what
-
- we do next. Keep in mind that "pet2" could have just as
-
- easily been used for the new allocation. The new structure
-
- is filled with silly data for illustration.
-
- Finally, we allocate another block on the heap using
-
- the pointer "pet3", and fill its block with illustrative
-
- data.
-
- Printing the data out should pose no problem to you
-
- since there is nothing new in the three print statements.
-
- It is left for you to study.
-
- GETTING RID OF THE DYNAMICALLY ALLOCATED DATA
-
- Another new function is used to get rid of the data and
-
- free up the space on the heap for reuse, the function
-
- "free". To use it, you simply call it with the pointer to
-
- the block as the only argument, and the block is
-
- deallocated.
-
- In order to illustrate another aspect of the dynamic
-
- allocation and deallocation of data, an additional step is
-
- included in the program on your monitor. The pointer "pet1"
-
- is assigned the value of "pet3". In doing this, the block
-
- that "pet1" was pointing to is effectively lost since there
-
- is no pointer that is now pointing to that block. It can
-
- therefore never again be referred to, changed, or disposed
-
- of. That memory, which is a block on the heap, is wasted
-
- from this point on. This is not something that you would
-
- ever purposely do in a program. It is only done here for
-
- illustration.
-
- The first "free" function call removes the block of
-
- data that "pet1" and "pet3" were pointing to, and the second
-
- "free" call removes the block of data that "pet2" was
-
- pointing to. We therefore have lost access to all of our
-
- data generated earlier. There is still one block of data
-
- that is on the heap but there is no pointer to it since we
-
- lost the address to it. Trying to "free" the data pointed
-
- to by "pet1" would result in an error because it has already
-
- been "freed" by the use of "pet3". There is no need to
-
- worry, when we return to DOS, the entire heap will be
-
- disposed of with no regard to what we have put on it. The
-
- point does need to made that losing a pointer to a block of
-
- the heap, forever removes that block of data storage from
-
- our program and we may need that storage later.
-
-
-
- Page 86
-
-
-
-
-
-
-
-
-
- Chapter 12 - Dynamic Allocation
-
-
-
- Compile and run the program to see if it does what you
-
- think it should do based on this discussion.
-
- THAT WAS A LOT OF DISCUSSION
-
- It took nearly four pages to get through the discussion
-
- of the last program but it was time well spent. It should
-
- be somewhat exciting to you to know that there is nothing
-
- else to learn about dynamic allocation, the last four pages
-
- covered it all. Of course, there is a lot to learn about
-
- the technique of using dynamic allocation, and for that
-
- reason, there are two more files to study. But the fact
-
- remains, there is nothing more to learn about dynamic
-
- allocation than what was given so far in this chapter.
-
- AN ARRAY OF POINTERS
-
- Load and display the file BIGDYNL.C for another example
-
- of dynamic allocation. This program is very similar to the
-
- last one since we use the same structure, but this time we
-
- define an array of pointers to illustrate the means by which
-
- you could build a large database using an array of pointers
-
- rather than a single pointer to each element. To keep it
-
- simple we define 12 elements in the array and another
-
- working pointer named "point".
-
- The "*pet[12]" is new to you so a few words would be in
-
- order. What we have defined is an array of 12 pointers, the
-
- first being "pet[0]", and the last "pet[11]". Actually,
-
- since an array is itself a pointer, the name "pet" by itself
-
- is a pointer to a pointer. This is valid in C, and in fact
-
- you can go farther if needed but you will get quickly
-
- confused. I know of no limit as to how many levels of
-
- pointing are possible, so a definition such as "int ****pt"
-
- is legal as a pointer to a pointer to a pointer to a pointer
-
- to an integer type variable, if I counted right. Such usage
-
- is discouraged until you gain considerable experience.
-
- Now that we have 12 pointers which can be used like any
-
- other pointer, it is a simple matter to write a loop to
-
- allocate a data block dynamically for each and to fill the
-
- respective fields with any data desirable. In this case,
-
- the fields are filled with simple data for illustrative
-
- purposes, but we could be reading in a database, readings
-
- from some test equipment, or any other source of data.
-
- A few fields are randomly picked to receive other data
-
- to illustrate that simple assignments can be used, and the
-
- data is printed out to the monitor. The pointer "point" is
-
- used in the printout loop only to serve as an illustration,
-
-
-
- Page 87
-
-
-
-
-
-
-
-
-
- Chapter 12 - Dynamic Allocation
-
-
- the data could have been easily printed using the "pet[n]"
-
- means of definition. Finally, all 12 blocks of data are
-
- freed before terminating the program.
-
- Compile and run this program to aid in understanding
-
- this technique. As stated earlier, there was nothing new
-
- here about dynamic allocation, only about an array of
-
- pointers.
-
- A LINKED LIST
-
- We finally come to the grandaddy of all programming
-
- techniques as far as being intimidating. Load the program
-
- DYNLINK.C for an example of a dynamically allocated linked
-
- list. It sounds terrible, but after a little time spent
-
- with it, you will see that it is simply another programming
-
- technique made up of simple components that can be a
-
- powerful tool.
-
- In order to set your mind at ease, consider the linked
-
- list you used when you were a child. Your sister gave you
-
- your birthday present, and when you opened it, you found a
-
- note that said, "Look in the hall closet." You went to the
-
- hall closet, and found another note that said, "Look behind
-
- the TV set." Behind the TV you found another note that
-
- said, "Look under the coffee pot." You continued this
-
- search, and finally you found your pair of socks under the
-
- dogs feeding dish. What you actually did was to execute a
-
- linked list, the starting point being the wrapped present
-
- and the ending point being under the dogs feeding dish. The
-
- list ended at the dogs feeding dish since there were no more
-
- notes.
-
- In the program DYNLINK.C, we will be doing the same
-
- thing as your sister forced you to do. We will however, do
-
- it much faster and we will leave a little pile of data at
-
- each of the intermediate points along the way. We will also
-
- have the capability to return to the beginning and
-
- retraverse the entire list again and again if we so desire.
-
- THE DATA DEFINITIONS
-
- This program starts similarly to the last two with the
-
- addition of the definition of a constant to be used later.
-
- The structure is nearly the same as that used in the last
-
- two programs except for the addition of another field within
-
- the structure, the pointer. This pointer is a pointer to
-
- another structure of this same type and will be used to
-
- point to the next structure in order. To continue the above
-
- analogy, this pointer will point to the next note, which in
-
- turn will contain a pointer to the next note after that.
-
-
-
- Page 88
-
-
-
-
-
-
-
-
-
- Chapter 12 - Dynamic Allocation
-
-
-
- We define three pointers to this structure for use in
-
- the program, and one integer to be used as a counter, and we
-
- are ready to begin using the defined structure for whatever
-
- purpose we desire. In this case, we will once again
-
- generate nonsense data for illustrative purposes.
-
- THE FIRST FIELD
-
- Using the "malloc" function, we request a block of
-
- storage on the "heap" and fill it with data. The additional
-
- field in this example, the pointer, is assigned the value of
-
- NULL, which is only used to indicate that this is the end of
-
- the list. We will leave the pointer "start" at this
-
- structure, so that it will always point to the first
-
- structure of the list. We also assign "prior" the value of
-
- "start" for reasons we will see soon. Keep in mind that the
-
- end points of a linked list will always have to be handled
-
- differently than those in the middle of a list. We have a
-
- single element of our list now and it is filled with
-
- representative data.
-
- FILLING ADDITIONAL STRUCTURES
-
- The next group of assignments and control statements
-
- are included within a "for" loop so we can build our list
-
- fast once it is defined. We will go through the loop a
-
- number of times equal to the constant "RECORDS" defined at
-
- the beginning of our program. Each time through, we
-
- allocate memory, fill the first three fields with nonsense,
-
- and fill the pointers. The pointer in the last record is
-
- given the address of this new record because the "prior"
-
- pointer is pointing to the prior record. Thus "prior->next"
-
- is given the address of the new record we have just filled.
-
- The pointer in the new record is assigned the value "NULL",
-
- and the pointer "prior" is given the address of this new
-
- record because the next time we create a record, this one
-
- will be the prior one at that time. That may sound
-
- confusing but it really does make sense if you spend some
-
- time studying it.
-
- When we have gone through the "for" loop 6 times, we
-
- will have a list of 7 structures including the one we
-
- generated prior to the loop. The list will have the
-
- following characteristics.
-
-
- 1. "start" points to the first structure in the list.
-
- 2. Each structure contains a pointer to the next structure.
-
-
-
-
- Page 89
-
-
-
-
-
-
-
-
-
- Chapter 12 - Dynamic Allocation
-
-
- 3. The last structure has a pointer that points to NULL and
-
- can be used to detect the end.
-
- start->struct1 This diagram should aid in
- name understanding the structure of
- breed the data at this point.
- age
- point->struct2
- name
- breed
- age
- point->struct3
- name
- breed
- age
- point-> . . . . struct7
- name
- breed
- age
- point->NULL
-
-
- It should be clear to you, if you understand the above
-
- structure, that it is not possible to simply jump into the
-
- middle of the structure and change a few values. The only
-
- way to get to the third structure is by starting at the
-
- beginning and working your way down through the structure
-
- one record at a time. Although this may seem like a large
-
- price to pay for the convenience of putting so much data
-
- outside of the program area, it is actually a very good way
-
- to store some kinds of data.
-
- A word processor would be a good application for this
-
- type of data structure because you would never need to have
-
- random access to the data. In actual practice, this is the
-
- basic type of storage used for the text in a word processor
-
- with one line of text per record. Actually, a program with
-
- any degree of sophistication would use a doubly linked list.
-
- This would be a list with two pointers per record, one
-
- pointing down to the next record, and the other pointing up
-
- to the record just prior to the one in question. Using this
-
- kind of a record structure would allow traversing the data
-
- in either direction.
-
- PRINTING THE DATA OUT
-
- To print the data out, a similar method is used as that
-
- used to generate the data. The pointers are initialized and
-
- are then used to go from record to record reading and
-
- displaying each record one at a time. Printing is
-
- terminated when the NULL on the last record is found, so the
-
-
-
- Page 90
-
-
-
-
-
-
-
-
-
- Chapter 12 - Dynamic Allocation
-
-
- program doesn't even need to know how many records are in
-
- the list. Finally, the entire list is deleted to make room
-
- in memory for any additional data that may be needed, in
-
- this case, none. Care must be taken to assure that the last
-
- record is not deleted before the NULL is checked. Once the
-
- data is gone, it is impossible to know if you are finished
-
- yet.
-
- MORE ABOUT DYNAMIC ALLOCATION AND LINKED LISTS
-
- It is not difficult, and it is not trivial, to add
-
- elements into the middle of a linked lists. It is necessary
-
- to create the new record, fill it with data, and point its
-
- pointer to the record it is desired to precede. If the new
-
- record is to be installed between the 3rd and 4th, for
-
- example, it is necessary for the new record to point to the
-
- 4th record, and the pointer in the 3rd record must point to
-
- the new one. Adding a new record to the beginning or end of
-
- a list are each special cases. Consider what must be done
-
- to add a new record in a doubly linked list.
-
- Entire books are written describing different types of
-
- linked lists and how to use them, so no further detail will
-
- be given. The amount of detail given should be sufficient
-
- for a beginning understanding of C and its capabilities.
-
- ANOTHER NEW FUNCTION - CALLOC
-
- One more function must be mentioned, the "calloc"
-
- function. This function allocates a block of memory and
-
- clears it to all zeros which may be useful in some
-
- circumstances. It is similar to "malloc" and will be left
-
- as an exercise for you to read about and use "calloc" if you
-
- desire.
-
- PROGRAMMING EXERCISES
-
- 1. Rewrite the example program STRUCT1.C from chapter 11 to
-
- dynamically allocate the two structures.
-
- 2. Rewrite the example program STRUCT2.C from chapter 11 to
-
- dynamically allocate the 12 structures.
-
-
-
-
-
-
-
-
-
-
-
- Page 91
-