📄 ch11.htm
字号:
Cat #500: 999
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>Line 26 declares the array
<TT>Family</TT>, which holds 500 <TT>CAT</TT> objects. The entire array is created
on the free store with the call to <TT>new</TT> <TT>CAT[500]</TT>.<BR>
<BR>
Each <TT>CAT</TT> object added to the array also is created on the free store (line
31). Note, however, that the pointer isn't added to the array this time; the object
itself is. This array isn't an array of pointers to <TT>CAT</TT>s. It is an array
of <TT>CAT</TT>s.
<H3 ALIGN="CENTER"><A NAME="Heading36"></A><FONT COLOR="#000077">Deleting Arrays
on the Free Store</FONT></H3>
<P><TT>Family</TT> is a pointer, a pointer to the array on the free store. When,
on line 33, the pointer <TT>pCat</TT> is dereferenced, the <TT>CAT</TT> object itself
is stored in the array (why not? the array is on the free store). But <TT>pCat</TT>
is used again in the next iteration of the loop. Isn't there a danger that there
will now be no pointer to that <TT>CAT</TT> object, and a memory leak has been created?</P>
<P>This would be a big problem, except that deleting <TT>Family</TT> returns all
the memory set aside for the array. The compiler is smart enough to destroy each
object in the array and to return its memory to the free store.</P>
<P>To see this, change the size of the array from 500 to 10 in lines 26, 29, and
37. Then uncomment the <TT>cout</TT> statement in line 21. When line 40 is reached
and the array is destroyed, each <TT>CAT</TT> object destructor is called.</P>
<P>When you create an item on the heap by using <TT>new</TT>, you always delete that
item and free its memory with <TT>delete</TT>. Similarly, when you create an array
by using <TT>new <class>[size]</TT>, you delete that array and free all its
memory with <TT>delete[]</TT>. The brackets signal the compiler that this array is
being deleted.</P>
<P>If you leave the brackets off, only the first object in the array will be deleted.
You can prove this to yourself by removing the bracket on line 40. If you edited
line 21 so that the destructor prints, you should now see only one <TT>CAT</TT> object
destroyed. Congratulations! You just created a memory leak.
<BLOCKQUOTE>
<P>
<HR>
<B>DO</B> remember that an array of n items is numbered from zero through n-1. <B>DON'T</B>
write or read past the end of an array. <B>DON'T</B> confuse an array of pointers
with a pointer to an array. <B>DO </B>use array indexing with pointers that point
to arrays.
<HR>
</BLOCKQUOTE>
<H3 ALIGN="CENTER"><A NAME="Heading37"></A><FONT COLOR="#000077">char Arrays</FONT></H3>
<P>A string is a series of characters. The only strings you've seen until now have
been unnamed string constants used in <TT>cout</TT> statements, such as</P>
<PRE><FONT COLOR="#0066FF">cout << "hello world.\n";
</FONT></PRE>
<P>In C++ a string is an array of <TT>char</TT>s ending with a null character. You
can declare and initialize a string just as you would any other array. For example,</P>
<PRE><FONT COLOR="#0066FF">char Greeting[] =
{ `H', `e', `l', `l', `o', ` `, `W','o','r','l','d', `\0' };
</FONT></PRE>
<P>The last character, <TT>`\0'</TT>, is the null character, which many C++ functions
recognize as the terminator for a string. Although this character-by-character approach
works, it is difficult to type and admits too many opportunities for error. C++ enables
you to use a shorthand form of the previous line of code. It is</P>
<PRE><FONT COLOR="#0066FF">char Greeting[] = "Hello World";
</FONT></PRE>
<P>You should note two things about this syntax:
<UL>
<LI>Instead of single quoted characters separated by commas and surrounded by braces,
you have a double-quoted string, no commas, and no braces.
<P>
<LI>You don't need to add the null character because the compiler adds it for you.
</UL>
<P>The string <TT>Hello World</TT> is 12 bytes. <TT>Hello</TT> is 5 bytes, the space
1, <TT>World</TT> 5, and the null character 1.</P>
<P>You can also create uninitialized character arrays. As with all arrays, it is
important to ensure that you don't put more into the buffer than there is room for.</P>
<P>Listing 11.8 demonstrates the use of an uninitialized buffer.</P>
<P><A NAME="Heading38"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.8. Filling
an array.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1: //Listing 11.8 char array buffers
2:
3: #include <iostream.h>
4:
5: int main()
6: {
7: char buffer[80];
8: cout << "Enter the string: ";
9: cin >> buffer;
10: cout << "Here's the buffer: " << buffer << endl;
11: return 0;
<TT>12: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Enter the string: Hello World
Here's the buffer: Hello
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis: </B></FONT>On line 7, a buffer is declared
to hold 80 characters. This is large enough to hold a 79-character string and a terminating
null character.<BR>
On line 8, the user is prompted to enter a string, which is entered into buffer on
line 9. It is the syntax of <TT>cin</TT> to write a terminating null to buffer after
it writes the string.</P>
<P>There are two problems with the program in Listing 11.8. First, if the user enters
more than 79 characters, <TT>cin</TT> writes past the end of the buffer. Second,
if the user enters a space, <TT>cin</TT> thinks that it is the end of the string,
and it stops writing to the buffer.</P>
<P>To solve theseproblems, you must call a special method on <TT>cin</TT>: <TT>get()</TT>.
<TT>cin.get()</TT> takes three parameters:
<DL>
<DD>The buffer to fill<BR>
<BR>
The maximum number of characters to get<BR>
<BR>
The delimiter that terminates input
</DL>
<P><BR>
The default delimiter is <TT>newline</TT>. Listing 11.9 illustrates its use.</P>
<P><A NAME="Heading40"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.9. Filling
an array.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1: //Listing 11.9 using cin.get()
2:
3: #include <iostream.h>
4:
5: int main()
6: {
7: char buffer[80];
8: cout << "Enter the string: ";
9: cin.get(buffer, 79); // get up to 79 or newline
10: cout << "Here's the buffer: " << buffer << endl;
11: return 0;
<TT>12: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Enter the string: Hello World
Here's the buffer: Hello World
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis</B></FONT><B>: </B>Line 9 calls the method <TT>get()</TT>
of <TT>cin</TT>. The buffer declared in line 7 is passed in as the first argument.
The second argument is the maximum number of characters to get. In this case, it
must be 79 to allow for the terminating <TT>null</TT>. There is no need to provide
a terminating character because the default value of <TT>newline</TT> is sufficient.<BR>
<TT><BR>
cin</TT> and all its variations are covered on Day 17, "The Preprocessor,"
when streams are discussed in depth.
<H3 ALIGN="CENTER"><A NAME="Heading41"></A><FONT COLOR="#000077">strcpy() and strncpy()</FONT></H3>
<P>C++ inherits from C a library of functions for dealing with strings. Among the
many functions provided are two for copying one string into another: <TT>strcpy()</TT>
and <TT>strncpy()</TT>. <TT>strcpy()</TT> copies the entire contents of one string
into a designated buffer. Listing 11.10 demonstrates the use of <TT>strcpy()</TT>.</P>
<P><A NAME="Heading42"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.10. Using
strcpy().</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1: #include <iostream.h>
2: #include <string.h>
3: int main()
4: {
5: char String1[] = "No man is an island";
6: char String2[80];
7:
8: strcpy(String2,String1);
9:
10: cout << "String1: " << String1 << endl;
11: cout << "String2: " << String2 << endl;
12: return 0;
<TT>13: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: String1: No man is an island
String2: No man is an island
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>The header file <TT>string.h</TT>
is included in line 2. This file contains the prototype of the <TT>strcpy()</TT>
function. <TT>strcpy()</TT> takes two character arrays--a destination followed by
a source. If the source were larger than the destination, <TT>strcpy()</TT> would
overwrite past the end of the buffer.<BR>
<BR>
To protect against this, the standard library also includes <TT>strncpy()</TT>. This
variation takes a maximum number of characters to copy. <TT>strncpy()</TT> copies
up to the first null character or the maximum number of characters specified into
the destination buffer.</P>
<P>Listing 11.11 illustrates the use of<TT> strncpy()</TT>.</P>
<P><A NAME="Heading43"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.11. Using
strncpy().</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1: #include <iostream.h>
2: #include <string.h>
3: int main()
4: {
5: const int MaxLength = 80;
6: char String1[] = "No man is an island";
7: char String2[MaxLength+1];
8:
9:
10: strncpy(String2,String1,MaxLength);
11:
12: cout << "String1: " << String1 << endl;
13: cout << "String2: " << String2 << endl;
14: return 0;
<TT>15: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: String1: No man is an island
String2: No man is an island
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>In line 10, the call to <TT>strcpy()</TT>
has been changed to a call to <TT>strncpy()</TT>, which takes a third parameter:
the maximum number of characters to copy. The buffer <TT>String2</TT> is declared
to take <TT>MaxLength+1</TT> characters. The extra character is for the null, which
both <TT>strcpy()</TT> and <TT>strncpy()</TT> automatically add to the end of the
string.
<H3 ALIGN="CENTER"><A NAME="Heading44"></A><FONT COLOR="#000077">String Classes</FONT></H3>
<P>Most C++ compilers come with a class library that includes a large set of classes
for data manipulation. A standard component of a class library is a <TT>String</TT>
class.</P>
<P>C++ inherited the null-terminated string and the library of functions that includes
<TT>strcpy()</TT> from C, but these functions aren't integrated into an object-oriented
framework. A <TT>String</TT> class provides an encapsulated set of data and functions
for manipulating that data, as well as accessor functions so that the data itself
is hidden from the clients of the <TT>String</TT> class.</P>
<P>If your compiler doesn't already provide a <TT>String</TT> class--and perhaps
even if it does--you might want to write your own. The remainder of this chapter
discusses the design and partial implementation of <TT>String</TT> classes.</P>
<P>At a minimum, a <TT>String</TT> class should overcome the basic limitations of
character arrays. Like all arrays, character arrays are static. You define how large
they are. They always take up that much room in memory even if you don't need it
all. Writing past the end of the array is disastrous.</P>
<P>A good <TT>String</TT> class allocates only as much memory as it needs, and always
enough to hold whatever it is given. If it can't allocate enough memory, it should
fail gracefully.</P>
<P>Listing 11.12 provides a first approximation of a <TT>String</TT> class.</P>
<P><A NAME="Heading45"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 11.12. Using
a String class.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1: //Listing 11.12
2:
3: #include <iostream.h>
4: #include <string.h>
5:
6: // Rudimentary string class
7: class String
8: {
9: public:
10: // constructors
11: String();
12: String(const char *const);
13: String(const String &);
14: ~String();
15:
16: // overloaded operators
17: char & operator[](unsigned short offset);
18: char operator[](unsigned short offset) const;
19: String operator+(const String&);
20: void operator+=(const String&);
21: String & operator= (const String &);
22:
23: // General accessors
24: unsigned short GetLen()const { return itsLen; }
25: const char * GetString() const { return itsString; }
26:
27: private:
28: String (unsigned short); // private constructor
29: char * itsString;
30: unsigned short itsLen;
31: };
32:
33: // default constructor creates string of 0 bytes
34: String::String()
35: {
36: itsString = new char[1];
37: itsString[0] = `\0';
38: itsLen=0;
39: }
40:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -