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

📄 chapter05.html

📁 think like a computer scientist
💻 HTML
📖 第 1 页 / 共 3 页
字号:
<HTML><HEAD>  <TITLE>Chapter 5</TITLE>  <LINK REL="STYLESHEET" HREF="downey.css" tppabs="http://rocky.wellesley.edu/downey/ost/thinkCS/c++_html/downey.css"></HEAD><BODY><H2>Chapter 5</H2><H1>Fruitful functions</H1><P>Some of the built-in functions we have used, like the math functions, have produced results.  That is, the effect of calling the function is to generate a new value, which we usually assign to a variable or use as part of an expression. For example:</P><PRE>  double e = exp (1.0);  double height = radius * sin (angle);</PRE><P>But so far all the functions we have written have been <B>void</B> functions;that is, functions that return no value.  When you call a void function, it is typically on a line by itself, with no assignment:</P><PRE>  nLines (3);  countdown (n-1);</PRE><P>In this chapter, we are going to write functions that return things, which Iwill refer to as <B>fruitful</B> functions, for want of a better name.  The first example is <TT>area</TT>, which takes a <TT>double</TT> as a parameter,and returns the area of a circle with the given radius:</P><PRE>double area (double radius) {  double pi = acos (-1.0);  double area = pi * radius * radius;  return area;}</PRE><P>The first thing you should notice is that the beginning of the function definition is different.  Instead of <TT>void</TT>, which indicates a void function, we see <TT>double</TT>, which indicates that the return value from this function will have type <TT>double</TT>.</P><P>Also, notice that the last line is an alternate form of the <TT>return</TT> statement that includes a return value.  This statement means, ``return immediately from this function and use the following expression as a return value.''  The expression you provide can be arbitrarily complicated, so we could have written this function more concisely:</P><PRE>double area (double radius) {  return acos(-1.0) * radius * radius;}</PRE><P>On the other hand, <B>temporary</TT> variables like <TT>area</TT> often makedebugging easier.  In either case, the type of the expression in the <TT>return</TT> statement must match the return type of the function. In other words, when you declare that the return type is <TT>double</TT>, you are makinga promise that this function will eventually produce a <TT>double</TT>. If you try to <TT>return</TT> with no expression, or an expression with the wrong type, the compiler will take you to task.</P><P>Sometimes it is useful to have multiple return statements, one in each branch of a conditional:</P><PRE>double absoluteValue (double x) {  if (x < 0) {    return -x;  } else {    return x;  }}</PRE><P>Since these returns statements are in an alternative conditional, only one will be executed.  Although it is legal to have more than one <TT>return</TT> statement in a function, you should keep in mind that as soon as one is executed, the function terminates without executing any subsequent statements.</P><P>Code that appears after a <TT>return</TT> statement, or any place else whereit can never be executed, is called <B>dead code</B>. Some compilers warn you if part of your code is dead.</P><P>If you put return statements inside a conditional, then you have to guarantee that <I>every possible path</I> through the program hits a return statement.  For example:</P><PRE>double absoluteValue (double x) {  if (x < 0) {    return -x;  } else if (x > 0) {    return x;  }                          // WRONG!!}</PRE><P>This program is not correct because if <TT>x</TT> happens to be 0, then neither condition will be true and the function will end without hitting a return statement.  Unfortunately, many C++ compilers do not catch this error. As a result, the program may compile and run, but the return value when <TT>x==0</TT> could be anything, and will probably be different in different environments.</P><P>By now you are probably sick of seeing compiler errors, but as you gain moreexperience, you will realize that the only thing worse than getting a compiler error is <I>not</I> getting a compiler error when your program is wrong.</P><P>Here's the kind of thing that's likely to happen: you test <TT>absoluteValue</TT> with several values of <TT>x</TT> and it seems to workcorrectly.  Then you give your program to someone else and they run it in another environment.  It fails in some mysterious way, and it takes days of debugging to discover that the problem is an incorrect implementation of <TT>absoluteValue</TT>.  If only the compiler had warned you!</P><P>From now on, if the compiler points out an error in your program, you shouldnot blame the compiler.  Rather, you should thank the compiler for finding yourerror and sparing you days of debugging.  Some compilers have an option that tells them to be extra strict and report all the errors they can find.  You should turn this option on all the time.</P></P>As an aside, you should know that there is a function in the math library called <TT>fabs</TT> that calculates the absolute value of a <TT>double</TT>---correctly.</P><BR><BR><H3>5.2 Program development</H3><P>At this point you should be able to look at complete C++ functions and tell what they do.  But it may not be clear yet how to go about writing them.  I am going to suggest one technique that I call <B>incremental development</B>.</P><P>As an example, imagine you want to find the distance between two points, given by the coordinates <TT>(x<SUB>1</SUB>, y<SUB>1</SUB>)</TT> and <TT>(x<SUB>2</SUB>, y<SUB>2</SUB>)</TT>.  By the usual definition, with <TT>sqrt</TT> representing the square root function,</P><TT>distance = sqrt[(x<SUB>2</SUB> - x<SUB>1</SUB>)<SUP>2</SUP> +                    (y<SUB>2</SUB> - y<SUB>1</SUB>)<SUP>2</SUP>]</TT><P>The first step is to consider what a <TT>distance</TT> function should look like in C++.  In other words, what are the inputs (parameters) and what is the output (return value).</P><P>In this case, the two points are the parameters, and it is natural to represent them using four <TT>double</TT>s.  The return value is the distance, which will have type <TT>double</TT>.</P><P>Already we can write an outline of the function:</P><PRE>double distance (double x1, double y1, double x2, double y2) {  return 0.0;}</PRE><P>The <TT>return</TT> statement is a placekeeper so that the function willcompile and return something, even though it is not the right answer. At this stage the function doesn't do anything useful, but it is worthwhile to try compiling it so we can identify any syntax errors before we make it more complicated.</P><P>In order to test the new function, we have to call it with sample values.Somewhere in <TT>main</TT> I would add:</P><PRE>  double dist = distance (1.0, 2.0, 4.0, 6.0);  cout << dist << endl;</PRE><P>I chose these values so that the horizontal distance is 3 and the vertical distance is 4; that way, the result will be 5 (the hypotenuse of a 3-4-5 triangle). When you are testing a function, it is useful to know the rightanswer.</P><P>Once we have checked the syntax of the function definition, we can start adding lines of code one at a time.  After each incremental change, we recompile and run the program.  That way, at any point we know exactly where the error must be---in the last line we added.</P><P>The next step in the computation is to find the differences <TT>x<SUB>2</SUB> - x<SUB>1</SUB></TT> and <TT>y<SUB>2</SUB> - y<SUB>1</SUB></TT>.  I will store those values in temporaryvariables named <TT>dx</TT> and <TT>dy</TT>.</P><PRE>double distance (double x1, double y1, double x2, double y2) {  double dx = x2 - x1;  double dy = y2 - y1;  cout << "dx is " << dx << endl;  cout << "dy is " << dy << endl;  return 0.0;}</PRE><P>I added output statements that will let me check the intermediate values before proceeding.  As I mentioned, I already know that they should be 3.0 and 4.0.</P><P>When the function is finished I will remove the output statements. Code likethat is called <B>scaffolding</B>, because it is helpful for building the program, but it is not part of the final product. Sometimes it is a good idea to keep the scaffolding around, but comment it out, just in case you need it later.</P><P>The next step in the development is to square <TT>dx</TT> and <TT>dy</TT>.We could use the <TT>pow</TT> function, but it is simpler and faster to just multiply each term by itself.</P><PRE>double distance (double x1, double y1, double x2, double y2) {  double dx = x2 - x1;  double dy = y2 - y1;  double dsquared = dx*dx + dy*dy;  cout << "dsquared is " << dsquared;  return 0.0;}</PRE><P>Again, I would compile and run the program at this stage and check the intermediate value (which should be 25.0).<P><P>Finally, we can use the <TT>sqrt</TT> function to compute and return the result.</P><PRE>double distance (double x1, double y1, double x2, double y2) {  double dx = x2 - x1;  double dy = y2 - y1;  double dsquared = dx*dx + dy*dy;  double result = sqrt (dsquared);  return result;}</PRE><P>Then in <TT>main</TT>, we should output and check the value of the result.</P><P>As you gain more experience programming, you might find yourself writing anddebugging more than one line at a time.  Nevertheless, this incremental development process can save you a lot of debugging time.</P><P>The key aspects of the process are:</P><OL>  <LI>Start with a working program and make small, incremental changes. At any   point, if there is an error, you will know exactly where it is.</LI>  <LI>Use temporary variables to hold intermediate values so you can output and  check them.</LI>  <LI>Once the program is working, you might want to remove some of the   scaffolding or consolidate multiple statements into compound expressions,   but only if it does not make the program difficult to read.</LI></OL><BR><BR><H3>5.3 Composition</H3><P>As you should expect by now, once you define a new function, you can use it as part of an expression, and you can build new functions using existing functions.  For example, what if someone gave you two points, the center of thecircle and a point on the perimeter, and asked for the area of the circle?</P><P>Let's say the center point is stored in the variables <TT>xc</TT> and <TT>yc</TT>, and the perimeter point is in <TT>xp</TT> and <TT>yp</TT>. The first step is to find the radius of the circle, which is the distance between the two points.  Fortunately, we have a function, <TT>distance</TT>, that does that.</P><PRE>  double radius = distance (xc, yc, xp, yp);</PRE><P>The second step is to find the area of a circle with that radius, and returnit.</P><PRE>  double result = area (radius);

⌨️ 快捷键说明

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