intthat's been assigned the value 4,
(k - 2)*7is an expression of type
intand value 14.
int k; cin >> k; cout << k+7;... what is the value of the expressioon
k+1? Well, it depends what the user enters for input. That's something that cannot be known until the program is run. However, the type of the expression
k+1is something we do know before running the program: it's
int. Most of the time (especially for the subset of C++ we concentrate on) the type of an expression is known at compile time, i.e. when compiling the program, as opposed to running it. Because of this, C++ is said to be a "statically typed" language.
One example of something that is less obviously an
k = 5, where
k is once
again a variable of type
int. The type of this
int, and the value is 5. In general,
an assignment expression has the same type as the
object being assigned to, and the same value as that object
after the assignment is carried out. Thus, oddly enough,
x is a variable of type
(x = 3.4)*2.0 makes perfect sense, it is an
expression of type
double, and after it is
evaluated, it has value 6.8. This is our first explicit example
of a side effect. The expression has type and value,
but additionally it has the side effect that evaluating the
expression changes the value of the variable
Another example of something that probably doesn't seem like an
expression but is in fact, is
cout << x.
As we saw last lecture,
cout is an object of type
ostream. The expression
cout << x
also has type
ostream, and its value is just
(like multiplying zero by anything, you still get zero).
However, there is a side-effect to evaluating this expression,
x gets written out to the screen!
k = 4is an expression as used in
(k=4)*3will evaluate to 12, the statement
k = 4;as a line of code ending in a semicolon is not an expression. Declarations of variables, something like
int kfor example, are not expressions - regardless of whether the ; is there. Still, most things are expressions, and understanding this fact and being able to identify the types and values of expressions are key to understanding C++ ... and most any other programming language.
xis of type
doublewith value 3.3, and
kis of type
intwith value -2? The answer is type
-6.6. The explanation is this:
C++ knows how multiply two
int objects, and it
knows how to multiply two
double objects, it
doesn't know how to multiply one of each. However, it
understands that an
int can be converted
double and vice versa. So it converts one and
performs the multiplication on two objects of the same type.
But which way should it go? For arithmetic, types are always
converted in the direction that gives the most precision - this
is referred to as type promotion - which in this case
means that the
int is converted (or promoted) to a
double, and the operation is performed on two doubles. It
wouldn't make nearly as much sense the other way round, would
This implicit type conversion (implicit meaning that it
happens automatically behind the scenes, without you doing
anything directly) happens in other cases. The only one
affecting us right now is assignments. You can assign an object
of one type to an object of a different type, as long as C++
knows how to do the conversion. If it doesn't, the compiler
will let you know. So, for example,
x is of type
double with value 3.3, and
k is of type
k = x is an expression of type
int with value 3. C++ truncates
doubles when converting to
intand you'd like to convert it to the equivalent
double, you'd write:
(double)kwhich would "cast"
double. C++ actually adds functionality to C, i.e. it is literally C plus some other stuff. So C constructs like
nbeing the larger. We'd like to print out the value of
cout << m/n << endl;will just print out zero! (Make sure you know why!) We'd like to get some fractional value, in other words, we'd like these values treated as
doubles. To explicitly convert them to
doubles first we'd write:
cout << double(m)/double(n) << endl;[Challenge: can you explain what type and value you get with
m / double(n)?] Explicit conversion can get tricky later on, but at this stage it's as simple as writing the new type name followed by the old object in ()'s.
|Some Quick Conversion Rules|
|int → double : This does exactly what you'd expect.|
|double → int : This simply truncates the value, meaning that whatever's after the decimal point just gets chopped. You can get in trouble if the double value is too big.|
|bool → int : true goes to 1, false goes to 0.|
|int → bool : 0 goes to false, everything else goes to true;|
|int → char : if the int is in the range 0-127 the char value is determined by the ASCII table;|
|char → int : the int value is determined by the ASCII table;|
You've probably heard terms like bits and bytes
used in connection with computers, and you've probably heard
people say that inside a computer everything is 0's and 1's. If
not, I'll say it now: Inside a computer everything is 0's and 1's!
(A bit is just a 0/1 value.)
But how can all of these things -
be represented by zeros and ones? Our understanding of types will
really depend on being able to answer these questions.
3027 → 3*10^3 + 0*10^2 + 2*10^1 + 7*10^0Or, for another example,
1011 → 1*10^3 + 0*10^2 + 1*10^1 + 1*10^0In the binary number system we have the same idea, but the base is now 2 rather than 10. So, binary digits are in the range [0,1], and now 1011 has a different interpretation. In binary it is short-hand for:
1011 → 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = 2^3 + 2 + 1 = 11 (in decimal)So, in binary the decimal number 11 is represented as 1011. The binary number 1001 = 2^3 + 1 = 9, for another example. With four bits, i.e. four binary digits, we can represent any number from 0 up to 15 (which is 2^3 + 2^2 + 2^1 + 2^0). With four decimal digits I can represent from 0 up to 9999, i.e. from 0 up to 10000 - 1. So we need more bits than decimal digits, but given enough bits we can represent any number we care to. Using k-bits, we can represent the numbers from 0 up to 2^k - 1.
bool is just a way of interpreting a byte
of memory. If all 8 bits of the byte are zero, the
interpretation as a bool is
false. Otherwise, the
interpretation of a bool is
char is just a different way of
interpreting a byte of memory! For example, the byte
01100001 is interpreted as the character
This intepretation of bytes as characters is called the ASCII
encoding, and this
table, for example, shows you the whole thing.
Interpreting 01100001 as a number in binary, we get the number
97, and if you look up 97 in the table, you'll see that it
corresponds to the character
Already we see one of the fundamental ideas behind computing, different types of objects may be represented by treating sequences of 0's and 1's in different ways. That's why C++ needs to keep track of the types of objects, so it knows how to interpret the contents of the chunk of memory associated with each object.
charas just being a small integer (I say small because 8-bits only allows us the range [0,255]). This interpretation pretty much tells us what to expect of conversions between
ints. One interesting feature of this match-up between characters and numbers is that statements like
'b' - 'a'make perfect sense. Looking at the ASCII table, we see that
'b'corresponds to the number 98, and
'a'to the number 97. So C++ treats this as the
intsubtraction problem 98 - 97, which evaluates to 1. In fact, the letters of the alphabet appear in order, so that a is 97, b is 98, ..., z is 122. So,
char('b' + 3)is the character
inton your PC consists of 4 bytes, or 32 bits, so it can represent very large numbers. We're not going to get into the question of how negative numbers are represented in binary. Essentially an
intlooks like the binary number representation we just talked about, but in 32 bits.
00000000 00000000 00000000 00000101... or it could be represented as
00000101 00000000 00000000 00000000... depending on what's referred to as as the "endianness" of the underlying machine. That particular distinction is beyond the scope of this course, but you will encounter it in subsequent CS/IT course.
int5 is represented in the computer as:
00000000 00000000 00000000 00000101... where I've broken things up into bytes to make it all a little clearer.
double takes up 8 bytes, or 64 bits. The format
is more complex, however, and we will not go over it here,
except to say that it is a binary version of the familiar
scientific notation. However, instead of a base of 10, it uses
a base of two. (Example: 12 is represented as 1.5 x 2^3.)
Let it suffice to say that the
double 1.0 is
represented by the following 64 bits:
00000011 11111111 11111111 00000000 00000000 00000000 00000000 00000000