3.1 + int( bool( int(3.1) ) )
char, bool, int, double.
// Suppose k is an int variable with value 4
(k - 2)*7 // This is an expression -- type: int, value: 14
k = 5 // This is an expression -- type int, value: 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, if x is a
variable of type double, then
(x = 3.4)*2.0 // type: double, value: 6.8, there is a side effect
makes perfect sense. In particular,
double, and after it is evaluated,
it has value 6.8.
x to 3.4.
cout << x // type: ostream, value: cout, there is a side effect
As we saw last lecture, cout is an object of type
ostream.
cout << x also
has type ostream, and its value is just cout
(like multiplying zero by anything, you still get zero).
x gets written out to the screen!
k+1 is something we
almost always know before running the program.
Look at the code below:
int k;
cin >> k;
cout << k+7;
k+7?
A: 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.
However, often the value of an expression cannot be determined until the program is run. Consider the code above again.
k+7?
A: Well, it depends what the user enters for input. That's something that cannot be known until the program is run.
int k for example, are not expressions. Therefore, the following
code will not compile successfully:
int n;
n = (int k); // Error! (int k) is not an expression -- type/value is not defined well
int k;
int n;
n = (k=4)*3; // Good! (k=4) is an assignment expression
n = (k=4;)*3; // Error! k=4; is not an expression, but a statement
Q: Consider the following code. What is the type and value of the expression
x*k?
|
A: (drag your mouse):
// x*k -- type: double, value: -6.6
Explanation: C++ knows how multiply two int objects, and it knows how to
multiply two double objects, but it doesn't know how to multiply
one of each. However, it understands that an int can be
converted to a 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. Specifically, the direction is as follows:
→ int → doubleSo, in our example above, 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 it?
Some more examples are shown on the right.
Arithmetics on chars.
One interesting feature of this match-up between characters and numbers is
that statements like
cout << ('b' - 'a') << endl // 'b'-'a': int
make perfect sense.
'b' corresponds to the number 98, and 'a' to
the number 97.
int subtraction
problem 98 - 97, which evaluates to 1.
cout << ('b'+3) << endl;
will output 101.
So, for example, consider the following code:
double x;
int k;
x = 3.3;
cout << (k = x) << endl;; // expression k=x -- type: int, value: 3
In the above, the expression k=x is of type int
with value 3. C++ truncates doubles when converting to
ints.
k is an int and you'd like to
convert it to the equivalent double, you'd write:
(double)kwhich would "cast"
k to type
double. C++ actually adds functionality to C, i.e. it is
literally C plus some other stuff. So C constructs like
(double)k all work.
m and n are ints,
n being the larger. We'd like to print out the value of
m/n. Well,
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;
Quick check: Can you explain what type and value you get with the following code?
1 / double(2)
Answer (drag your mouse): It's of type double and
value 0.5. Integer 1 is implicitly promoted to the double type before the
division operation.
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; |
Recall that 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 -
chars, ints, bools, and
doubles - be represented by zeros and ones? Our
understanding of types will really depend on being able to answer these
questions.
| type | #bytes | notes |
char | 1 | A single byte ASCII code for the character |
bool | 1 | 0 for false, and a non zero for true |
int | 4 | A 4-byte signed integer. |
double | 8 | Represented with a scientific notation (i.e., sign, mantissa, exponent) |
| code | program output |
|
p is at 0x7fffe5aec3c4 p's value is 3 |
& is called the address-of operator.
For any variable p, expression &p returns the
address in the memory where the variable p is located.
|
address value (annotate variables p and q) 0x000000000000 ... 0x7ffff79351c4 0x7ffff79351c8 0x7ffff79351cc 0x7ffff79351d0 0x7ffff79351d4 15 p 0x7ffff79351d8 12 q 0x7ffff79351dc ... 0xffffffffffff |
&pWhenever the value of a variable changes, you need to refresh the memory view to see the most recent content.
Sample run
$ ./a.out Enter key value: 3 Enter 4-letter message: lazy Encrypted message is: odcbSolution: Ceasar Shift Encryption