0% found this document useful (0 votes)
3 views

C++ 3

The document discusses mathematical functions in C++, explaining how to evaluate them and use built-in functions like sin and log. It covers function composition, the creation of new functions, and the importance of parameters and arguments, emphasizing that parameters are local to their functions. Additionally, it outlines the syntax for declaring functions with multiple parameters and the distinction between functions that return values and those that perform actions without returning a result.

Uploaded by

zaff888
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

C++ 3

The document discusses mathematical functions in C++, explaining how to evaluate them and use built-in functions like sin and log. It covers function composition, the creation of new functions, and the importance of parameters and arguments, emphasizing that parameters are local to their functions. Additionally, it outlines the syntax for declaring functions with multiple parameters and the distinction between functions that return values and those that perform actions without returning a result.

Uploaded by

zaff888
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

3.3.

MATH FUNCTIONS 23

3.3 Math functions


In mathematics, you have probably seen functions like sin and log, and you have
learned to evaluate expressions like sin(π/2) and log(1/x). First, you evaluate
the expression in parentheses, which is called the argument of the function.
For example, π/2 is approximately 1.571, and 1/x is 0.1 (if x happens to be 10).
Then you can evaluate the function itself, either by looking it up in a table
or by performing various computations. The sin of 1.571 is 1, and the log of 0.1
is -1 (assuming that log indicates the logarithm base 10).
This process can be applied repeatedly to evaluate more complicated ex-
pressions like log(1/ sin(π/2)). First we evaluate the argument of the innermost
function, then evaluate the function, and so on.
C++ provides a set of built-in functions that includes most of the mathe-
matical operations you can think of. The math functions are invoked using a
syntax that is similar to mathematical notation:

double log = log (17.0);


double angle = 1.5;
double height = sin (angle);

The first example sets log to the logarithm of 17, base e. There is also a function
called log10 that takes logarithms base 10.
The second example finds the sine of the value of the variable angle. C++
assumes that the values you use with sin and the other trigonometric functions
(cos, tan) are in radians. To convert from degrees to radians, you can divide
by 360 and multiply by 2π.
If you don’t happen to know π to 15 digits, you can calculate it using the
acos function. The arccosine (or inverse cosine) of -1 is π, because the cosine
of π is -1.

double pi = acos(-1.0);
double degrees = 90;
double angle = degrees * 2 * pi / 360.0;

Before you can use any of the math functions, you have to include the math
header file. Header files contain information the compiler needs about func-
tions that are defined outside your program. For example, in the “Hello, world!”
program we included a header file named iostream using an include statement:

#include <iostream>
using namespace std;

iostream contains information about input and output (I/O) streams, including
the object named cout. C++ has a powerful feature called namespaces, that
allow you to write your own implementation of cout. But in most cases, we
would need to use the standard implementation. To convey this to the compiler,
we use the line
24 CHAPTER 3. FUNCTION

using namespace std;


As a rule of the thumb, you should write using namespace std; whenever
you use iostream.
Similarly, the math header file contains information about the math func-
tions. You can include it at the beginning of your program along with iostream:
#include <cmath>
Such header files have an initial ‘c’ to signify that these header files have
been derived from the C language.

3.4 Composition
Just as with mathematical functions, C++ functions can be composed, mean-
ing that you use one expression as part of another. For example, you can use
any expression as an argument to a function:
double x = cos (angle + pi/2);
This statement takes the value of pi, divides it by two and adds the result to
the value of angle. The sum is then passed as an argument to the cos function.
You can also take the result of one function and pass it as an argument to
another:
double x = exp (log (10.0));
This statement finds the log base e of 10 and then raises e to that power. The
result gets assigned to x; I hope you know what it is.

3.5 Adding new functions


So far we have only been using the functions that are built into C++, but it is
also possible to add new functions. Actually, we have already seen one function
definition: main. The function named main is special because it indicates where
the execution of the program begins, but the syntax for main is the same as for
any other function definition:
void NAME ( LIST OF PARAMETERS ) {
STATEMENTS
}
You can make up any name you want for your function, except that you can’t
call it main or any other C++ keyword. The list of parameters specifies what
information, if any, you have to provide in order to use (or call) the new function.
main doesn’t take any parameters, as indicated by the empty parentheses ()
in it’s definition. The first couple of functions we are going to write also have
no parameters, so the syntax looks like this:
3.5. ADDING NEW FUNCTIONS 25

void newLine () {
cout << endl;
}

This function is named newLine; it contains only a single statement, which


outputs a newline character, represented by the special value endl.
In main we can call this new function using syntax that is similar to the way
we call the built-in C++ commands:

int main ()
{
cout << "First Line." << endl;
newLine ();
cout << "Second Line." << endl;
return 0;
}

The output of this program is

First line.

Second line.

Notice the extra space between the two lines. What if we wanted more space
between the lines? We could call the same function repeatedly:

int main ()
{
cout << "First Line." << endl;
newLine ();
newLine ();
newLine ();
cout << "Second Line." << endl;
return 0;
}

Or we could write a new function, named threeLine, that prints three new
lines:

void threeLine ()
{
newLine (); newLine (); newLine ();
}

int main ()
{
cout << "First Line." << endl;
26 CHAPTER 3. FUNCTION

threeLine ();
cout << "Second Line." << endl;
return 0;
}

You should notice a few things about this program:

• You can call the same procedure repeatedly. In fact, it is quite common
and useful to do so.

• You can have one function call another function. In this case, main calls
threeLine and threeLine calls newLine. Again, this is common and
useful.

• In threeLine I wrote three statements all on the same line, which is syn-
tactically legal (remember that spaces and new lines usually don’t change
the meaning of a program). On the other hand, it is usually a better idea
to put each statement on a line by itself, to make your program easy to
read. I sometimes break that rule in this book to save space.

So far, it may not be clear why it is worth the trouble to create all these new
functions. Actually, there are a lot of reasons, but this example only demon-
strates two:

1. Creating a new function gives you an opportunity to give a name to a group


of statements. Functions can simplify a program by hiding a complex
computation behind a single command, and by using English words in
place of arcane code. Which is clearer, newLine or cout << endl?

2. Creating a new function can make a program smaller by eliminating repet-


itive code. For example, a short way to print nine consecutive new lines
is to call threeLine three times. How would you print 27 new lines?

3.6 Definitions and uses


Pulling together all the code fragments from the previous section, the whole
program looks like this:

#include <iostream>
using namespace std;

void newLine ()
{
cout << endl;
}

void threeLine ()
3.7. PROGRAMS WITH MULTIPLE FUNCTIONS 27

{
newLine (); newLine (); newLine ();
}

int main ()
{
cout << "First Line." << endl;
threeLine ();
cout << "Second Line." << endl;
return 0;
}

This program contains three function definitions: newLine, threeLine, and


main.
Inside the definition of main, there is a statement that uses or calls
threeLine. Similarly, threeLine calls newLine three times. Notice that the
definition of each function appears above the place where it is used.
This is necessary in C++; the definition of a function must appear before
(above) the first use of the function. You should try compiling this program
with the functions in a different order and see what error messages you get.

3.7 Programs with multiple functions


When you look at a class definition that contains several functions, it is tempting
to read it from top to bottom, but that is likely to be confusing, because that
is not the order of execution of the program.
Execution always begins at the first statement of main, regardless of where
it is in the program (often it is at the bottom). Statements are executed one at
a time, in order, until you reach a function call. Function calls are like a detour
in the flow of execution. Instead of going to the next statement, you go to the
first line of the called function, execute all the statements there, and then come
back and pick up again where you left off.
That sounds simple enough, except that you have to remember that one func-
tion can call another. Thus, while we are in the middle of main, we might have
to go off and execute the statements in threeLine. But while we are executing
threeLine, we get interrupted three times to go off and execute newLine.
Fortunately, C++ is adept at keeping track of where it is, so each time
newLine completes, the program picks up where it left off in threeLine, and
eventually gets back to main so the program can terminate.
What’s the moral of this sordid tale? When you read a program, don’t read
from top to bottom. Instead, follow the flow of execution.
28 CHAPTER 3. FUNCTION

