⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch05.htm

📁 C++ From Scratch: An Object-Oriented Approach is designed to walk novice programmers through the ana
💻 HTM
📖 第 1 页 / 共 5 页
字号:
  letter occurs in an array of characters. On line 2 the counter is initialized   to zero. On line 3 we begin a <tt>for</tt> loop that iterates through every   <tt>position</tt> in the array.</p><p>On line 5 we test each character to see whether it matches the character that   was sent in to be tested; if so, we increment the counter. Note that the braces   at lines 4 and 7 are not technically necessary, but as Donald Xie pointed out   when editing this book, they do make the code much easier to read. </p><p>Finally, on line 8 we return that value.</p><p>In Listing 5.9, on line 7, we now have a value on the right side of the assignment   that represents how many times <tt>alpha[i]</tt> occurs in <tt>thisGuess</tt>:   that is, in the array that is passed in from <tt>Play()</tt>.</p><p>On line 8, we compute the same value for the solution. The value of <tt>correct</tt>   is the lesser of these two, which we accomplish on lines 9 and 10 by using the   ternary operator to find the smaller value.</p><p>An example makes this clearer: If the solution has <i>aabba</i> and the guess   has <i>ababc</i>, we examine the first letter <i>a</i>. <tt>howMany() </tt>returns   <tt>2</tt> for the guess and <tt>3</tt> for the solution, so the player has   the lesser, <tt>2</tt>, correct.</p><p>On lines 14-18, we iterate again through the loops, this time testing on line   16 to see whether the character at a specific offset in <tt>thisGuess</tt> is   the same as the character at the same offset in the solution. If so, another   letter is in the right position.</p><p>Because <tt>correct</tt> and <tt>position</tt> were passed in as references, the   changes that are made in <tt>Score() </tt>are reflected back in <tt>Play()</tt>.   <a name="_Toc444312813"></a></p><h2> <a name="Heading15">Using ASSERT</a></h2><p>Before moving on, I want to demonstrate how this code can be made both more   reliable and more understandable through the use of <tt>ASSERT</tt>.</p><p>The purpose of <tt>ASSERT</tt> is to test your assumptions when you are debugging   your code, but to have no effect at all when you release your final production   version.</p><p>When you are debugging your code, you signal your compiler to enter <i>debug   mode</i>. When you are ready to release your program to the paying public, you   rebuild in <i>release mode</i>. Debug mode brings along a lot of debugging information   that you don't want in release mode. </p><p>Thus, in debug mode, you can write</p><pre><tt>ASSERT ( <tt>position</tt> &lt;= <tt>correct</tt> )</tt></pre><p>Here you are simultaneously documenting your belief that <tt>position</tt> must   never be larger than <tt>correct</tt>. (You can never have five in the correct   position if you only have four correct letters!) You are also testing that assertion   each time the code runs to prove that you are right. In debug mode, if <tt>position</tt>   ever is<b> </b>larger than <tt>correct</tt>, this <tt>ASSERT</tt> statement fails   and an error message is written. </p><p>When your program is ready to be released, the <tt>ASSERT</tt> macro magically   disappears and has no effect on the efficiency of your code.</p><h3> <a name="Heading16">How ASSERT Works</a></h3><p><tt>ASSERT</tt> is typically implemented as a <i>macro</i>. Macros are left   over from C; they are type-unsafe routines that are processed not by the compiler   but by the precompiler, the same beast that handles your <tt>#include</tt> and   <tt>#define</tt> statements. In fact, a macro <i>is</i> a <tt>#define</tt> statement.</p><blockquote>  <hr>  <p><b>macro</b>--A text substitution by the precompiler. Macros can act as small     subprograms.</p>  <hr></blockquote><h2> <a name="Heading17">Excursion: Macros</a></h2><p>A macro function is a symbol that is created using <tt>#define</tt>, which   takes an argument much like a function does, and which replaces the macro and   its argument with a <i>substitution string</i>. For example, you can define   the macro <tt>TWICE</tt> as follows:</p><pre><tt>#define TWICE(x) ( (x) * 2 )</tt></pre><p>Then in your code you write</p><pre><tt>TWICE(4)</tt></pre><p>The entire string <tt>TWICE(4)</tt> is removed and the value <tt>4*2</tt> is   substituted. When the precompiler sees TWICE(<tt>4)</tt>, it substitutes <tt>(   (4) * 2 )</tt>. That is just what you want because 4*2 evaluates to 8, so <tt>TWICE</tt>   will have done just the work you expected.</p><p>A macro can have more than one parameter, and each parameter can be used repeatedly   in the replacement text. Two common macros are <tt>MAX</tt> and <tt>MIN</tt>:</p><pre><tt>#define MAX(x,y) ( (x) &gt; (y) ? (x) : (y) )</tt><tt>#define MIN(x,y) ( (x) &lt; (y) ? (x) : (y) )</tt></pre><p><tt>MAX</tt> returns the larger of two values (<tt>x</tt> and <tt>y</tt>),   and <tt>MIN</tt> returns the lesser. Thus, <tt>MAX(7,5)</tt> is <tt>7</tt>,   and <tt>MIN(7,5)</tt> is <tt>5</tt>.</p><blockquote>  <hr>  <p><strong>NOTE: </strong> In a macro function definition, the opening parenthesis     for the parameter list must immediately follow the macro name, with no spaces.     The preprocessor is not as forgiving of white space as is the compiler. <a name="_Toc382902686"></a><a name="_Toc444312816"></a></p>  <hr></blockquote><h3> <a name="Heading18">Why All the Parentheses?</a></h3><p>You might be wondering why there are so many parentheses in these macros. The   preprocessor does not demand that parentheses be placed around the arguments   in the substitution string, but the parentheses help you avoid unwanted side   effects when you pass complicated values to a macro. For example, if you define   <tt>MAX</tt> as</p><pre><tt>#define MAX(x,y) x &gt; y ? x : y</tt></pre><p>and pass in the values <tt>5</tt> and <tt>7</tt>, the macro works as intended.   If you pass in a more complicated expression, however, you'll get unintended   results, as shown in Listing 5.11.</p><h4> Listing 5.11 Unintended Macro Results</h4><pre><tt>0:  </tt><tt>1:  #include &lt;iostream.h&gt;</tt><tt>2:  </tt><tt>3:  #define CUBE(a) ( (a) * (a) * (a) )</tt><tt>4:  #define THREE(a) a * a * a</tt><tt>5:  </tt><tt>6:  int main()</tt><tt>7:  {</tt><tt>8:      long x = 5;</tt><tt>9:      long y = CUBE(x);</tt><tt>10:      long z = THREE(x);</tt><tt>11:  </tt><tt>12:      cout &lt;&lt; "y: " &lt;&lt; y &lt;&lt; endl;</tt><tt>13:      cout &lt;&lt; "z: " &lt;&lt; z &lt;&lt; endl;</tt><tt>14:  </tt><tt>15:      long a = 5, b = 7;</tt><tt>16:      y = CUBE(a+b);</tt><tt>17:      z = THREE(a+b);</tt><tt>18:  </tt><tt>19:      cout &lt;&lt; "y: " &lt;&lt; y &lt;&lt; endl;</tt><tt>20:      cout &lt;&lt; "z: " &lt;&lt; z &lt;&lt; endl;</tt><tt>21:      return 0;</tt><tt>22:  }</tt><tt>***Please Insert Output icon herey: 125</tt><tt>z: 125</tt><tt>y: 1728</tt><tt>z: 82</tt></pre><p>On line 1, we use the old-fashioned iostream.h so that we can avoid using namespaces.   This is perfectly legal in C++, and it is common in writing very short demonstration   programs.</p><p>On line 3, the macro <tt>CUBE</tt> is defined, with the argument <tt>x</tt>   put into parentheses each time it is used. On line 4, the macro <tt>THREE</tt>   is defined, without the parentheses. It is intended for these macros to do exactly   the same thing: to multiply their arguments times themselves, three times.</p><p>In the first use of these macros, on line 16, the value <tt>5</tt> is given   as the parameter and both macros work fine. <tt>CUBE(5)</tt> expands to <tt>(   (5) * (5) * (5) )</tt>, which evaluates to <tt>125</tt>, and <tt>THREE(5)</tt>   expands to <tt>5 * 5 * 5</tt>, which also evaluates to <tt>125</tt>.</p><p>In the second use, on line 17, the parameter is <tt>5 + 7</tt>. In this case,   <tt>CUBE(5+7)</tt> evaluates to</p><pre><tt> ( (5+7) * (5+7) * (5+7) )</tt></pre><p>which evaluates to</p><pre><tt> ( (12) * (12) * (12) )</tt></pre><p>which in turn evaluates to <tt>1,728</tt>. <tt>THREE(5+7)</tt>, however, evaluates   to</p><pre><tt>5 + 7 * 5 + 7 * 5 + 7</tt></pre><p>Because multiplication has a higher precedence than addition, this becomes</p><pre><tt>5 + (7 * 5) + (7 * 5) + 7</tt></pre><p>which evaluates to</p><pre><tt>5 + (35) + (35) + 7</tt></pre><p>which finally evaluates to <tt>82</tt>. <a name="_Toc382902687"></a><a name="_Toc444312817"></a></p><h3> <a name="Heading19">Macros Versus Functions</a></h3><p>Macros suffer from four problems in the eyes of a C++ programmer. First, because   all macros must be defined on one line, they can be confusing if they become   large. You can extend that line by using the backslash character (<tt>\</tt>),   but large macros quickly become difficult to manage.</p><p>Second, macros are expanded inline each time they are used. This means that   if a macro is used a dozen times, the substitution appears 12 times in your   program, rather than appearing once as a function call does. On the other hand,   they are usually quicker than a function call because the overhead of a function   call is avoided.</p><p>The fact that they are expanded inline leads to the third problem, which is   that the macro does not appear in the intermediate source code that is used   by the compiler, and therefore it is not visible in most debuggers. By the time   you see it in the debugger, the substitution is already accomplished. This makes   debugging macros tricky.</p><p>The final problem, however, is the largest: Macros are not type-safe. Although   it is convenient that absolutely any argument can be used with a macro, this   completely undermines the strong typing of C++ and so is anathema to C++ programmers. </p><p>That said, the <tt>ASSERT</tt> macro is a good example of a time when this   is not a bug, but a feature: One <tt>ASSERT</tt> macro can test any condition,   mathematical or otherwise. <a name="_Toc382902689"></a><a name="_Toc444312818"></a></p><h2> <a name="Heading20">String Manipulation</a></h2><p>The preprocessor provides two special operators for manipulating strings in   macros. The <i>stringizing operator</i> (<tt>#</tt>) substitutes a quoted string   for whatever follows the stringizing operator. The <i>concatenation operator</i>   (<tt>##</tt>) bonds two strings together into one.</p><blockquote>  <hr>  <p><strong>NOTE: </strong> The <i>stringizing operator</i> (<tt>#</tt>) substitutes     a quoted string for whatever follows the stringizing operator.</p>  <p> The <i>concatenation operator</i> (<tt>##</tt>) bonds two strings together     into one. <a name="_Toc382902690"></a><a name="_Toc444312819"></a></p>  <hr></blockquote><h3> <a name="Heading21">Stringizing</a></h3><p>The stringizing operator(<tt>#</tt>) puts quotes around any characters that   follow the operator, up to the next white space. Thus, if you write</p><pre><tt>#define WRITESTRING(x) cout &lt;&lt; #x</tt></pre><p>and then call</p><pre><tt>WRITESTRING(This is a string);</tt></pre><p>the precompiler turns it into</p><pre><tt>cout &lt;&lt; "This is a string";</tt></pre><p>Note that the string <tt>This is a string</tt> is put into quotes, as is required   by <tt>cout</tt>. <a name="_Toc382902691"></a><a name="_Toc444312820"></a></p><h3> <a name="Heading22">Concatenation</a></h3><p>The concatenation operator (<tt>##</tt>) enables you to bond together more   than one term into a new word. The new word is actually a token that can be   used as a class name, a variable name, or an offset into an array--or anywhere   else a series of letters might appear.</p><p>Assume for a moment that you have five functions named <tt>fOnePrint</tt>,   <tt>fTwoPrint</tt>, <tt>fThreePrint</tt>, <tt>fFourPrint</tt>, and <tt>fFivePrint</tt>.   You can then declare</p><pre><tt>#define fPRINT(x) f ## x ## Print</tt></pre><p>and then use it with <tt>fPRINT(Two)</tt> to generate <tt>fTwoPrint</tt>, and   with <tt>fPRINT(Three)</tt> to generate <tt>fThreePrint</tt>. <a name="_Toc382902692"></a><a name="_Toc444312821"></a></p><h2> <a name="Heading23">Predefined Macros</a></h2><p>Many compilers predefine a number of useful macros, including <tt>__DATE__</tt>,   <tt>__TIME__</tt>, <tt>__LINE__</tt>, and <tt>__FILE__</tt>. Each of these names   is surrounded by two underscore<tt> </tt>characters to reduce the likelihood that   the names will conflict with names you've used in your program.</p><p>When the precompiler sees one of these macros, it makes the appropriate substitutes.   For <tt>__DATE__</tt>, the current Date is substituted; for <tt>__TIME__</tt>,   the current time is substituted. <tt>__LINE__</tt> and <tt>__FILE__</tt> are   replaced with the source code line number and filename, respectively. Note that   this substitution is made when the source is precompiled, not when the program   is run. If you ask the program to print <tt>__DATE__</tt>, you do not get the   current date; instead, you get the date the program was compiled. These defined   macros are very useful in debugging.</p><p>Although many compilers do provide an <tt>ASSERT</tt> macro, it will be instructive   to create our own, shown in Listing 5.12.</p><h4> Listing 5.12 An ASSERT Macro</h4><pre><tt>0:  #define DEBUG</tt><tt>1:  </tt><tt>2:  #ifndef DEBUG</tt><tt>3:      #define ASSERT(x)</tt><tt>4:  #else</tt><tt>5:      #define ASSERT(x) \</tt><tt>6:              if (! (x)) \</tt><tt>7:              { \</tt><tt>8:                  cout &lt;&lt; "ER

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -