C++ 3
C++ 3
MATH FUNCTIONS 23
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
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.
void newLine () {
cout << endl;
}
int main ()
{
cout << "First Line." << endl;
newLine ();
cout << "Second Line." << endl;
return 0;
}
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 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:
#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 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:
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.
argument
’b’ main
phil
printTwice
’b’
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!
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).
• 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)?
• 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.
argument: A value that you provide when you call a function. This value must
have the same type as the corresponding parameter.
33
34 CHAPTER 4. CONDITIONALS AND RECURSION
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.
if (x%2 == 0) {
cout << "x is even" << endl;
} else {
cout << "x is odd" << endl;
}
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:
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.
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.
#include <cmath>
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
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;
}
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...