📄 ch11.htm
字号:
<FONT COLOR="#0066FF">Output: Test 1:TargetArray[0]: 0TargetArray[24]: 0SentinelOne[0]: 0SentinelTwo[0]: 0SentinelOne[1]: 0SentinelTwo[1]: 0SentinelOne[2]: 0SentinelTwo[2]: 0Assigning...Test 2:TargetArray[0]: 20TargetArray[24]: 20TargetArray[25]: 20SentinelOne[0]: 20SentinelTwo[0]: 0SentinelOne[1]: 0SentinelTwo[1]: 0SentinelOne[2]: 0SentinelTwo[2]: 0</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis: </B></FONT>Lines 9 and 10 declare two arraysof three integers that act as sentinels around <TT>TargetArray</TT>. These sentinelarrays are initialized with the value <TT>0</TT>. If memory is written to beyondthe end of <TT>TargetArray</TT>, the sentinels are likely to be changed. Some compilerscount down in memory; others count up. For this reason, the sentinels are placedon both sides of <TT>TargetArray</TT>.<BR><BR>Lines 19-29 confirm the sentinel values in Test 1. In line 33 <TT>TargetArray</TT>'smembers are all initialized to the value <TT>20</TT>, but the counter counts to <TT>TargetArray</TT>offset 25, which doesn't exist in <TT>TargetArray</TT>.</P><P>Lines 36-38 print <TT>TargetArray</TT>'s values in Test 2. Note that <TT>TargetArray[25]</TT>is perfectly happy to print the value <TT>20</TT>. However, when <TT>SentinelOne</TT>and <TT>SentinelTwo</TT> are printed, <TT>SentinelTwo[0]</TT> reveals that its valuehas changed. This is because the memory that is 25 elements after <TT>TargetArray[0]</TT>is the same memory that is at <TT>SentinelTwo[0]</TT>. When the nonexistent <TT>TargetArray[0]</TT>was accessed, what was actually accessed was <TT>SentinelTwo[0]</TT>.</P><P>This nasty bug can be very hard to find, because <TT>SentinelTwo[0]</TT>'s valuewas changed in a part of the code that was not writing to <TT>SentinelTwo</TT> atall.</P><P>This code uses "magic numbers" such as 3 for the size of the sentinelarrays and 25 for the size of <TT>TargetArray</TT>. It is safer to use constants,so that you can change all these values in one place.<H3 ALIGN="CENTER"><A NAME="Heading11"></A><FONT COLOR="#000077">Fence Post Errors</FONT></H3><P>It is so common to write to one past the end of an array that this bug has itsown name. It is called a fence post error. This refers to the problem in countinghow many fence posts you need for a 10-foot fence if you need one post for everyfoot. Most people answer 10, but of course you need 11. Figure 11.2 makes this clear.<BR><BR><A NAME="Heading12"></A><A HREF="11zcp02.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch11/11zcp02.jpg"><FONT COLOR="#000077">Figure11.2.</FONT></A><FONT COLOR="#000077"> </FONT><I>Fence post errors.</I> <BR><BR>This sort of "off by one" counting can be the bane of any programmer'slife. Over time, however, you'll get used to the idea that a 25-element array countsonly to element 24, and that everything counts from 0. (Programmers are often confusedwhy office buildings don't have a floor zero. Indeed, some have been known to pushthe 4 elevator button when they want to get to the fifth floor.)<BLOCKQUOTE> <P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>Some programmers refer to <TT>ArrayName[0]</TT> as the zeroth element. Getting into this habit is a big mistake. If <TT>ArrayName[0]</TT> is the zeroth element, what is <TT>ArrayName[1]</TT>? The oneth? If so, when you see <TT>ArrayName[24]</TT>, will you realize that it is not the 24th element, but rather the 25th? It is far better to say that <TT>ArrayName[0]</TT> is at offset zero and is the first element. <HR></BLOCKQUOTE><H3 ALIGN="CENTER"><A NAME="Heading13"></A><FONT COLOR="#000077">Initializing Arrays</FONT></H3><P>You can initialize a simple array of built-in types, such as integers and characters,when you first declare the array. After the array name, you put an equal sign (<TT>=</TT>)and a list of comma-separated values enclosed in braces. For example,</P><PRE><FONT COLOR="#0066FF">int IntegerArray[5] = { 10, 20, 30, 40, 50 };</FONT></PRE><P>declares <TT>IntegerArray</TT> to be an array of five integers. It assigns <TT>IntegerArray[0]</TT>the value <TT>10</TT>, <TT>IntegerArray[1]</TT> the value <TT>20</TT>, and so forth.</P><P>If you omit the size of the array, an array just big enough to hold the initializationis created. Therefore, if you write</P><PRE><FONT COLOR="#0066FF">int IntegerArray[] = { 10, 20, 30, 40, 50 };</FONT></PRE><P>you will create exactly the same array as you did in the previous example.</P><P>If you need to know the size of the array, you can ask the compiler to computeit for you. For example,</P><PRE><FONT COLOR="#0066FF">const USHORT IntegerArrayLength;IntegerArrayLength = sizeof(IntegerArray)/sizeof(IntegerArray[0]);</FONT></PRE><P>sets the constant <TT>USHORT</TT> variable <TT>IntegerArrayLength</TT> to theresult obtained from dividing the size of the entire array by the size of each individualentry in the array. That quotient is the number of members in the array.</P><P>You cannot initialize more elements than you've declared for the array. Therefore,</P><PRE><FONT COLOR="#0066FF">int IntegerArray[5] = { 10, 20, 30, 40, 50, 60};</FONT></PRE><P>generates a compiler error because you've declared a five-member array and initializedsix values. It is legal, however, to write</P><PRE><FONT COLOR="#0066FF">int IntegerArray[5] = { 10, 20};</FONT></PRE><P>Although uninitialized array members have no guaranteed values, actually, aggregateswill be initialized to <TT>0</TT>. If you don't initialize an array member, its valuewill be set to <TT>0</TT>.<BLOCKQUOTE> <P><HR><B>DO</B> let the compiler set the size of initialized arrays. <B>DON'T</B> write past the end of the array. <B>DO</B> give arrays meaningful names, as you would with any variable.<B>DO</B> remember that the first member of the array is at offset 0. <HR></BLOCKQUOTE><H3 ALIGN="CENTER"><A NAME="Heading14"></A><FONT COLOR="#000077">Declaring Arrays</FONT></H3><P>Arrays can have any legal variable name, but they cannot have the same name asanother variable or array within their scope. Therefore, you cannot have an arraynamed <TT>myCats[5]</TT> and a variable named <TT>myCats</TT> at the same time.</P><P>You can dimension the array size with a <TT>const</TT> or with an enumeration.Listing 11.3 illustrates this.</P><P><A NAME="Heading15"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.3. Usingconsts and enums in arrays.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 11.32: // Dimensioning arrays with consts and enumerations3:4: #include <iostream.h>5: int main()6: {7: enum WeekDays { Sun, Mon, Tue, 8: Wed, Thu, Fri, Sat, DaysInWeek };9: int ArrayWeek[DaysInWeek] = { 10, 20, 30, 40, 50, 60, 70 };10:11: cout << "The value at Tuesday is: " << ArrayWeek[Tue];12: return 0;<TT>13: }</TT>Output: The value at Tuesday is: 30</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>Line 7 creates an enumerationcalled <TT>WeekDays</TT>. It has eight members. Sunday is equal to 0, and <TT>DaysInWeek</TT>is equal to 7.<BR><BR>Line 11 uses the enumerated constant <TT>Tue</TT> as an offset into the array. Because<TT>Tue</TT> evaluates to <TT>2</TT>, the third element of the array, <TT>DaysInWeek[2]</TT>,is returned and printed in line 11.<H3 ALIGN="CENTER"><A NAME="Heading17"></A><FONT COLOR="#000077">Arrays</FONT></H3><P>To declare an array, write the type of object stored, followed by the name ofthe array and a subscript with the number of objects to be held in the array. Example1</P><PRE><FONT COLOR="#0066FF">int MyIntegerArray[90];</FONT></PRE><P>Example 2</P><PRE><FONT COLOR="#0066FF">long * ArrayOfPointersToLongs[100];</FONT></PRE><P>To access members of the array, use the subscript operator. Example 1</P><PRE><FONT COLOR="#0066FF">int theNinethInteger = MyIntegerArray[8];</FONT></PRE><P>Example 2</P><PRE><FONT COLOR="#0066FF">long * pLong = ArrayOfPointersToLongs[8]</FONT></PRE><P>Arrays count from zero. An array of n items is numbered from 0 to n-1.<H3 ALIGN="CENTER"><A NAME="Heading18"></A><FONT COLOR="#000077">Arrays of Objects</FONT></H3><P>Any object, whether built-in or user-defined, can be stored in an array. Whenyou declare the array, you tell the compiler the type of object to store and thenumber of objects for which to allocate room. The compiler knows how much room isneeded for each object based on the class declaration. The class must have a defaultconstructor that takes no arguments so that the objects can be created when the arrayis defined.</P><P>Accessing member data in an array of objects is a two-step process. You identifythe member of the array by using the index operator (<TT>[ ]</TT>), and then youadd the member operator (<TT>.</TT>) to access the particular member variable. Listing11.4 demonstrates how you would create an array of five <TT>CAT</TT>s.</P><P><A NAME="Heading19"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.4. Creatingan array of objects.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 11.4 - An array of objects2:3: #include <iostream.h>4:5: class CAT6: {7: public:8: CAT() { itsAge = 1; itsWeight=5; } 9: ~CAT() {} 10: int GetAge() const { return itsAge; }11: int GetWeight() const { return itsWeight; }12: void SetAge(int age) { itsAge = age; }13:14: private:15: int itsAge;16: int itsWeight;17: };18:19: int main()20: {21: CAT Litter[5];22: int i;23: for (i = 0; i < 5; i++)24: Litter[i].SetAge(2*i +1);25:26: for (i = 0; i < 5; i++)27: {28: cout << "Cat #" << i+1<< ": ";29: cout << Litter[i].GetAge() << endl;30: }31: return 0;<TT>32: }</TT>Output: cat #1: 1cat #2: 3cat #3: 5cat #4: 7cat #5: 9</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis</B></FONT><B>: </B>Lines 5-17 declare the <TT>CAT</TT>class. The <TT>CAT</TT> class must have a default constructor so that <TT>CAT</TT>objects can be created in an array. Remember that if you create any other constructor,the compiler-supplied default constructor is not created; you must create your own.<BR><BR>The first <TT>for</TT> loop (lines 23 and 24) sets the age of each of the five <TT>CAT</TT>sin the array. The second <TT>for</TT> loop (lines 26 and 27) accesses each memberof the array and calls <TT>GetAge()</TT>.</P><P>Each individual <TT>CAT</TT>'s <TT>GetAge()</TT> method is called by accessingthe member in the array, <TT>Litter[i]</TT>, followed by the dot operator (<TT>.</TT>),and the member function.<H3 ALIGN="CENTER"><A NAME="Heading21"></A><FONT COLOR="#000077">MultidimensionalArrays</FONT></H3><P>It is possible to have arrays of more than one dimension. Each dimension is representedas a subscript in the array. Therefore, a two-dimensional array has two subscripts;a three-dimensional array has three subscripts; and so on. Arrays can have any numberof dimensions, although it is likely that most of the arrays you create will be ofone or two dimensions.</P><P>A good example of a two-dimensional array is a chess board. One dimension representsthe eight rows; the other dimension represents the eight columns. Figure 11.3 illustratesthis idea.</P><P>Suppose that you have a class named <TT>SQUARE</TT>. The declaration of an arraynamed <TT>Board</TT> that represents it would be</P><PRE><FONT COLOR="#0066FF">SQUARE Board[8][8];</FONT></PRE><P>You could also represent the same data with a one-dimensional, 64-square array.For example,</P><PRE><FONT COLOR="#0066FF">SQUARE Board[64]</FONT></PRE><P>This doesn't correspond as closely to the real-world object as the two-dimension.When the game begins, the king is located in the fourth position in the first row.Counting from zero array, that position corresponds to</P><PRE><FONT COLOR="#0066FF">Board[0][3];</FONT></PRE><P>assuming that the first subscript corresponds to <TT>row</TT>, and the secondto <TT>column</TT>. The layout of positions for the entire board is illustrated inFigure 11.3.<BR><BR><A NAME="Heading22"></A><A HREF="11zcp03.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch11/11zcp03.jpg"><FONT COLOR="#000077">Figure11.3.</FONT></A><FONT COLOR="#000077"><I> </I></FONT><I>A chess board and a two-dimensionalarray.</I><H3 ALIGN="CENTER"><A NAME="Heading23"></A><FONT COLOR="#000077">Initializing MultidimensionalArrays</FONT></H3><P>You can initialize multidimensional arrays. You assign the list of values to arrayelements in order, with the last array subscript changing while each of the formerholds steady. Therefore, if you have an array</P><PRE><FONT COLOR="#0066FF">int theArray[5][3]</FONT></PRE><P>the first three elements go into <TT>theArray[0]</TT>; the next three into <TT>theArray[1]</TT>;and so forth.</P><P>You initialize this array by writing</P><PRE><FONT COLOR="#0066FF">int theArray[5][3] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -