Professional Documents
Culture Documents
Chapter VI Topics
6.1 Introduction
6.1 Introduction
This chapter is very critical because the logical correctness of a computer program
assumes correct usage of operations. C++ has a very large variety of operations
that will seem confusing at first. A lot of the confusion is not due to complexity
but to quantity. A large quantity of anything, no matter how simple, can be quite
overwhelming. Be methodical; make sure that you understand each operation,
and practice every new feature until it makes sense.
This chapter will provide detailed explanations, when detailed explanations are
considered necessary. For many situations the best explanation is a program
example that demonstrates how to use certain programming features.
// PROG0601.CPP
// This program demonstrates integer operations.
void main()
{
int Nr1 = 100;
int Nr2 = 30;
int Result1, Result2, Result3, Result4, Result5;
clrscr();
cout << Nr1 << " + " << Nr2 << " = " << Result1
<< endl;
cout << Nr1 << " - " << Nr2 << " = " << Result2
<< endl;
cout << Nr1 << " * " << Nr2 << " = " << Result3
<< endl;
cout << Nr1 << " / " << Nr2 << " = " << Result4
<< endl;
cout << Nr1 << " % " << Nr2 << " = " << Result5
<< endl;
getch();
}
PROG0601.CPP OUTPUT
12 / 3 = 4
12 / 4 = 3
12 / 5 = 2
12 / 8 = 1
12 / 12 = 1
12 / 15 = 0
12 % 3 = 0
12 % 4 = 0
12 % 5 = 2
12 % 8 = 4
12 % 12 = 0
12 % 15 = 12
C++ does not always use the world’s best set of symbols.
There is no typo here. The percent (%) symbol is used for
modulus division.
The people who originally invented C++ must have had a serious phobia to
touching the keyboard. They created every conceivable shortcut notation to
shorten the source code. In the process, the code is not always very readable.
However, there are some neat shortcuts you will enjoy using, and you also need to
// PROG0602.CPP
// This program demonstrates incrementers and
decrementers.
#include <iostream.h>
#include <conio.h>
void main()
{
clrscr();
int Nr1 = 100;
int Nr2 = 30;
cout << "Nr1 = " << Nr1 << endl;
cout << "Nr2 = " << Nr2 << endl;
getch();
}
PROG0602.CPP OUTPUT
Nr1 = 100
Nr2 = 30
Nr1 = 101
Nr2 = 31
Nr1 = 100
Nr2 = 30
You may be confused about the postfix and prefix notation. Like ..... where is
the difference? In the manner that the example program is written, and the
examples shown above, there is no difference. There does exist a reason for two
versions of incrementing and decrementing. The next program example will more
clearly demonstrate that a difference does exist.
// PROG0603.CPP
// This program demonstrates the difference between
// the X++ and ++X incrementers.
#include <iostream.h>
#include <conio.h>
void main()
{
clrscr();
int X1,X2;
X1 = X2 = 10;
cout << X1 << " " << X2 << endl;
cout << ++X1 << " " << X2++ << endl;
cout << X1 << " " << X2 << endl;
getch();
}
10 10
11 10
11 11
This output should cause a few frowns here and there. Let us see what is
happening? First, the program assigns 10 simultaneously to X1 and X2 with the
statement X1 = X2 = 10. This is followed by displaying the values of the two
variables. The output shows an identical 10 for each variable, and you probably
expected that. Now it becomes weird. In the next output the prefix notation ++X
outputs 11 and the postfix notation outputs 10. And then with the third statement,
both variables display the value 11. What is happening here?
The difference occurs because the program combines the cout output function
with the incrementers. The prefix (++X1) has precedence over the output
function, increments first, and then displays the values. The postfix (X++)
operation does not have precedence over the output function. The output of X is
done first - with the previous X value - and then incremented.
This business of what comes first allows some real clever programming tricks. It
also creates some exceptionally ambiguous programming code. We will return to
this topic shortly and you will see that this prefix and postfix business can be
quite confusing, but luckily it can also be totally avoided.
There exists some other neat shortcuts that can be used with each of one the five
arithmetic operations. These are popular programming shortcuts that are
commonly used in C++ programs. The “no shortcut notation” you see below is a
style used by a variety of other programming languages. Program
PROG0604.CPP shows the details of each one of the shortcuts, on the next page.
K = K + 5 K += 5
K = K - 5 K -= 5
K = K * 5 K *= 5
// PROG0604.CPP
// This program demonstrates using shortcut notation
with
// each one of the 5 basic operations.
void main()
{
clrscr();
int Nr = 100;
cout << "Nr " << Nr << endl << endl;
Nr += 10;
cout << "Nr += 10 " << Nr << endl << endl;
Nr -= 20;
cout << "Nr -= 20 " << Nr << endl << endl;
Nr *= 2;
cout << "Nr *= 2 " << Nr << endl << endl;
Nr /= 5;
cout << "Nr /= 5 " << Nr << endl << endl;
Nr %= 7;
cout << "Nr %= 7 " << Nr << endl << endl;
getch();
}
Nr 100
Nr += 10 110
Nr -= 20 90
Nr *= 2 180
Nr /= 5 36
Nr %= 7 1
Using a shortcut like K++ is neat, and it is also pretty nice to use shortcuts like
K+=5 and K/=L. The problem starts when over-enthusiastic C++ programmers
go overboard on the shortcut business. They frequently combine too many
statements together with some very difficult-to-predict results. I will show you
two programs that demonstrate this point. The first program is not too bad, and
most people can determine the output. The second program is pretty bizarre and
should convince anybody about the problems with shortcuts.
// PROG0605.CPP
// This program demonstrates complexity caused
// by combining incrementers.
#include <iostream.h>
#include <conio.h>
void main()
{
clrscr();
int X = 10;
++X += X++;
cout << "X = " << X << endl << endl;
getch();
}
X = 23
I have intentionally not explained how this program works. Many teachers will
prefer if students are simply told not to combine shortcuts. Any explanation and
increased knowledge in the area of shortcuts may increase the likelihood of
students using undesirable shortcuts.
Who needs an explanation? Perhaps you understand where the value 23 comes
from. If you do, you will enjoy program PROG0606.CPP. This program is
quite challenging and hopefully convinces everybody that this shortcut business
can get pretty crazy in a hurry.
The output of the next program example is intentionally not shown. It is more
interesting to see how many students can determine what the output will be. The
point about using too many shortcuts is more convincing when the majority of
students do not compute the correct answer. On the other hand, if you already
knew the answer from the chapter reading, it becomes difficult to determine what
you remembered from reading and what you determined on your own.
Check PROG0606.CPP and put on your thinking cap. Can you figure out what
the output is? If you are confused, do not feel bad, because most students have
serious problems with this style of code.
// PROG0606.CPP
// This program shows complexity with combining
incrementers.
#include <iostream.h>
#include <conio.h>
void main()
{
clrscr();
int X = 10;
++X += (X++ + ++X);
cout << "X = " << X << endl << endl;
getch();
}
PROG0606.CPP OUTPUT
Did you figure the output correctly? Right. Well, whether you understood the
output of the previous program or not, remember the following warning.
Proper Usage:
K++;
cout << K << endl;
Problematic Usage:
Real number operations closely resemble the operations with integers. The only
difference in the operations is with division. Real numbers do not have integer
division or remainder division. You do have division that computes a fractional
answer. The C++ data type, used earlier for real numbers is float, short for
floating point number. Program PROG0607.CPP demonstrates real operations.
// PROG0607.CPP
// This program demonstrates real number operations
// implemented with the float type.
void main()
{
float Nr1 = 1000;
float Nr2 = 3.3;
float Result1, Result2, Result3, Result4;
Result1 = Nr1 + Nr2;
Result2 = Nr1 - Nr2;
Result3 = Nr1 * Nr2;
Result4 = Nr1 / Nr2;
clrscr();
cout << Nr1 << " + " << Nr2 << " = " << Result1
<< endl;
cout << Nr1 << " - " << Nr2 << " = " << Result2
<< endl;
cout << Nr1 << " * " << Nr2 << " = " << Result3
<< endl;
cout << Nr1 << " / " << Nr2 << " = " << Result4
<< endl;
getch();
}
PROG0607.CPP OUTPUT
The output shows some expected fractional digits beyond the decimal (floating)
point. On the other hand, output like 1003.299988 does not inspire confidence.
Should that output not be in the neighborhood of 1003.3? You are right, and for
this reason real numbers in C++ normally use the double type, not the float type.
At the end of this chapter, we will investigate computer precision very closely,
and provide more information about the differences between the many data types
available in C++.
// PROG0608.CPP
// This program demonstrates real number operations
// implemented with the double type.
#include <iostream.h>
#include <conio.h>
PROG0608.CPP OUTPUT
The output of program PROG0608.CPP shows the type of result that you had
probably expected. All the future program examples, which use real numbers,
will use the double real number type.
5XY 5*X*Y
4X + 3Y 4*X + 3*Y
6(A - B) 6*(A - B)
5 5/7
7
A + B (A + B)/(A - B)
A - B
AB (A * B)/(X * Y)
XY
// PROG0609.CPP
// This program demonstrates math precedence in C++.
#include <iostream.h>
#include <conio.h>
void main()
{
double A,B,C, Result;
A = 1000;
B = 100;
C = 2.5;
clrscr();
cout << "A = " << A << " B = " << B << " C = "
<< C << endl << endl;
Result = A + B * C;
cout << "A + B * C = " << Result << endl;
Result = (A + B) * C;
cout << "(A + B) * C = " << Result << endl;
Result = A / B * C;
cout << "A / B * C = " << Result << endl;
Result = A * B / C;
cout << "A * B / C = " << Result << endl;
getch();
}
PROG0609.CPP OUTPUT
A + B * C = 1250
(A + B) * C = 2750
A / B * C = 25
A * B / C = 40000
The title of this section may surprise you. Performing operations with integers
and real numbers makes good sense to you. Doing operations with characters is
quite another story. Relax, we will not add A + B and somehow get C, but we
will do similar operations and you need to be aware of the manner in which C++
deals with character data types.
It is very important to understand that characters are stored, and treated, like
numerical values by C++. One byte of memory is used for characters, and this
allows 256 different combinations for 256 different characters. When you use
mathematical operators with characters, results are determined based on the
computation of the numerical values of the characters. The next example,
program PROG0610.CPP demonstrates addition and subtraction with characters.
// PROG0610.cpp
// This program demonstrates that characters
// are stored as numbers.
#include <iostream.h>
#include <conio.h>
void main()
{
clrscr();
cout << "'a' - 'A' = " << 'a' - 'A' << endl;
cout << "'b' - 'B' = " << 'b' - 'B' << endl;
cout << "'z' - 'Z' = " << 'z' - 'Z' << endl;
cout << "'a' + 'A' = " << 'a' + 'A' << endl;
cout << "'b' + 'B' = " << 'b' + 'B' << endl;
cout << "'z' + 'Z' = " << 'z' + 'Z' << endl;
getch();
}
PROG0610.CPP
'a' - 'A' = 32
'b' - 'B' = 32
'c' - 'C' = 32
'a' + 'A' = 162
'b' + 'B' = 164
'c' + 'C' = 212
The previous program showed addition and subtraction of characters only. The
next program example will demonstrate what happens when you try to add
numbers to characters. It will also show the incrementer operation used with a
character variable.
// PROG0611.cpp
// This program demonstrates operations with character
variables.
#include <iostream.h>
#include <conio.h>
void main()
{
clrscr();
char Char1, Char2;
Char1 = 'A';
Char2 = Char1 + 5;
cout << Char1 << " + 5 = " << Char2 << endl;
Char1++;
cout << "Char1++ = " << Char1 << endl;
getch();
}
PROG0611.CPP OUTPUT
A + 5 = F
A + 10 = K
Char1++ = B
You were totally impressed that C++ managed to perform arithmetic operations
on characters. Do you believe C++ can continue its amazing performance and
also perform operations with strings? Probably a stupid question? Why would a
section be titled String Concatenation, if such an operation did not exist?
You need to realize that there will not be cute tricks like adding numerical values
that represent characters. In fact, there will not be addition in the numerical sense
at all. The + operator will be used, but it has a different meaning with strings,
and it is called concatenation.
String Concatenation
The apstring, introduced in the last chapter, implements concatenation with the
plus + operator. You will note something here that will occur frequently in C++.
Symbols and operators will have different meanings in different situations.
// PROG0612.cpp
// This program demonstrates concatenation with
strings.
#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"
void main()
{
clrscr();
apstring String1 = "Good";
apstring String2 = "Morning";
apstring String3;
String3 = String1 + ' ' + String2;
cout << String1 << " + " << String2 << " = " <<
String3
<< endl;
getch();
}
PROG0612.CPP OUTPUT
In the last chapter, I mentioned that you need to be careful when you mix different
data type variables. You may get results that are unexpected. If you understand
what is happening, you will note that the results are not unexpected. Furthermore,
you can take control, and intentionally assign one data type to a different data
type for a desired result. Intentionally assigning one data type to another type is
called type casting.
double Result;
Result = 5/3; // integer division
double Result;
Result = (double) 5/3; // real division
// due to type casting
You have already seen the unique relationship between characters and integers.
In program PROG0613.CPP you will see the character/integer relationship
repeated and see various other relationships as well.
// PROG0613.CPP
#include <iostream.h>
#include <conio.h>
void main()
{
char Var1;
int Var2;
float Var3;
Var1 = 'A';
Var2 = 65;
Var3 = 3.14159;
clrscr();
cout << Var1 << endl;
cout << Var2 << endl;
cout << Var3 << endl;
cout << endl;
cout << "A becomes " << (int) Var1 << endl;
cout << "65 becomes " << (char) Var2 << endl;
cout << "65/3 without casting becomes " << Var2/3 <<
endl;
cout << "65/3 with casting becomes " << (float)
Var2/3 << endl;
cout << "3.14159 becomes " << (int) Var3 << endl;
getch();
}
A
65
3.14159
A becomes 65
65 becomes A
65/3 without casting becomes 21
65/3 with casting becomes 21.666666
3.14159 becomes 3
// PROG0614.CPP
// This program demonstrates a second syntax style
// for type casting.
#include <iostream.h>
#include <conio.h>
void main()
{
char Var1;
int Var2;
double Var3;
Var1 = 'A';
Var2 = 65;
Var3 = 3.14159;
clrscr();
cout << Var1 << endl;
cout << Var2 << endl;
cout << Var3 << endl;
cout << endl;
cout << "A becomes " << int (Var1) << endl;
cout << "65 becomes " << char (Var2) << endl;
cout << "65/3 without casting becomes " << Var2/3 <<
endl;
cout << "65/3 with casting becomes " << float
(Var2/3) << endl;
cout << "3.14159 becomes " << int (Var3) << endl;
getch();
}
Type casting is a powerful tool in C++. Use this tool wisely and carefully. The
compiler knows correct syntax, but the compiler does not know what is in your
head. You must be logical and determine how to use variables properly.
6.9 Integer Overflow Problems
In this section we will explore the reasons for such inaccuracies. In particular,
we are going to take a close look at the problems that can very easily occur with
integers. What type of problems am I talking about? Check out program
PROG0615.CPP and notice the very odd, inaccurate, output that is shown. The
title of this chapter section is Integer Overflow Problems because mathematical
inaccuracies happen when a number overflows.
// PROG0615.CPP
// This program demonstrates integer overflow problems.
#include <iostream.h>
#include <conio.h>
void main()
{
clrscr();
int Number = 20000;
cout << "Number: " << Number << endl;
Number += 10000;
cout << "Number: " << Number << endl;
Number += 10000;
cout << "Number: " << Number << endl;
Number = 32767;
cout << "Number: " << Number << endl;
Number++;
cout << "Number: " << Number << endl;
getch();
}
PROG0615.CPP
Number: 20000
Number: 30000
Number: -25356
Number: 32767
Number: -32768
0 9 9 9 9 9
This odometer cannot display a larger number with 5 digits. One more mile and
the entire display will change. Each one of the digits will change from 9 to 0, and
the 0 on the far left will become 1.
1 0 0 0 0 0
You also need to realize that the odometer will max out at 999,999. It is not
possible to display 1,000,000. The limit of the number is based on the limit of the
number of displayed digits.
The same exact logic applies to variables in a computer. Different variables are
assigned different amounts of memory. In Turbo C++ an integer is allocated 2
bytes of memory. This means a total of 16 bits are used to represent an integer in
memory. Furthermore, remember that every bit can only have two different
values: 0 or 1. As a human being you may think in base 10, but the computer is
busily storing values - and computing values - in machine code, base 2. The
largest possible 6-digit number in base 10 is 999,999 and the absolute largest
possible 16-digit number in base-2 is represented by the simulated integer
memory below.
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
This does not explain why 32767 + 1 gives negative results. The largest possible
integer, depicted above is not how an int is represented in C++. Numbers can be
positive or negative and the first bit is the sign bit. That leaves 15 bits for
representing the number. The 0 in the first bit indicates a positive number. A 1 in
the first bit is for a negative number. This means that 0 followed by 15 1s is the
largest integer, which equals 32,767.
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
This follows the same logic as 99,999 + 1 = 100,000. We do not see that logic
with the 32767, base 10 number, because we have not reached any maximum
digit values with base 10. At the base 10 level, 32,767 simply increments to
32,768. At the base 2 level the equivalent values “rollover” and result in the
integer value shown below.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Note, however, that the sign-bit, which was positive, has been changed to 1 and
now the whole number is negative. This is as far as we want to look at these
negative numbers. There is more complexity to the storing and management of
negative numbers.
If you read other computer science text books, you may see something called
complement arithmetic. There is a special way to compute negative values in
base 2. Right now the biggest point to realize, and remember, is that you will
get incorrect values when the variable “overflows.” This means that you need to
be very conscious that you pick the correct data type.
Several sections ago, we changed from float to double for our real number data
type of choice. In this section we are going to take a closer look at real numbers
and how we can control accuracy of the real numbers that are stored. You already
know from the previous integer overflow section that too large a number in too
little space causes problems. The float data type has 4 bytes, and double reserves
8 bytes to store its variables. This is considerably more than the modest 2 bytes
allowed for an integer. However, integers are not concerned with storing
fractional amounts. There can be plenty of problems with real number precision.
The first program example, PROG0616.CPP concentrates on the float data type
and displays, or tries to display, numbers that steadily increase the number of
digits beyond the decimal point. It does not take long before float runs out off
gas and stops giving proper precision. This program helps to identify the point
where this happens.
#include <iostream.h>
#include <conio.h>
void main()
{
clrscr();
float Number;
Number = 9.1;
cout << "Number 9.1 = " << Number << endl;
Number = 9.12;
cout << "Number 9.12 = " << Number << endl;
Number = 9.123;
cout << "Number 9.123 = " << Number << endl;
Number = 9.1234;
cout << "Number 9.1234 = " << Number << endl;
Number = 9.12345;
cout << "Number 9.12345 = " << Number << endl;
Number = 9.123456;
cout << "Number 9.123456 = " << Number << endl;
Number = 9.1234567;
cout << "Number 9.1234567 = " << Number << endl;
Number = 9.12345678;
cout << "Number 9.12345678 = " << Number << endl;
getch();
}
PROG0616.CPP OUTPUT
You see in the program source code of PROG0616.CPP that the number of
digits, beyond the decimal point, increases to eight. The output shows that the
float data type throws in the towel after six digits are displayed. Does this mean
that a double real number type allows twelve digits to be displayed? A logical
question. Let us check out some of these concerns.
A float data type allocates four bytes of memory. A double data type allocates
eight bytes of memory. The doubling of the memory allocation accounts for the
naming of the double type. With twice the number of bytes, it certainly is
possible to store more information. The larger space allows storing a larger
number as well as store more precision for the fractional portion beyond the
floating point. Floating point seems more accurate than decimal point. You may
see number in the decimal, base 10, notation. The computers sees numbers in the
binary, base 2, notation. Base 2 does not have any decimal point, but it is very
accurate to use the term floating point. This also explains the name of the C++
real number data type float.
C++ allows control over the digits following the floating point. It is done with the
setprecision function. Access to this function requires including the iomanip.h
function library. It makes sense to use a special function to indicate desired
precision. C++ is basically at a loss how accurately numbers should be displayed.
Programs that involve the processing of monetary values are happy with accuracy
that only goes two places beyond the floating point. A navigation program used
for a space shuttle mission will require much greater accuracy. How about the
construction of micro chips? Placing millions of bytes in one small space requires
an accuracy that is hard to imagine.
Now it is easy enough to state that accuracy of 15 digits beyond the floating point
is required. Do you get such accuracy? In other words, what are the limitations,
if any, of the setprecision function?
// PROG0617.CPP
// This program demonstrates precision with float and
double.
#include <iostream.h>
#include <conio.h>
#include <iomanip.h> // required for setprecision
function
void main()
{
clrscr();
float FNr;
double DNr;
getch();
}
PROG0617.CPP OUTPUT
So far only a few of the C++ data types have been discussed. It turns out that C+
+ has a wide variety of integer and real number data types that you have not seen
yet. There are integer types that are both smaller and larger than int and there are
more real numbers than just float and double. C++ has numerical data types that
take as little as 1 byte and as many as 10 bytes for memory. One feature that C+
+ allows is provided with the reserved word, unsigned. Placing this word in front
of an integer type doubles the maximum value of the integer, but limits the values
to non-negative numbers. The sign bit is no longer used and numbers can be
twice the signed value.
// PROG0618.CPP
// This program demonstrates the various integer
// and real C++ data types
void main()
{
char Int1; // 1 byte -128..127
unsigned char Int2; // 1 byte 0..255
int Int3; // 2 bytes -32768..32767
unsigned int Int4; // 2 bytes 0..65535
long Int5; // 4 bytes -
2,147,483,647..2,147,483,647
unsigned long Int6; // 4 bytes 0..4,294,967,295
float Float1; // 6 bytes 3.4e-38..3.4e38
double Float2; // 8 bytes 1.7e-308..1.7e308
long double Float3; // 10 bytes 3.4e-
4932..1.1e4932
Int1 = 127;
Int2 = 255;
Int3 = 32767;
Int4 = 65535;
Int5 = 2147483647;
Int6 = 4294967295;
Float1 = 3.4e38;
Float2 = 1.7e308;
Float3 = 1.1e4932;
clrscr();
cout << (int) Int1 << endl; // type casting is
needed
cout << (int) Int2 << endl; // type casting is
needed
cout << Int3 << endl;
cout << Int4 << endl;
cout << Int5 << endl;
cout << Int6 << endl;
cout << endl;
cout << Float1 << endl;
cout << Float2 << endl;
cout << Float3 << endl;
getch();
}
127
255
32767
65535
2147483647
4294967295
3.4e38
1.7e308
1.1e4932
This program showed many, many different data types. These types are shown
partially for your curiosity, and partially to create a reference if you need to use a
special data type.
At regular intervals I will make reference to the APCS C++ Subset or about
requirements for the APCS Examination. APCS stands for Advanced Placement
Computer Science. C++ is a very, very large programming language. The
College Board and ETS (Educational Testing Service), the folks who create the
APCS Examination, have created a C++ Subset that will be used to test students
for college credit.
The Exposure C++ series will cover every topic of the APCS Curriculum and
every feature of the APCS C++ subset. There will also be some additional topics
that are meant to be enrichment. One example is the data type section that was
just now mentioned.
It will be helpful for students and teachers in general to observe summary boxes
that help to summarize certain computer science features. These summaries are
provided at the conclusion of various topics. I believe this is more beneficial than
a summary at the end of each chapter. You are still getting a summary of
important facts, but they are provided throughout the chapter.
The word use means that you can write C++ source code
that includes the specified topic.
There exists a data type that stores either the value true or the value false. This
data type is called bool, short for Boolean. You will receive detailed information
about this data type in a later chapter.