📄 ch11.htm
字号:
Arrays</FONT></H3>
<P>You can initialize multidimensional arrays. You assign the list of values to array
elements in order, with the last array subscript changing while each of the former
holds 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 }
</FONT></PRE>
<P>For the sake of clarity, you could group the initializations with braces. For
example,</P>
<PRE><FONT COLOR="#0066FF">int theArray[5][3] = { {1,2,3},
{4,5,6},
{7,8,9},
{10,11,12},
{13,14,15} };
</FONT></PRE>
<P>The compiler ignores the inner braces, which make it easier to understand how
the numbers are distributed.</P>
<P>Each value must be separated by a comma, without regard to the braces. The entire
initialization set must be within braces, and it must end with a semicolon.</P>
<P>Listing 11.5 creates a two-dimensional array. The first dimension is the set of
numbers from 0 to 5. The second dimension consists of the double of each value in
the first dimension.</P>
<P><A NAME="Heading24"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.5. Creating
a multidimensional array.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1: #include <iostream.h>
2: int main()
3: {
4: int SomeArray[5][2] = { {0,0}, {1,2}, {2,4}, {3,6}, {4,8}};
5: for (int i = 0; i<5; i++)
6: for (int j=0; j<2; j++)
7: {
8: cout << "SomeArray[" << i << "][" << j << "]: ";
9: cout << SomeArray[i][j]<< endl;
10: }
11:
12: return 0;
<TT>13: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: SomeArray[0][0]: 0
SomeArray[0][1]: 0
SomeArray[1][0]: 1
SomeArray[1][1]: 2
SomeArray[2][0]: 2
SomeArray[2][1]: 4
SomeArray[3][0]: 3
SomeArray[3][1]: 6
SomeArray[4][0]: 4
SomeArray[4][1]: 8
</FONT></PRE>
<P><FONT COLOR="#0000AA"><B>Analysis:</B></FONT><B> </B>Line 4 declares <TT>SomeArray</TT>
to be a two-dimensional array. The first dimension consists of five integers; the
second dimension consists of two integers. This creates a 5x2 grid, as Figure 11.4
shows. <BR>
<A HREF="11zcp04.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch11/11zcp04.jpg"><BR>
</A><A NAME="Heading26"></A><A HREF="11zcp04.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch11/11zcp04.jpg"><FONT COLOR="#000077">Figure
11.4.</FONT></A><FONT COLOR="#000077"> </FONT><I>A 5x2 array. </I><BR>
<BR>
The values are initialized in pairs, although they could be computed as well. Lines
5 and 6 create a nested <TT>for</TT> loop. The outer <TT>for</TT> loop ticks through
each member of the first dimension. For every member in that dimension, the inner
<TT>for</TT> loop ticks through each member of the second dimension. This is consistent
with the printout. <TT>SomeArray[0][0]</TT> is followed by <TT>SomeArray[0][1]</TT>.
The first dimension is incremented only after the second dimension is incremented
by 1. Then the second dimension starts over.
<H3 ALIGN="CENTER"><A NAME="Heading27"></A><FONT COLOR="#000077">A Word About Memory</FONT></H3>
<P>When you declare an array, you tell the compiler exactly how many objects you
expect to store in it. The compiler sets aside memory for all the objects, even if
you never use it. This isn't a problem with arrays for which you have a good idea
of how many objects you'll need. For example, a chess board has 64 squares, and cats
have between 1 and 10 kittens. When you have no idea of how many objects you'll need,
however, you must use more advanced data structures.</P>
<P>This book looks at arrays of pointers, arrays built on the free store, and various
other collections. Other more advanced data structures that solve large data storage
problems are beyond the scope of this book. Two of the great things about programming
are that there are always more things to learn and that there are always more books
from which to learn.
<H3 ALIGN="CENTER"><A NAME="Heading28"></A><FONT COLOR="#000077">Arrays of Pointers</FONT></H3>
<P>The arrays discussed so far store all their members on the stack. Usually stack
memory is severely limited, whereas free store memory is far larger. It is possible
to declare each object on the free store and then to store only a pointer to the
object in the array. This dramatically reduces the amount of stack memory used. Listing
11.6 rewrites the array from Listing 11.4, but it stores all the objects on the free
store. As an indication of the greater memory that this enables, the array is expanded
from 5 to 500, and the name is changed from <TT>Litter</TT> to <TT>Family</TT>.</P>
<P><A NAME="Heading29"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.6. Storing
an array on the free store.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1: // Listing 11.6 - An array of pointers to objects
2:
3: #include <iostream.h>
4:
5: class CAT
6: {
7: public:
8: CAT() { itsAge = 1; itsWeight=5; }
9: ~CAT() {} // destructor
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 * Family[500];
22: int i;
23: CAT * pCat;
24: for (i = 0; i < 500; i++)
25: {
26: pCat = new CAT;
27: pCat->SetAge(2*i +1);
28: Family[i] = pCat;
29: }
30:
31: for (i = 0; i < 500; i++)
32: {
33: cout << "Cat #" << i+1 << ": ";
34: cout << Family[i]->GetAge() << endl;
35: }
36: return 0;
<TT>37: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Cat #1: 1
Cat #2: 3
Cat #3: 5
...
Cat #499: 997
Cat #500: 999</FONT></PRE>
<DL>
<DD><FONT COLOR="#0066FF"></FONT>
</DL>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>The <TT>CAT</TT> object declared
in lines 5-17 is identical with the <TT>CAT</TT> object declared in Listing 11.4.
This time, however, the array declared in line 21 is named <TT>Family</TT>, and it
is declared to hold 500 pointers to <TT>CAT</TT> objects.</P>
<P>In the initial loop (lines 24-29), 500 new <TT>CAT</TT> objects are created on
the free store, and each one has its age set to twice the index plus one. Therefore,
the first <TT>CAT</TT> is set to <TT>1</TT>, the second <TT>CAT</TT> to <TT>3</TT>,
the third <TT>CAT</TT> to <TT>5</TT>, and so on. Finally, the pointer is added to
the array.</P>
<P>Because the array has been declared to hold pointers, the pointer--rather than
the dereferenced value in the pointer--is added to the array.</P>
<P>The second loop (lines 31 and 32) prints each of the values. The pointer is accessed
by using the index, <TT>Family[i]</TT>. That address is then used to access the <TT>GetAge()</TT>
method.</P>
<P>In this example, the array <TT>Family</TT> and all its pointers are stored on
the stack, but the 500 <TT>CAT</TT>s that are created are stored on the free store.
<H3 ALIGN="CENTER"><A NAME="Heading31"></A><FONT COLOR="#000077">Declaring Arrays
on the Free Store</FONT></H3>
<P>It is possible to put the entire array on the free store, also known as the heap.
You do this by calling <TT>new</TT> and using the subscript operator. The result
is a pointer to an area on the free store that holds the array. For example,</P>
<PRE><FONT COLOR="#0066FF">CAT *Family = new CAT[500];
</FONT></PRE>
<P>declares <TT>Family</TT> to be a pointer to the first in an array of 500 <TT>CAT</TT>s.
In other words, <TT>Family</TT> points to--or has the address of--<TT>Family[0]</TT>.</P>
<P>The advantage of using <TT>Family</TT> in this way is that you can use pointer
arithmetic to access each member of <TT>Family</TT>. For example, you can write</P>
<PRE><FONT COLOR="#0066FF">CAT *Family = new CAT[500];
CAT *pCat = Family; //pCat points to Family[0]
pCat->SetAge(10); // set Family[0] to 10
pCat++; // advance to Family[1]
pCat->SetAge(20); // set Family[1] to 20
</FONT></PRE>
<P>This declares a new array of 500 <TT>CAT</TT>s and a pointer to point to the start
of the array. Using that pointer, the first <TT>CAT</TT>'s <TT>SetAge()</TT> function
is called with a value of <TT>10</TT>. The pointer is then incremented to point to
the next <TT>CAT</TT>, and the second <TT>Cat</TT>'s <TT>SetAge()</TT> method is
then called.
<H3 ALIGN="CENTER"><A NAME="Heading32"></A><FONT COLOR="#000077">A Pointer to an
Array Versus an Array of Pointers</FONT></H3>
<P>Examine these three declarations:</P>
<PRE><FONT COLOR="#0066FF">1: Cat FamilyOne[500]
2: CAT * FamilyTwo[500];
3: CAT * FamilyThree = new CAT[500];
</FONT></PRE>
<P><TT>FamilyOne</TT> is an array of 500 <TT>CAT</TT>s. <TT>FamilyTwo</TT> is an
array of 500 pointers to <TT>CAT</TT>s. <TT>FamilyThree</TT> is a pointer to an array
of 500 <TT>CAT</TT>s.</P>
<P>The differences among these three code lines dramatically affect how these arrays
operate. What is perhaps even more surprising is that <TT>FamilyThree</TT> is a variant
of <TT>FamilyOne</TT>, but is very different from <TT>FamilyTwo</TT>.</P>
<P>This raises the thorny issue of how pointers relate to arrays. In the third case,
<TT>FamilyThree</TT> is a pointer to an array. That is, the address in <TT>FamilyThree</TT>
is the address of the first item in that array. This is exactly the case for <TT>FamilyOne</TT>.
<H3 ALIGN="CENTER"><A NAME="Heading33"></A><FONT COLOR="#000077">Pointers and Array
Names</FONT></H3>
<P>In C++ an array name is a constant pointer to the first element of the array.
Therefore, in the declaration</P>
<PRE><FONT COLOR="#0066FF">CAT Family[50];
</FONT></PRE>
<P><TT>Family</TT> is a pointer to <TT>&Family[0]</TT>, which is the address
of the first element of the array <TT>Family</TT>.</P>
<P>It is legal to use array names as constant pointers, and vice versa. Therefore,
<TT>Family + 4</TT> is a legitimate way of accessing the data at <TT>Family[4]</TT>.</P>
<P>The compiler does all the arithmetic when you add to, increment, and decrement
pointers. The address accessed when you write <TT>Family + 4</TT> isn't 4 bytes past
the address of <TT>Family</TT>--it is four objects. If each object is 4 bytes long,
<TT>Family + 4</TT> is 16 bytes. If each object is a <TT>CAT</TT> that has four <TT>long</TT>
member variables of 4 bytes each and two <TT>short</TT> member variables of 2 bytes
each, each <TT>CAT</TT> is 20 bytes, and <TT>Family + 4</TT> is 80 bytes past the
start of the array.</P>
<P>Listing 11.7 illustrates declaring and using an array on the free store.</P>
<P><A NAME="Heading34"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.7. Creating
an array by using new.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1: // Listing 11.7 - An array on the free store
2:
3: #include <iostream.h>
4:
5: class CAT
6: {
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: CAT :: ~CAT()
20: {
21: // cout << "Destructor called!\n";
22: }
23:
24: int main()
25: {
26: CAT * Family = new CAT[500];
27: int i;
28: CAT * pCat;
29: for (i = 0; i < 500; i++)
30: {
31: pCat = new CAT;
32: pCat->SetAge(2*i +1);
33: Family[i] = *pCat;
34: delete pCat;
35: }
36:
37: for (i = 0; i < 500; i++)
38: {
38: cout << "Cat #" << i+1 << ": ";
39: cout << Family[i].GetAge() << endl;
40: }
41:
42: delete [] Family;
43:
44: return 0;
<TT>45: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Cat #1: 1
Cat #2: 3
Cat #3: 5
...
Cat #499: 997
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -