home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / lang / c / 19300 < prev    next >
Encoding:
Internet Message Format  |  1993-01-06  |  5.9 KB

  1. Path: sparky!uunet!mcsun!sun4nl!and!jos
  2. From: jos@and.nl (Jos Horsmeier)
  3. Newsgroups: comp.lang.c
  4. Subject: Re: Moving from Pascal to C, Help please!!!!!!
  5. Message-ID: <4293@dozo.and.nl>
  6. Date: 6 Jan 93 10:46:18 GMT
  7. References: <78858@hydra.gatech.EDU> <C04E63.863@newcastle.ac.uk> <1993Jan5.162504.1680@leland.Stanford.EDU>
  8. Organization: AND Software BV Rotterdam
  9. Lines: 147
  10.  
  11. In article <1993Jan5.162504.1680@leland.Stanford.EDU> dkeisen@leland.Stanford.EDU (Dave Eisen) writes:
  12. |In article <C04E63.863@newcastle.ac.uk> Raj.Subramani@newcastle.ac.uk (D. Subramani) writes:
  13. |>
  14. |>I would recommend that you have a look at "Numerical Recipies in C"
  15. |>'cause there they explain how arrays of 2-D are pointers to a pointer
  16. |>and so on which no one else does. Also they have a few routines that
  17. |>allocate memory as per your requirement, ie. [6...26] etc. but be 
  18. |>warned, when you do that you will not be able to exploit the advantages
  19. |>of pointer arethmatic fully (it will be too confusing).
  20.  
  21. |I've never read this book, but I sincerely hope that they do
  22. |not explain that 2D arrays are pointers to pointers because
  23. |they most certainly are not. This distinction is not fully
  24. |understood by a large number of new C programmers and a question
  25. |about it appears here every week or two. I would hate to think
  26. |that popular books like "Numerical Recipes in C" are contributing
  27. |to this misunderstanding.
  28.  
  29. IMHO `Numerical Recipes in C' is a fine book when one needs to implement
  30. one or more of those nifty, clever numerical algorithms. Also IMHO this
  31. book is a horrible mess when it comes to the usage of the C language.
  32. I've read this book and it gave me the shivers. The authors should have
  33. sticked to FORTRAN or Pascal. They've really made a mess out of things
  34. when they made the transition to C.
  35.  
  36. |I can tolerate what they do with arrays ranging from 6 to 26 because
  37. |while it is not legal C, it does work on every system I've ever
  38. |heard about. Still, it would be nice if they had gotten this
  39. |right too.
  40.  
  41. Then you've just been plain lucky and so were the authors of NRC. 99%
  42. of all their pointer fiddling (subtracting the lowest index value from a
  43. pointer) is done with an offset of one. Imagine a segmented memory
  44. architecture as used in a PC. Global arrays are almost never stored
  45. at the beginning of a segment, so the offset of the address of such
  46. an array is always larger than one. Pointer arithmetic is almost always
  47. done using the offset. The segment value is ignored. The same thing is
  48. valid for dynamically allocated memory. Most implementations of the
  49. malloc() function I've seen, prepend the size of the allocated block
  50. in front of that block. This results in an offset of at least two.
  51. In both cases, subracting one from a pointer value, described above,
  52. can do no harm. But if one tries to subtract six (as in your example)
  53. from such a pointer value, please let me know in advance: the behavior
  54. is undefined and no one can tell what's gonna happen then. Maybe the
  55. PC will explode? Who knows ... ;-)
  56.  
  57. About 2D arrays being an array of pointers, pointing to 1D arrays:
  58. As you wrote, a lot of people get it wrong when they start programming
  59. in C. Lets have a look what the standard has to say about all this:
  60.  
  61. the standard may cause a bit of confusion when not interpreted 
  62. correctly. 3.3.2.1. Array subscripting:
  63.  
  64. Successive subscript operators designate an element of a multidimensional
  65. array object. If E is an n-dimensional array (n >= 2) with dimensions
  66. i*j* ... *k, then E (used as other than an lvalue) is converted to a
  67. pointer to an (n-1) dimensional array with dimensions j* ... *k. If the
  68. unary * operator is applied to this pointer explicitely, or implicitely
  69. as a result of subscripting, the result is the pointed to (n-1) dimen-
  70. sional array, which itself is converted into a pointer if used as
  71. other than an lvalue. [ ... ]
  72.  
  73. All this pointer conversion stuff may confuse the reader. All what this
  74. paragraph says, is, that when used in an _expression_, the (partly)
  75. subscripted array is converted to a pointer. Those pointer values
  76. aren't stored anywhere in that array.
  77.  
  78. Another paragraph takes the confusion away: 3.3.6 Additive operators:
  79.  
  80. footnote:
  81.  
  82. Another way to approach pointer arithmetic is first to convert the
  83. pointer(s) to character pointer(s): [ ... ] For pointer subtracion,
  84. the result of the difference between the character pointers is 
  85. similarly divided by the size of the object originally pointed to.
  86.  
  87. Now assume that the following definition:
  88.  
  89. int a[2][3];
  90.  
  91. results in a memory layout like this (an array of pointers to arrays):
  92.  
  93.            p
  94.                   |
  95.      +---+     v
  96.      |   |    +--+--+--+
  97.      | ------>|00|01|02|
  98.      |   |    +--+--+--+
  99.      +---+
  100.      |   |    +--+--+--+
  101.      | ------>|10|11|12|
  102.      |   |    +--+--+--+
  103.      +---+            ^
  104.               |
  105.               q
  106.  
  107. Lets have a look at the following snippet of code:
  108.  
  109. int *p= &(a[0][0]);
  110. int *q= &(a[1][2]);
  111.  
  112. The result of (q-p) has to be 5. But in this implementation, pointers p
  113. and q don't even point to the same object. The same paragraph as quoted
  114. above, reads: 3.3.6. Additive operators:
  115.  
  116. Unless both pointers point to elements of the same array object, [ ... ] 
  117. the behaviour is undefined.
  118.  
  119. So, the memory layout described above is not a valid implementation 
  120. for a 2D array. The array a can simply be implemented as:
  121.  
  122.      p
  123.      |
  124.      v
  125.     +--+--+--+
  126.     |00|01|02|
  127.     +--+--+--+
  128.     |10|11|12|
  129.     +--+--+--+
  130.                 ^
  131.         |
  132.         q
  133.  
  134. Or, since memory is a linear string of slots (bytes):
  135.  
  136.      p
  137.      |
  138.      v
  139.     +--+--+--+--+--+--+
  140.     |00|01|02|10|11|12|
  141.     +--+--+--+--+--+--+
  142.                      ^
  143.              |
  144.              q
  145.  
  146. Now, the pointer subtraction (q-p) is a breeze: simply subtract both
  147. address values and divide the result by the size of an integer.
  148. Subscripting calculations such as a[n][m] is (without further optimi-
  149. zation) done as follows: a[n][m] == *(a+(3*n+m)*sizeof(int)) where a
  150. is considered to be a simple character pointer.
  151.  
  152. kind regards,
  153.  
  154. Jos aka jos@and.nl
  155.  
  156. ps. I did not assume a row major ordering, it simply follows from the
  157.     definitions in paragraph 3.3.2.1 described above.
  158.