a
and
a + n
mean?
a means
&a[0],
the address of the first element of the array.
a+n means
&a[n],
the address of the (non-existant) element
a[n]
that would come immediately after the last element
a[n-1].
See, for example,
loop.C.
const int a[] {
0,
10,
20,
30,
40
};
const size_t n {size(a)}; //number of elements in the array
for (const int *p {a}; p < a + n; ++p) {
if (p[0] == p[1]) {
cout << "Found 2 consecutive copies of the same value.\n";
}
}
During the first iteration of the loop,
the pointer
p
points to
a[0],
so
p[0]
and
p[1]
are
a[0]
and
a[1].
During the fifth and last iteration of the loop,
the pointer
p
points to
a[4],
so
p[0]
and
p[1]
are
a[4]
and
a[5].
But there is no
a[5],
so
p[1]
might be unpredictable garbage.
Or
p[1]
might blow up the program.
player.
Then it creates one structure named
player1
of this new type.
Then it passes the address of this structure
down to the two functions
moveDown
and
moveRight.
Do the underlined
++p’s
increment
p?
If not,
what prevents them from doing so?
No, the
++
increments
p->row.
It does not increment
p.
That’s because the
->
has higher precedence than the prefix
++.
See levels 2 and 3 in
this
chart.
Rewrite the program with the following three changes.
player
from a type of structure to a class of objects.
Since the class will have two
int
data members,
it should have a constructor with two
int
arguments.
The class will not need a destructor.
player1
from a structure to an object.
moveDown
and
moveRight
to member functions of the class.
When the program calls these member functions,
they should increment the
row
and
col
data members of the object.
#include <cstdlib> //for the macro EXIT_SUCCESS;
struct player {
int row;
int col;
};
void moveDown(player *p); //function declarations
void moveRight(player *p);
int main()
{
player player1 {0, 0};
moveDown(&player1);
moveRight(&player1);
return EXIT_SUCCESS;
}
void moveDown(player *p) //function definitions
{
++p->row;
}
void moveRight(player *p)
{
++p->col;
}
The following member functions are short enough to be inline, like the constructor:
#include <cstdlib> //for the macro EXIT_SUCCESS;
class player {
private:
int row;
int col;
public:
player(int init_row, int init_col): row {init_row}, col {init_col} {}
void moveDown();
void moveRight();
};
void player::moveDown()
{
++row;
}
void player::moveRight()
{
++col;
}
int main()
{
player player1 {0, 0};
player1.moveDown();
player1.moveRight();
return EXIT_SUCCESS;
}
const int a[] {
0,
10,
20,
30,
40
};
const size_t n {size(a)}; //number of elements in the array
//Output all the elements in the array, but do not change them.
for (int *const p {a}; p < a + n; ++p) {
cout << *p << "\n";
}
The
const
will prevent the
++
from compiling.
This type of pointer will always point to the same place.
minimum
and
maximum,
over and over in the member functions of this class,
please create them in a better way.
The two variables should be accessible only to the member functions
and friend functions of the class.
In other words,
the names of the two variables should be mentionable only in the member functions
and friends of the class.
class shoe {
private:
int shoeSize; //in the range 6 to 16 inclusive
public:
shoe(int init_shoeSize);
void changeSize(int newShoeSize);
};
shoe::shoe(int init_shoeSize)
: shoeSize {init_shoeSize} //Initialize the data member.
{
const int minimum { 6};
const int maximum {16};
if (shoeSize < minimum || shoeSize > maximum) {
cerr << "Can't create shoe with size " << init_shoeSize << "\n";
exit(EXIT_FAILURE);
}
}
void shoe::changeSize(int newShoeSize)
{
const int minimum { 6};
const int maximum {16};
if (newShoeSize < minimum || newShoeSize > maximum) {
cerr << "Can't change shoe to size " << newShoeSize << "\n";
return;
}
shoeSize = newShoeSize; //Update the data member.
}
class shoe {
private:
int shoeSize; //in the range 6 to 16 inclusive
static const int minimum { 6};
static const int maximum {16};
public:
shoe(int init_shoeSize);
void changeSize(int newShoeSize);
};
shoe::shoe(int init_shoeSize)
: shoeSize {init_shoeSize} //Initialize the data member.
{
if (shoeSize < minimum || shoeSize > maximum) {
cerr << "Can't create shoe with size " << init_shoeSize << "\n";
exit(EXIT_FAILURE);
}
}
void shoe::changeSize(int newShoeSize)
{
if (newShoeSize < minimum || newShoeSize > maximum) {
cerr << "Can't change shoe to size " << newShoeSize << "\n";
return;
}
shoeSize = newShoeSize; //Update the data member.
}
equals
that will take two objects of the same class,
and return
true
or
false
to tell me if the two objects
have the same value.
In order to do its work,
this function will need to use the
private members of the class.
Therefore the function will have to be either a member function or a
friend function of the class.
Should
equals
be a member function or a friend function,
and why?
Instead of
equals,
what would be a better name for this function in C++?
(“Better” means the name that everyone would expect the function to have.)
The function should be a friend function of the class,
because it uses
two
objects of the class.
(A function that uses only
one
object should be a member function
of the class.)
The name that everyone expects this function to have is
operator==.
See, for example,
this
date.h.
Make a class of objects whose constructor opens a file
and whose destructor closes the file.
Then create one of these objects and let it live out its life.
See, for example,
the object
outfile
in
constructor.C.
#ifndef,
#define,
and
#endif,
directives at the start and end of a
.h
file?
If a
.C
file accidentally includes the same
.h
file more than once, the
#
directives will make this harmless.
They will prevent the computer from reading the
.h
file the second time it is included.
decimal: 19
binary: 10011
hexadecimal: 13
#include <iostream>
#include <cstdlib>
using namespace std;
void f(int a); //function declaration
int main()
{
int i {10};
f(i);
cout << i << "\n";
return EXIT_SUCCESS;
}
void f(int a) //function definition
{
++a;
}
It outputs
10.
The program makes a copy of
i
and increments the copy,
but this has no effect on
i.
(The copy is named
a.)
const int i {1};
cout << (i << 4) << "\n";
It outputs
16.
(By default in C++, an
int
is output in decimal.)
Each left-shift gives a result that is twice the original number.
Four left shifts in a row will give us a result that is 16 times the
original number.
Note that
i << 4
has no effect on
i,
for the same reason that
i + 4
has no effect on
i.
1101 1110 1010 1101 1011 1110 1110 1111
DEADBEEF
int a[] {
0,
10,
20
};
int *p1 {a};
++p1; //Statement 1
++*p1; //Statement 2
int *const p2 {a};
++p2; //Statement 3
++*p2; //Statement 4
const int *p3 {a};
++p3; //Statement 5
++*p3; //Statement 6
const int *const p4 {a};
++p4; //Statement 7
++*p4; //Statement 8
1, 2, 4, 5
p2
and
p4
always point to the same place.
p3
and
p4
cannot change the value thay are pointing to.
They are “needles that can’t scratch the record”.
ints
into a
vector<int>
instead of into a plain old array of
ints?
ints
there will be.ints
as the program is running.
vector
van expand.
int i {0x4 | 0x2};
cout << i << "\n";
It outputs
6,
because in C++ an
int
is output in decimal by default.
In binary, the “bitwise or” calculation is
100 10 110See Bitwise or.
cout << "How many ints do you want to store? ";
size_t n {0};
cin >> n;
const int *p {new int[n]}; //Get a block of memory from the operating system.
//Don't make any other pointers.
//Some time later,
delete[] p; //Give the block back to the operating system.
The dynamically allocated block of memory is totally useless,
because you can’t
write any information into it.
That’s because the only pointer that points to it
is a
read-only
pointer.
operator<<
function to the following class,
so that the output of the program will be
(3, 4)
#include <iostream>
#include <cstdlib>
using namespace std;
class point {
private:
double x;
double y;
public:
point(double init_x, double init_y): x {init_x}, y {init_y} {}
friend ostream& operator<<(ostream& ost, const point& p) {
return ost << "(" << p.x << ", " << p.y << ")";
}
};
int main()
{
const point A {3, 4};
cout << A << "\n"; //means operator<<(operator<<(cout, A), "\n");
return EXIT_SUCCESS;
}
A lot of weird stuff went down in the old Soviet Union. In Red Plenty, a quirky book by Francis Spufford about the Soviet economy, I saw a reference to “glorious eccentricities, like Brusentsov’s trinary processor at the University of Moscow, the only one in the world to explore three-state electronics”. What advantages would a base 3 computer have over a plain old base 10 computer? Any disadvantages?
The advantages of base 3 over base 10
are the same as the advantages of base 2 over base 10.
A base 3 component would have simpler electronics than a base 10 component.
Therefore
The disadvantages are the same, too:
base 3 need more digits than base 10.
Consider, for example, the number 2026:
In base 10, it takes 4 digits (2026).
In base 3, it takes 7 digits (2210001).
In base 2, it takes 11 digits (11111101010).
.C
file, instead of breaking it up realistically into several
.h
and
.C
files.
Show me the lines of output that the program produces,
in the correct order.
#include <iostream>
#include <cstdlib>
using namespace std;
class littleObject {
private:
int i;
public:
littleObject(int init_i): i {init_i} {cout << "littleObject born\n";}
~littleObject() {cout << "littleObject dies\n";}
};
class mediumObject {
private:
littleObject lo;
public:
mediumObject(int init_lo): lo {init_lo} {cout << "mediumObject born\n";}
~mediumObject() {cout << "mediumObject dies\n";}
};
class bigObject {
private:
mediumObject mo;
public:
bigObject(int init_mo): mo {init_mo} {cout << "bigObject born\n";}
~bigObject() {cout << "bigObject dies\n";}
};
int main()
{
bigObject bo {10};
return EXIT_SUCCESS;
}
The innermost object is constructed first and destructed last.
If the
outermost
object were constructed first and destructed last,
we would momentaruly have a hollow object
(the outermost one),
without any guts.
littleObject born mediumObject born bigObject born bigObject dies mediumObject dies littleObject dies