home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / m2t-1.zip / CHAP12.TXT < prev    next >
Text File  |  1989-01-18  |  25KB  |  587 lines

  1.  
  2.                                                     Chapter 12
  3.  
  4.                                POINTERS AND DYNAMIC ALLOCATION
  5.  
  6.  
  7.  
  8. PREREQUISITES FOR THIS MATERIAL
  9. ______________________________________________________________
  10.  
  11. In order to understand this chapter, you should have a good
  12. grasp of the entirety of Part I and a clear understanding of
  13. chapter 11.
  14.  
  15. For certain types of programs, pointers and dynamic allocation
  16. can be a tremendous advantage, but many programs do not need
  17. such a high degree of data structure.  For that reason, it
  18. would probably be to your advantage to lightly skim over these
  19. topics and come back to them later when you have a substantial
  20. base of Modula-2 programming experience.  It would be good to
  21. at least skim over this material rather than completely
  22. neglecting it, so you will have an idea of how pointers and
  23. dynamic allocation work and that they are available for your
  24. use when needed.
  25.  
  26. A complete understanding of this material will require deep
  27. concentration as it is very complex and not at all intuitive.
  28. Nevertheless, if you pay close attention, you will have a good
  29. grasp of pointers and dynamic allocation in a short time.
  30.  
  31.  
  32.  
  33. WHAT ARE POINTERS, AND WHAT GOOD ARE THEY?
  34. ______________________________________________________________
  35.  
  36. If you examine POINTERS.MOD, you will see     ================
  37. a very trivial example of pointers and how      POINTERS.MOD
  38. they are used.  In the var declaration,       ================
  39. you will see that the two variables have
  40. the two reserved words POINTER TO in front of their respective
  41. types.  These are not actually variables, instead they point
  42. to dynamically allocated variables that have not been defined
  43. yet, and they are called pointers.  We will see, when we get
  44. to chapter 14, that a pointer can be used to point to any
  45. variable, even a statically defined one, but that will have
  46. to wait awhile.
  47.  
  48. The pointer MyName is a pointer to a 20 character string and
  49. is therefore not a variable into which a value can be stored.
  50. This is a very special type, and it cannot be assigned a
  51. character string, only a pointer value or address.  Likewise
  52. MyAge is a pointer to an integer type variable even though it
  53. has nothing to point at.  Note that neither pointer has
  54. anything to point at yet.  Note that Modula-2 does not
  55. initialize pointers automatically.  It is up to you to
  56. initialize all pointers prior to using them.
  57.  
  58.                                                           12-1
  59.  
  60.                   Chapter 12 - Pointers and Dynamic Allocation
  61.  
  62. Your computer has some amount of memory installed in it.  If
  63. it is an IBM-PC or compatible, it can have up to 640K of RAM
  64. which is addressable by various programs.  The operating
  65. system requires about 60K of the total, and your program can
  66. use up to 64K assuming that your compiler uses a small memory
  67. model.  Adding those two numbers together results in about
  68. 124K.  Any memory you have installed in excess of that is
  69. available for the stack and the heap.  The stack is a standard
  70. DOS defined and controlled area that can grow and shrink as
  71. needed.  Many books are available to define the stack if you
  72. are interested in more information on it.
  73.  
  74.  
  75. WHAT IS THE HEAP?
  76. ______________________________________________________________
  77.  
  78. The heap is a Modula-2 entity that utilizes otherwise unused
  79. memory to store data.  It begins immediately following the
  80. program and grows as necessary upward toward the stack which
  81. is growing downward.  As long as they never meet, there is no
  82. problem.  If they meet, a run-time error is generated.  The
  83. heap is therefore outside of the actual program and local data
  84. storage space.
  85.  
  86. If you did not understand the last two paragraphs, don't
  87. worry.  Simply remember that dynamically allocated variables
  88. are stored on the heap and do not count in the 64K limitation
  89. placed upon you by some compilers.
  90.  
  91. Back to our example program, POINTERS.MOD.  When we actually
  92. begin executing the program, we still have not defined the
  93. variables we wish to use to store data in.  We only have 2
  94. pointers defined at this point in the program, and the data
  95. space can be pictured graphically as shown in fig 12-1 where
  96. a pointer is a box with a dot in it.  The first executable
  97. statement in line 15 generates a variable for us with no name
  98. and stores it on the heap.  Since it has no name, we cannot
  99. do anything with it, except for the fact that we do have the
  100. pointer MyAge that is pointing to it.  By using the pointer,
  101. we can store any integer type variable in it, because that is
  102. its defined type, and later go back and retrieve it.
  103.  
  104.  
  105. WHAT IS DYNAMIC ALLOCATION?
  106. ______________________________________________________________
  107.  
  108. The variable we have just described is a dynamically allocated
  109. variable because it was not defined in a VAR declaration, but
  110. with an ALLOCATE procedure.  The ALLOCATE procedure creates
  111. a variable of the type defined by the pointer, puts the new
  112. variable on the heap, and assigns the address of the variable
  113. to the pointer itself.  Thus MyAge contains the address of the
  114. variable generated.
  115.  
  116.                                                           12-2
  117.  
  118.                   Chapter 12 - Pointers and Dynamic Allocation
  119.  
  120. The allocate procedure requires 2 parameters, the first of
  121. which is a pointer which will be used to point to the desired
  122. new block of dynamically allocated memory, and the second
  123. which gives the size of the block in bytes.  The supplied
  124. function TSIZE will return the size of the block of data
  125. required by the type supplied to it as an argument.  Be sure
  126. to use the type of the data and not the type of the pointer
  127. to the data for the argument.  Another procedure is available
  128. named SIZE which returns the size of any variable in bytes.
  129.  
  130. The statement in line 16 dynamically allocates an array type
  131. variable which is large enough to store 20 char type data
  132. points, and assigns its address to MyName.  The data space
  133. would now appear as depicted in fig 12-2.  Following the
  134. allocate statements, we have two assignment statements in
  135. which the two variables pointed at are assigned values
  136. compatible with their respective types, and they are both
  137. written out to the video display.  Notice that both of these
  138. operations use the ^ which is the dereference operator which
  139. tells the system to store the data at the location where the
  140. pointer is pointing.  By adding the dereference operator to
  141. the pointer name, you can use the entire name just like any
  142. other variable name.  Figure 12-3 is a graphical
  143. representation of the data space after the data has been
  144. assigned.
  145.  
  146. Lines 21 through 26 illustrate use of the stored data, and the
  147. last two statements are illustrations of the way the
  148. dynamically allocated variables are removed from use.  When
  149. they are no longer needed, they are disposed of with the
  150. DEALLOCATE procedure, and the space on the heap is freed up
  151. for use by other dynamically allocated variables.
  152.  
  153.  
  154. ARE POINTERS REALLY USEFUL?
  155. ______________________________________________________________
  156.  
  157. In such a simple program, pointers cannot be appreciated, but
  158. it is necessary for a simple illustration.  In a large, very
  159. active program, it is possible to define many variables,
  160. dispose of some of them, define more, and dispose of more,
  161. etc.  Each time some variables are deallocated, their space
  162. is then made available for additional variables defined with
  163. the allocate procedure.
  164.  
  165. The heap can be made up of any assortment of variables, they
  166. do not have to all be the same.  One thing must be remembered.
  167. Anytime a variable is defined, it will have a pointer pointing
  168. to it.  The pointer is the only means by which the variable
  169. can be accessed.  If the pointer to the variable is lost or
  170. changed, the data itself is lost for all practical purposes.
  171.  
  172.  
  173.  
  174.                                                           12-3
  175.  
  176.                   Chapter 12 - Pointers and Dynamic Allocation
  177.  
  178. WHAT ABOUT THE NEW AND DISPOSE PROCEDURES?
  179. ______________________________________________________________
  180.  
  181. The new and dispose procedures are a carryover from Pascal and
  182. are available on some Modula-2 compilers.  When they are
  183. available, they are simply translated internally into calls
  184. to allocate and deallocate which must be imported in order to
  185. use new and dispose.  Since they are being removed from the
  186. language definition, their use should be discouraged in favor
  187. of the more universal allocate and deallocate procedures.
  188.  
  189.  
  190. DYNAMICALLY STORING RECORDS;
  191. ______________________________________________________________
  192.  
  193. The next example program, DYNREC.MOD, is a    ================
  194. repeat of one we studied in an earlier           DYNREC.MOD
  195. chapter.  For your own edification, review    ================
  196. the example program BIGREC.MOD before
  197. going ahead in this chapter.
  198.  
  199. Assuming that you are back in DYNREC.MOD, you will notice that
  200. this program looks very similar to the earlier one, and in
  201. fact, they do exactly the same thing.  The only difference in
  202. the type declaration is the addition of a pointer PersonID,
  203. and in lines 30 and 31 of the var declaration, the variables
  204. are defined as pointers, whereas they were defined as record
  205. variables in the last program.
  206.  
  207.  
  208. WE JUST BROKE THE GREAT RULE OF MODULA-2
  209. ______________________________________________________________
  210.  
  211. Notice in the type declaration that we used the identifier
  212. Person in line 22 prior to defining it, which we said earlier
  213. is illegal in Modula-2.  Foreseeing the need to define a
  214. pointer prior to the record, the designer of Modula-2 allows
  215. us to break the rule in this one place.  The pointer could
  216. have been defined after the record in this particular example,
  217. but it was more convenient to put it first, and in the next
  218. example program, it will be required to define it ahead of the
  219. record.  We will get there soon.
  220.  
  221. Examining the var declaration, we see that Friend is really
  222. 50 pointers, so we have now defined 53 different pointers to
  223. records, but no variables other than Temp and Index.  Figure
  224. 12-4 illustrates the data space at this time.  We dynamically
  225. allocate a record with Self pointing to it in line 36, and use
  226. the pointer to fill the new record in lines 38 through 49.
  227. Compare the statements that fill the record with the
  228. corresponding statements in BIGREC.MOD and you will see that
  229. they are identical except for the addition of the ^ to each
  230. use of the pointer to designate the data pointed to.  Once
  231. again, this is called dereferencing the pointer.
  232.  
  233.                                                           12-4
  234.  
  235.                   Chapter 12 - Pointers and Dynamic Allocation
  236.  
  237. THIS IS A TRICK, BE CAREFUL
  238. ______________________________________________________________
  239.  
  240. Now go down to the place where Mother is assigned a record and
  241. is then pointing to the record.  It seems an easy thing to do
  242. then to simply assign all of the values of Self to all the
  243. values of Mother as shown in line 52, but it doesn't work.
  244. All the statement in line 52 does, is make the pointer Mother
  245. point to the same place where Self is pointing.  The data
  246. space that was allocated to the pointer Mother is now
  247. somewhere on the heap, but since we have lost the original
  248. pointer to it, we cannot find it, use it, or deallocate it.
  249. This is an example of losing data on the heap.  Figure 12-5
  250. illustrates the data space at this time.  The proper way of
  251. assigning data from one dynamically allocated record to
  252. another is given in line 55 where all fields of Father are
  253. defined by all fields of Mother which is pointing at the
  254. original Self record.
  255.  
  256. Note that since Mother and Self are both pointing at the same
  257. record, changing the data with either pointer results in the
  258. data appearing to be changed in both because there is, in
  259. fact, only one data field.
  260.  
  261. The loop in lines 57 through 60 dynamically allocates 50
  262. records and uses the 50 pointers in the Friend array to point
  263. to them, then fills each record with the data contained in the
  264. record pointed to by the pointer named Mother.  Three values
  265. are finally output to the monitor in lines 63 through 65 for
  266. illustrative purposes.
  267.  
  268.  
  269. A NOTE FOR PASCAL PROGRAMMERS
  270. ______________________________________________________________
  271.  
  272. In order to write from or read into a dynamically assigned
  273. record it is necessary to use a temporary record since
  274. dynamically assigned records are not allowed to be used in I/O
  275. statements in Pascal.  This is not true in Modula-2, and you
  276. can write directly out of a dynamically allocated record in
  277. Modula-2.  This is illustrated in the section of the program
  278. that writes some data to the monitor.  Notice line 62 where
  279. the data from a dynamically allocated record is assigned to
  280. all fields of a statically defined record.
  281.  
  282. Finally, the dynamically allocated variables are deallocated
  283. prior to ending the program.  For a simple program such as
  284. this, it is not necessary to deallocate them because all
  285. dynamic variables are deallocated automatically when the
  286. program is terminated, but the deallocate steps are included
  287. for illustration.  Notice that if the DEALLOCATE(Mother)
  288. statement was included in the program, the data could not be
  289. found due to the lost pointer, and the program would be
  290. unpredictable, possibly leading to a system crash.
  291.  
  292.                                                           12-5
  293.  
  294.                   Chapter 12 - Pointers and Dynamic Allocation
  295.  
  296. WHAT GOOD IS THIS ANYWAY?
  297. ______________________________________________________________
  298.  
  299. Remember when you were initially studying BIGREC.MOD?  I
  300. suggested that you see how big you could make the constant
  301. NumberOfFriends before you ran out of memory.  At that time
  302. you probably found that it could be made slightly greater than
  303. 1000 before you got the memory overflow message at
  304. compilation.  If your compiler uses a large memory model, you
  305. may have been able to go much larger.  Try the same thing with
  306. DYNREC.MOD to see how many records it can handle, remembering
  307. that the records are created dynamically, so you will have to
  308. execute the program to actually run out of memory.  The final
  309. result will depend on how much memory you have installed, and
  310. how many memory resident programs you are using such as
  311. Sidekick.  If you are using a personal computer and have a
  312. full memory of 640K, I would suggest you start somewhere
  313. around 8000 records of Friend.  If you are using a
  314. minicomputer, you may be able to store considerably more
  315. records before running out of memory.
  316. Now you should have a good idea of why dynamic allocation can
  317. be used to greatly increase the usefulness of your programs.
  318. There is, however, one more important topic we must cover on
  319. dynamic allocation.  That is the linked list.
  320.  
  321.  
  322. WHAT IS A LINKED LIST?
  323. ______________________________________________________________
  324.  
  325. Understanding and using a linked list is      ================
  326. by far the most baffling topic you will         LINKLIST.MOD
  327. confront in Modula-2.  Many people simply     ================
  328. throw up their hands and never try to use
  329. a linked list.  I will try to help you understand it by use
  330. of an example and lots of explanation.  Examine the program
  331. LINKLIST.MOD for an example of a linked list.  I tried to keep
  332. it short so you could see the entire operation and yet do
  333. something meaningful.
  334.  
  335. To begin with, notice that there are two types defined, a
  336. pointer to the record and the record itself.  The record,
  337. however, has one thing about it that is new to us, the last
  338. entry, Next is a pointer to this very record.  This record
  339. then, has the ability to point to itself, which would be
  340. trivial and meaningless, or to point to another record of the
  341. same type, which would be extremely useful in some cases.  In
  342. fact, this is the way a linked list is used.  I must point out
  343. that the pointer to another record, in this case called Next,
  344. does not have to be last in the list, it can be anywhere it
  345. is convenient for you.
  346.  
  347. A couple of pages ago, we discussed the fact that we had to
  348. break the great rule of Modula-2 and use an identifier before
  349. it was defined.  This is the reason the exception to the rule
  350.  
  351.                                                           12-6
  352.  
  353.                   Chapter 12 - Pointers and Dynamic Allocation
  354.  
  355. was allowed.  Since the pointer points to the record, and the
  356. record contains a reference to the pointer, one has to be
  357. defined after being used, and by rules of Modula-2, the
  358. pointer can be defined first.  That is a mouthful but if you
  359. just use the syntax shown in the example, you will not get
  360. into trouble with it.  Figure 12-6 is a graphical
  361. representation of the data space at this time.
  362.  
  363.  
  364. STILL NO VARIABLES?
  365. ______________________________________________________________
  366.  
  367. It may seem strange, but we still will have no variables
  368. defined, except for our old friend Index.  In fact, for this
  369. example, we will only define 3 pointers.  In the last example
  370. we defined 54 pointers, and had lots of storage room.  Before
  371. we are finished, we will have at least a dozen pointers but
  372. they will be stored in our records, so they too will be
  373. dynamically allocated.
  374.  
  375. Let's look at the program itself now.  In line 26, we create
  376. a dynamically allocated record and define it by the pointer
  377. PlaceInList.  It is composed of the three data fields, and
  378. another pointer.  We define StartOfList to point to the first
  379. record created, and we will leave it unchanged throughout the
  380. program.  The pointer StartOfList will always point to the
  381. first record in the linked list which we are building up.
  382.  
  383. We define the three variables in the record to be any name we
  384. desire for illustrative purposes, and set the pointer in the
  385. record to NIL.  NIL is a reserved word that doesn't put an
  386. address in the pointer but defines it as empty.  A pointer
  387. that is currently NIL cannot be used to access any data
  388. because it has no value, but it can be tested in a logical
  389. statement to see if it is NIL.  It is therefore a dummy
  390. assignment.  With all of that, the first record is completely
  391. defined, and the data space is illustrated in figure 12-7.
  392.  
  393.  
  394. DEFINING THE SECOND RECORD
  395. ______________________________________________________________
  396.  
  397. When you were young you may have played a searching game in
  398. which you were given a clue telling you where the next clue
  399. was at.  The next clue had a clue to the location of the third
  400. clue.  You kept going from clue to clue until you found the
  401. prize.  You simply exercised a linked list.  We will now build
  402. up the same kind of a list in which each record will tell us
  403. where the next record is at.
  404.  
  405. We will now define the second record.  Our goal will be to
  406. store a pointer to the second record in the pointer field of
  407. the first record.  In order to keep track of the last record,
  408. the one in which we need to update the pointer, we will keep
  409.  
  410.                                                           12-7
  411.  
  412.                   Chapter 12 - Pointers and Dynamic Allocation
  413.  
  414. a pointer to it in TempPlace, which we do in line 35.  Now we
  415. can create another new record in line 36 and use PlaceInList
  416. to point to it.  Since TempPlace is still pointing at the
  417. first record, we can use it to store the value of the pointer
  418. to the new record in the old record which we do in line 37.
  419. The 3 data fields of the new record are assigned nonsense data
  420. in lines 38 through 40 for our illustration, and the pointer
  421. field of the new record is assigned NIL.  See figure 12-8.
  422.  
  423. Let's review our progress to this point.  We now have the
  424. first record with a name, composed of 3 parts stored in it,
  425. and a pointer to the second record.  We also have a second
  426. record storing a different name and a pointer assigned NIL.
  427. We also have three pointers, one pointing to the first record,
  428. one pointing to the last record, and one we used just to get
  429. here since it is only a temporary pointer.  If you understand
  430. what is happening so far, let's go on to add some additional
  431. records to the list.  If you are confused, go back over this
  432. material again.
  433.  
  434.  
  435. TEN MORE RECORDS
  436. ______________________________________________________________
  437.  
  438. The next section of code beginning in line 45, is contained
  439. within a FOR loop so the statements are simply repeated ten
  440. times.  If you observe carefully, you will notice that the
  441. statements are identical to the second group of statements in
  442. the program (except of course for the name assigned).  They
  443. operate in exactly the same manner, and we end up with ten
  444. more names added to the list.  You will now see why the
  445. temporary pointer was necessary, but pointers are cheap, so
  446. feel free to use them at will.  A pointer generally uses only
  447. 4 bytes of memory.
  448.  
  449. One additional feature is illustrated in line 47.  The
  450. function procedure named Available is used to determine if
  451. there is enough space available on the heap to allocate the
  452. record.  This function procedure call passes the desired size
  453. to the procedure which returns a boolean value.  In this case,
  454. because the program is so small, we ignore the result, but a
  455. meaningful program should test prior to each allocation call
  456. and if it got a false returned, it would need to perform some
  457. error recovery routine.
  458.  
  459. After one pass through the loop, the data space will appear
  460. as shown in figure 12-9.  Each pass through the loop will add
  461. one new record to the list.  Further graphs will not be drawn
  462. but will be left to the student to draw, if he so desires.
  463.  
  464. After completing the loop in lines 46 through 54, we have a
  465. linked list of twelve entries.  We have a pointer pointing at
  466. the first entry, and another pointer pointing at the last.
  467. The only data stored within the program itself are three
  468.  
  469.                                                           12-8
  470.  
  471.                   Chapter 12 - Pointers and Dynamic Allocation
  472.  
  473. pointers, and one integer, all of the dynamically allocated
  474. data is on the heap.  This is one advantage to a linked list,
  475. it uses very little internal memory, but it is costly in terms
  476. of programming.  You should never use a linked list simply to
  477. save memory, but only because a certain program lends itself
  478. well to it.  Some sorting routines are extremely fast because
  479. they use a linked list, and it could be advantageous to use
  480. in a database.
  481.  
  482.  
  483. HOW DO WE GET TO THE DATA NOW?
  484. ______________________________________________________________
  485.  
  486. Since the data is in a list, how can we get a copy of the
  487. fourth entry, for example?  The only way is to start at the
  488. beginning of the list and successively examine pointers until
  489. you reach the desired one.  Suppose you are at the fourth and
  490. then wish to examine the third.  You cannot back up, because
  491. you didn't define the list that way, you can only start at the
  492. beginning and count to the third.  You could have defined the
  493. record with two pointers, one pointing forward, and one
  494. pointing backward.  This would be a doubly-linked list and you
  495. could then go directly from entry four to entry three.
  496.  
  497. Now that the list is defined, we will read the data from the
  498. list and display it on the video monitor in lines 58 through
  499. 66.  We begin by defining the pointer, PlaceInList, as the
  500. start of the list.  Now you see why it was important to keep
  501. a copy of where the list started.  In the same manner as
  502. filling the list, we go from record to record until we find
  503. the record with the value of NIL stored in its pointer.
  504.  
  505. Finally, it is necessary to deallocate the list, being careful
  506. to check for the ending NIL value before you deallocate it.
  507. It will be left for you to deallocate the records if you have
  508. such a desire.
  509.  
  510. There are entire books on how to use linked lists, and some
  511. Modula-2 programmers will seldom, if ever, use them.  For this
  512. reason, additional detail is considered unnecessary, but to
  513. be a fully informed Modula-2 programmer, some insight into
  514. linked lists is necessary.
  515.  
  516.  
  517. PROGRAMMING EXERCISES
  518. ______________________________________________________________
  519.  
  520. 1.   Write a program to store a few names dynamically, then
  521.      display the stored names on the monitor.  As your first
  522.      exercise in dynamic allocation, keep it very simple.
  523.  
  524. 2.   Add the necessary code to LINKLIST.MOD to deallocate all
  525.      of the records.
  526.  
  527.  
  528.                                                           12-9
  529.  
  530.                   Chapter 12 - Pointers and Dynamic Allocation
  531.  
  532. Note; The figures referred to in this chapter are graphics
  533.       which are impossible to include in a text file.  Since
  534.       there is no way to include them, we have made it possi-
  535.       ble for you to obtain a copy of these figures.  See the
  536.       READ.ME file for details.
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584.  
  585.                                                          12-10
  586.  
  587.