3.8 Parameters and arguments


Some of the built-in functions we have used have parameters, which are values
that you provide to let the function do its job. For example, if you want to find
the sine of a number, you have to indicate what the number is. Thus, sin takes
a double value as a parameter.
Some functions take more than one parameter, like pow, which takes two
doubles, the base and the exponent.
Notice that in each of these cases we have to specify not only how many
parameters there are, but also what type they are. So it shouldn’t surprise you
that when you write a class definition, the parameter list indicates the type of
each parameter. For example:

void printTwice (char phil) {


cout << phil << phil << endl;
}

This function takes a single parameter, named phil, that has type char. What-
ever that parameter is (and at this point we have no idea what it is), it gets
printed twice, followed by a newline. I chose the name phil to suggest that
the name you give a parameter is up to you, but in general you want to choose
something more illustrative than phil.
In order to call this function, we have to provide a char. For example, we
might have a main function like this:

int main () {
printTwice (’a’);
return 0;
}

The char value you provide is called an argument, and we say that the ar-
gument is passed to the function. In this case the value ’a’ is passed as an
argument to printTwice where it will get printed twice.
Alternatively, if we had a char variable, we could use it as an argument
instead:

int main () {
char argument = ’b’;
printTwice (argument);
return 0;
}

Notice something very important here: the name of the variable we pass as an
argument (argument) has nothing to do with the name of the parameter (phil).
Let me say that again:

The name of the variable we pass as an argument has noth-


ing to do with the name of the parameter.
3.9. PARAMETERS AND VARIABLES ARE LOCAL 29

They can be the same or they can be different, but it is important to realize
that they are not the same thing, except that they happen to have the same
value (in this case the character ’b’).
The value you provide as an argument must have the same type as the
parameter of the function you call. This rule is important, but it is sometimes
confusing because C++ sometimes converts arguments from one type to another
automatically. For now you should learn the general rule, and we will deal with
exceptions later.

3.9 Parameters and variables are local


Parameters and variables only exist inside their own functions. Within the
confines of main, there is no such thing as phil. If you try to use it, the
compiler will complain. Similarly, inside printTwice there is no such thing as
argument.
Variables like this are said to be local. In order to keep track of parameters
and local variables, it is useful to draw a stack diagram. Like state diagrams,
stack diagrams show the value of each variable, but the variables are contained
in larger boxes that indicate which function they belong to.
For example, the state diagram for printTwice looks like this:

argument

’b’ main

phil

printTwice
’b’

Whenever a function is called, it creates a new instance of that function.


Each instance of a function contains the parameters and local variables for that
function. In the diagram an instance of a function is represented by a box with
the name of the function on the outside and the variables and parameters inside.
In the example, main has one local variable, argument, and no parameters.
printTwice has no local variables and one parameter, named phil.
30 CHAPTER 3. FUNCTION

3.10 Functions with multiple parameters


The syntax for declaring and invoking functions with multiple parameters is a
common source of errors. First, remember that you have to declare the type of
every parameter. For example

void printTime (int hour, int minute) {


cout << hour;
cout << ":";
cout << minute;
}

It might be tempting to write (int hour, minute), but that format is only
legal for variable declarations, not for parameters.
Another common source of confusion is that you do not have to declare the
types of arguments. The following is wrong!

int hour = 11;


int minute = 59;
printTime (int hour, int minute); // WRONG!

In this case, the compiler can tell the type of hour and minute by looking at
their declarations. It is unnecessary and illegal to include the type when you
pass them as arguments. The correct syntax is printTime (hour, minute).

3.11 Functions with results


You might have noticed by now that some of the functions we are using, like the
math functions, yield results. Other functions, like newLine, perform an action
but don’t return a value. That raises some questions:

• What happens if you call a function and you don’t do anything with the
result (i.e. you don’t assign it to a variable or use it as part of a larger
expression)?

• What happens if you use a function without a result as part of an expres-


sion, like newLine() + 7?

• Can we write functions that yield results, or are we stuck with things like
newLine and printTwice?

The answer to the third question is “yes, you can write functions that return
values,” and we’ll do it in a couple of chapters. I will leave it up to you to answer
the other two questions by trying them out. Any time you have a question about
what is legal or illegal in C++, a good way to find out is to ask the compiler.
3.12. GLOSSARY 31

3.12 Glossary
floating-point: A type of variable (or value) that can contain fractions as well
as integers. There are a few floating-point types in C++; the one we use
in this book is double.
initialization: A statement that declares a new variable and assigns a value
to it at the same time.

function: A named sequence of statements that performs some useful function.


Functions may or may not take parameters, and may or may not produce
a result.

parameter: A piece of information you provide in order to call a function.


Parameters are like variables in the sense that they contain values and
have types.

argument: A value that you provide when you call a function. This value must
have the same type as the corresponding parameter.

call: Cause a function to be executed.


32 CHAPTER 3. FUNCTION
Chapter 4

Conditionals and recursion

4.1 The modulus operator


The modulus operator works on integers (and integer expressions) and yields
the remainder when the first operand is divided by the second. In C++, the
modulus operator is a percent sign, %. The syntax is exactly the same as for
other operators:
int quotient = 7 / 3;
int remainder = 7 % 3;
The first operator, integer division, yields 2. The second operator yields 1.
Thus, 7 divided by 3 is 2 with 1 left over.
The modulus operator turns out to be surprisingly useful. For example, you
can check whether one number is divisible by another: if x % y is zero, then x
is divisible by y.
Also, you can use the modulus operator to extract the rightmost digit or
digits from a number. For example, x % 10 yields the rightmost digit of x (in
base 10). Similarly x % 100 yields the last two digits.

4.2 Conditional execution


In order to write useful programs, we almost always need the ability to check
certain conditions and change the behavior of the program accordingly. Condi-
tional statements give us this ability. The simplest form is the if statement:
if (x > 0) {
cout << "x is positive" << endl;
}
The expression in parentheses is called the condition. If it is true, then the
statements in brackets get executed. If the condition is not true, nothing hap-
pens.

33
34 CHAPTER 4. CONDITIONALS AND RECURSION

The condition can contain any of the comparison operators:

x == y // x equals y
x != y // x is not equal to y
x > y // x is greater than y
x < y // x is less than y
x >= y // x is greater than or equal to y
x <= y // x is less than or equal to y

Although these operations are probably familiar to you, the syntax C++ uses is
a little different from mathematical symbols like =, 6= and ≤. A common error
is to use a single = instead of a double ==. Remember that = is the assignment
operator, and == is a comparison operator. Also, there is no such thing as =<
or =>.
The two sides of a condition operator have to be the same type. You can
only compare ints to ints and doubles to doubles. Unfortunately, at this
point you can’t compare Strings at all! There is a way to compare Strings,
but we won’t get to it for a couple of chapters.

4.3 Alternative execution


A second form of conditional execution is alternative execution, in which there
are two possibilities, and the condition determines which one gets executed. The
syntax looks like:

if (x%2 == 0) {
cout << "x is even" << endl;
} else {
cout << "x is odd" << endl;
}

If the remainder when x is divided by 2 is zero, then we know that x is even,


and this code displays a message to that effect. If the condition is false, the
second set of statements is executed. Since the condition must be true or false,
exactly one of the alternatives will be executed.
As an aside, if you think you might want to check the parity (evenness or
oddness) of numbers often, you might want to “wrap” this code up in a function,
as follows:

void printParity (int x) {


if (x%2 == 0) {
cout << "x is even" << endl;
} else {
cout << "x is odd" << endl;
}
}
4.4. CHAINED CONDITIONALS 35

Now you have a function named printParity that will display an appropriate
message for any integer you care to provide. In main you would call this function
as follows:

printParity (17);

Always remember that when you call a function, you do not have to declare the
types of the arguments you provide. C++ can figure out what type they are.
You should resist the temptation to write things like:

int number = 17;


printParity (int number); // WRONG!!!

4.4 Chained conditionals


Sometimes you want to check for a number of related conditions and choose one
of several actions. One way to do this is by chaining a series of ifs and elses:

if (x > 0) {
cout << "x is positive" << endl;
} else if (x < 0) {
cout << "x is negative" << endl;
} else {
cout << "x is zero" << endl;
}

These chains can be as long as you want, although they can be difficult to read
if they get out of hand. One way to make them easier to read is to use standard
indentation, as demonstrated in these examples. If you keep all the statements
and squiggly-braces lined up, you are less likely to make syntax errors and you
can find them more quickly if you do.

4.5 Nested conditionals


In addition to chaining, you can also nest one conditional within another. We
could have written the previous example as:

if (x == 0) {
cout << "x is zero" << endl;
} else {
if (x > 0) {
cout << "x is positive" << endl;
} else {
cout << "x is negative" << endl;
}
}
36 CHAPTER 4. CONDITIONALS AND RECURSION

There is now an outer conditional that contains two branches. The first branch
contains a simple output statement, but the second branch contains another if
statement, which has two branches of its own. Fortunately, those two branches
are both output statements, although they could have been conditional state-
ments as well.
Notice again that indentation helps make the structure apparent, but nev-
ertheless, nested conditionals get difficult to read very quickly. In general, it is
a good idea to avoid them when you can.
On the other hand, this kind of nested structure is common, and we will
see it again, so you better get used to it.

4.6 The return statement


The return statement allows you to terminate the execution of a function before
you reach the end. One reason to use it is if you detect an error condition:

#include <cmath>

void printLogarithm (double x) {


if (x <= 0.0) {
cout << "Positive numbers only, please." << endl;
return;
}

double result = log (x);


cout << "The log of x is " << result;
}

This defines a function named printLogarithm that takes a double named x


as a parameter. The first thing it does is check whether x is less than or equal
to zero, in which case it displays an error message and then uses return to exit
the function. The flow of execution immediately returns to the caller and the
remaining lines of the function are not executed.
I used a floating-point value on the right side of the condition because there
is a floating-point variable on the left.
Remember that any time you want to use one a function from the math
library, you have to include the header file math.h.

4.7 Recursion
I mentioned in the last chapter that it is legal for one function to call another,
and we have seen several examples of that. I neglected to mention that it is
also legal for a function to call itself. It may not be obvious why that is a good
thing, but it turns out to be one of the most magical and interesting things a
program can do.
4.7. RECURSION 37

For example, look at the following function:

void countdown (int n) {


if (n == 0) {
cout << "Blastoff!" << endl;
} else {
cout << n << endl;
countdown (n-1);
}
}

The name of the function is countdown and it takes a single integer as a pa-
rameter. If the parameter is zero, it outputs the word “Blastoff.” Otherwise,
it outputs the parameter and then calls a function named countdown—itself—
passing n-1 as an argument.
What happens if we call this function like this:

#include <iostream>
#include <cmath>
using namespace std;
void printLogarithm (double x) {
if (x <= 0.0) {
cout << "Positive numbers only, please." << endl;
return;
}

double result = log (x);


cout << "The log of x is " << result;
}

void countdown (int n) {


if (n == 0) {
cout << "Blastoff!" << endl;
} else {
cout << n << endl;
countdown (n-1);
}
}

int main ()
{
countdown (3);
return 0;
}

The execution of countdown begins with n=3, and since n is not zero, it outputs
the value 3, and then calls itself...

You might also like