Recitation: Friday 9/8/00, 11-12:00 (1-390)
TA: Petros Komodromos,
1-245,
petros@mit.edu
Office Hours:"The Java Tutorial", Mary Campione and Kathy Walrath, (required) "Core Java", Gary Cornell and Cay Horstmann, 2nd edition "The Java programming language", Ken Arnold and James Gosling, 2nd edition "Java: How to program", Deitel & Deitel, 2nd edition
Java 2 Platform API Specification
Prof Amaratunga: Tuesdays
and Thursdays, 4-5:00 p.m., Room 1-274
Petros: Fridays 12-2:00 pm,
Room 5-332
Eric: Mondays, 3:00-5:00 p.m,
Room 5-332
Problem Sets
You need to follow the instructions that are provided with each problem set, concerning what you must submit. In all problem sets you must both electronically turnin the source code files, and submit hardcopies of all completed, or modified, source code files. Sometimes you may also need to provide screen dumps of the window with the output results from the execution of your programs.
The problem statement and the provided source code files can be obtained
using CVS, which is a version control system (covered later in this recitation).
The problem set statement can also be obtained through the class homepage
(http://command.mit.edu/1.124_F00/home.nsf)
Whenever source code files are provided, the following naming convention
is used:
For each question there is a ps<number_of_problem_set>_<number_of_question>.C
which
you may need to use, e.g. ps3_2.C for question 2 of problem set
3.
In some cases a makefile (named make<number_of_problem_set>)
is provided, which you may use to compile and link your code
Please comment your code to make it more readable whenever you think
it would be helpful for someone else to understand what and how you do
it (i.e. for the graders). Comments may be incorporated in your code by
either enclosing them between /* and */, or, by putting them on the right
side of two division symbols //.
It is also very useful for both yourselves, and the graders, to indent
your code in order to emphasize loops and different parts of your code.
You should indent your code so that different blocks start in different
columns making it less obscure and difficult to understand.
Please, do not make any other changes to the provided code, except
those that you are asked to make.
You can print a file in a compact form (saving some paper) using the
following command so as to have the name of the file and the time and date
printed on the hardcopy.
athena% enscript
-2Gr -P<printer name> <filename>
Whenever necessary, you can dump an X window directly to a printer
using the following command and clicking on the window you want to print.
athena% xdpr -P<printer
name>
Homework that is turned in late will be penalized as follows:
Please, always staple your hardcopies together and write clearly
on the first page your name and username. Also, type within a comment at
the top of each file you submit the following information:
This problem set will be checked (its electronic turnin, in particular), but not graded. It is in your interest to spend some time getting familiar with Athena and the introductory topics covered in this problem set. Although for this problem set you don't have to submit any hardcopies (printouts), for all following problem sets you have to submit hardcopies of your source code files, in addition to the electronic turnin.
The provided source code files are in the source repository directory /mit/1.124/src from where you can check them out to your directory using CVS, and then, make the necessary additions and/or modifications.
To use CVS in order to check out a problem set (or any other provided
files) from the 1.124 you should set the environment variable CVSROOT
as below: (you can also put it in your .environment dotfile to avoid repetition)
% setenv CVSROOT /afs/athena.mit.edu/course/1/1.124/src
then you can use either of the following commands:
% cvs co Problems/PS0
% cvs co OOP_PS0
(alias defined in 1.124/src/CVSROOT/modules)
You can customize your account, using a dotfile, so that it will automatically
add the gnu locker at start-up. In the file .environment you need to add
the following line:
add -f gnu
The add command attaches the specified locker to your workstation and
adds it to your path. Dotfiles, such as .environment and .cshrc.mine,
can be used to set environment variables, shell aliases and attach lockers
in order to get the desired working environment. In the .environment dotfile
you may also put the following lines to avoid typing them every time you
log in:
add infoagents
add 1.124
setenv CVSROOT /afs/athena.mit.edu/course/1/1.124/src
You can check if you properly use the GNU compiler by giving the following
commands:
% which g++
which should give you something like:
/mit/gnu/arch/sun4x_55/bin/g++
or /mit/gnu/arch/sgi_53/bin/g++
Then, you can use the GNU compiler to compile a C++ source code file.
For example, to compile and link the source code file ps0_1.C, which
is provided in PS0, you can use the following command:
% g++ ps0_1 .C
Then, you can run the generated executable file, which is by default
named a.out, by typing its name at the Athena prompt.
To give a specific name to the generated executable the -o option must
be used:
% g++ ps0_1 .C -o ps0_1
Then, the generated executable file is named ps0_1
Sometimes, you may need to include an external library, e.g. the math
library, using the -l option as follows, and the name of the external library
(below the math library is included using m after -l) you want to include
(in addition to including its header file in your files):
% g++
ps0_1 .C -o ps0_1
-lm
In some cases that you only need to compile a file without linking,
i.e. to generate only the corresponding object file (machine language versions
of the source code) and not the executable, you need to use the -c option.
(In the following example a ps0_1.o will be generated)
% g++ -c ps0_1 .C
You also need to use the flags -ansi -pedantic to enforce the rules
of ANSI Standard C++. In addition, it is useful to use the -Wall option
to get all warnings, e.g.:
% g++ -ansi -pedantic -Wall
ps0_1 .C -o ps0_1 -lm
It is more convenient to set an alias (e.g. c++), instead of typing
all this every time. In particular you can add in your .cshrc.mine
dotfile the following:
alias "c++" "g++
-ansi -pedantic -Wall -lm"
and then simply use the following command to compile and link a program:
% c++ ps0_1 .C
-o ps0_1
In addition, you can use makefiles to help you automate the compilation
and linking of your programs. The following command creates the target_filename
according to the instructions provided in the makefile make0a.
% gmake -f makePS0a ps0_1
Eventually you must learn to use makefiles since they are extremely
useful for the development of large programs with several different source
code files.
Although you may work at any machine and using any compiler you want, you need to make sure that your code compiles properly using the GNU compiler on an Athena workstations. The graders will be using Athena workstations and the GNU compiler to check your solutions.
The debugger allows you to examine in detail what is happening during a program execution, or when it crashes due to a run-time error. In order to be able to use a debugger, such as gdb and ddd, you must first compile and link your code with the flag -g. e.g.:
% g++ -g
ps0_1 .C -o ps0_1
The g++
-g ps0_1 .C -o ps0_1 command
generates an executable filename that can be checked with gdb, e.g. using
the following command for the program compiled above:
% gdb ps0_1
You can find more information about GDB at the following URL:
A user friendlier debugger, available on athena,
is the Data Display Debugger (ddd), which uses the gdb for its operations.
The ddd program is available in the outland locker. Since we also need
the g++ compiler from the gnu locker for the compilation you need to type:
% add outlandTo invoke the ddd debugger with your executable program, e.g. for ps0_1, please, type:
% add gnu
% ddd ps0_1 &You can see that three windows pop up:
The execution of the program can be controlled from
the ddd command tool which has the Run, Interrupt, Step,
Next
etc. buttons.
You can step through the program using the buttons on the ddd window. A green arrow will indicate the current program statement being executed in the source code panel.
You can continuously see the values stored in a variable, by displaying it instead of printing it. The displayed variable will be shown in a new panel which will pop up above the source code panel. As you step through the program, any changes to the variable’s value will be shown there. You can display a variable by:
choose "Display function arguments" from the ’Data’ tab in the menu bar of the main window
Input and output is done through the debug console.
You can learn more about ddd from the ddd web-page at
http://www.gnu.org/software/ddd/ddd.htmlYou can find the ddd manual at the following URL:
http://www.gnu.org/manual/ddd
In problem set # 0, a simple makefile is provided for you, called makePS0a,
which you may use to compile and link your code. There is also a more advanced
makefile named makePS0b which you can use.
e.g. athena%
gmake -f makePS0a ps0_1
Executing the above command creates the target filename ps0_1,
according to the instructions provided in the makefile makePS0a.
You can find more information related to developing makefiles at the
following URL
http://www.lns.cornell.edu/public/COMP/info/make/make_toc.html
e.g. to submit the ps0_2.C file for problem set #0 you should use the
following command:
% turnin -c 1.124
0 ps0_2.C
Please, do not turnin any executable files electronically.
Problems set source code files must be turned in electronically before the beginning of the lecture (i.e. before 2:30 p.m.) on the due date of the problem set, unless permission has been granted from either of the professors prior to the due date. Any files turned in later than that time will be considered late and will be penalized.
A procedural language is based on a list of instructions (statements) organized in procedures (functions) and emphasizing the computations to be performed. Languages such as Fortran and C are procedural languages. C++ which is based on C, has many additional features that enable object oriented programming, where emphasis is given on the data and their behavior. Java is a pure object oriented language.
The additional features and advantages of C++ are the
following:
Classes allow the programmer to create her/his own data types extending
the capabilities of the language according to the physical world problems.
Classes are similar with the data structures in C, which are also available
in C++. However, within a class both data variables and member functions
that are used to work with the data variables can be provided.
class Complex
{
public:
double real;
double imaginary;
};
main()
{
Complex x;
x.real =15.5;
x.imaginary = 2.5;
}
There are many additional features, like inheritance and virtual functions, added to C++ which are related with the classes and provide simple ways to handle objects and develop programs in an object oriented programming style.
C++ allows reusability since a class which has been written, debugged and checked can be distributed to other programers and with minimal effort be incorporated in several programming packages.
C++ supports function overloading which allows the use of functions
with the same name, as long as they have different signature. The signature
of a function is considered its name and the number and type of its arguments.
e.g.:
int min(int x, int y) {
}
double min(double x, double y) {
}
In addition, virtual functions and polymorphism allows the dynamic binding on functions during run-time instead of static binding during compilation.
C++ allows operator overloading, i.e. to use operators with user
defined data types according to a specified function associated with the
specific operator. For example, we are able to add two complex numbers
which are a user defined data type, as long as we provide the necessary
functions for operator overloading.
main()
{
Complex x,y,z;
........
z = x + y ;
}
In C++, there are two ways to comment, // (which comments everything until the end of line), and /* */ (which comments everything between /* and */.
Two latest features of C++ are the templates and the exception handling. The templates allow us to parameterize the types within a function or a class providing a general definition that can be used for many different purposes. The exception handling mechanism provides a mechanism to respond to and handle run time errors (like division by zero, exhaustion of memory, etc.).
The bool data type can be
assigned the values true and false, which correspond to 1 and 0, respectively.
A char can be used both as a
character and as an integer, depending on how it is used. Therefore, char,
short,
int,
and long are all called integral data types.
There are also unsigned versions of
integer types, which allow the increase of the range of the larger number
that can be stored with them, by not using any bit for the sign: unsigned
char, unsigned short int (unsigned short), unsigned int, unsigned long
int (unsigned long).
The reason of using different data types is mainly for memory efficiency, since we can use the data type which correspond to our needs avoiding useless waste of memory. The proper data type must be selected and used based on the expected requirements during the program’s execution.
To refer to particular variables that correspond to a particular chunk of memory in C++ (and in any other programming language) we have to use identifiers (variable names). The variable names in C++ are case sensitive as they are in C, must begin with a letter or an underscore (_), and should not be a reserved keyword. You should use reasonable variable names that provide some meaning to the reader of your code.
Using the above keywords we can declare the data type of a variable giving to the compiler information about the necessary amount of memory required to store (i.e. the memory that is required to be allocated and reserved for) the variable and which is machine dependent, e.g.:
<data_type1>
<variable1_name>;
<data_type2> <variable2_name> = <initial_value>, <variable3_name>;
int a, b, c;The above declarations are also definitions. A declaration simply informs the compiler that the variable exists, its data type and that it is defined somewhere else in the program. C++ allows to have many declarations of the same variable as long as they are consistent. The definition of a variable defines the variable’s name, its data type and may also initialize the variable. Defining a variable informs the compiler about the variable's data type so as to reserve the proper amount of memory to store values for that variable. The difference is that the definition reserves memory for the variable. Therefore, there must be only one definition of a variable in a program. A declaration is also a definition if it also sets aside memory at compile time.
double x,y ;
float z ;
For example, the following statement is a declaration because it informs
the compiler that an external global variable will be used, but no memory
is allocated for that variable. The memory is allocated at the definition
of the variable.
extern int x_limit ;
// declaration
We can also initialize a variables in its definition, assigning an initial
value and this is called initialization. When a value is assigned
to an already defined variable this is called assignment:
int a, b, c;
// definitions
double x = 3.4, y(4.);
// definitions and initializations
float z = 9.9;
// definition and initialization
c = 10;
// assignment
An assignment expression has the value that is assigned to the variable
on the LHS, and, therefore, several variables can be assigned the same
value in one statement,
e.g.: x = y = z = 100;
The RHS of logical operators is executed only if its necessary for the decision that must be taken. e.g. if the LHS of a ‘logical and’ (&&) is false, there is no reason to examine its RHS.
In addition, in C++ it is allowed to create new definitions for operators
applied to user defined data types.
main()
{
Point x,y,z;
........
z = x + y ;
}
An action in C++ is referred as an expression, while an expression terminated by a semicolon is called a statement. More than one statements enclosed in a pair of curly braces is called a compound statement.
Precedence and associativity: The sequence (order) with which individual components of an expression in C++ are executed is based as in C on the order of precedence. When the operators have the same precedence the associativity defines the order of execution. A table with the precedence and associativity of the C++ operators is provided. Similar tables you can find in any C++ textbook.
e.g. a =
b += 5 +
3 / 2
- 5 +
17 / 2 /
3
(order): (8)
(7) (4)
(1) (5)
(6) (2)
(3)
The following table provides the precedence and associativity of the
C++ operators with the highest precedence being the operator :: having
precedence level equal to 1.
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<<= , >>= , &= , |= , ^= |
|
|
|
|
|
|
Conversions: C++ defines a set of standard conversions, implicit type conversions, that are used in arithmetic conversions, assignments using different data types, and passing arguments to a function of different data types than the function parameters. In particular, when we have such mixed expressions the compiler makes some standard conversions, e.g. in binary operations the lower data type is promoted to the higher one (which dominates), so as to avoid losing information.
The following order is used:
bool, char, short int < int < long int < float < double <
long double
bool, char and short int are always converted
to int whenever they appear in any expression, i.e. before performing any
operation on them. A bool is promoted to int, getting the value 1 or 0,
depending on its value (true or false, respectively). When a number is
converted to a type bool all values other than zero are converted to true
and a zero value is converted to false. Integer constants (e.g. 17) are
considered int, and, floating point constants (e.g. 4.53) are considered
double.
We can use L after an integer and a floating point constant to define that
should be considered as a long int, and, a long double, respectively.
In C++, we can also define rules of conversions to be used with operators applied on user-defined data types.
We can also explicitly define type conversions using casting to force the explicit conversion from one data type to another.
(dataType) variableOrExpression ; and dataType (variableOrExpression) ;
Another way do an explicit conversion, i.e. to cast a data type constant
or variable to another data type, is using the keyword static_cast followed
by a data type name surrounded by angle brackets and the certain variable
or constant to cast within parentheses, e.g.
static_cast <dataType> (variableOrExpression)
static_cast <float> (5) / 3
// gives 1.66667
/* Example: Mixed Expressions - Precedence - Associativity - Casting */
#include <iostream.h>
main()
{
int i=4 ;
float f = 2.5 ;
double d = 3;cout << "\n i / 5 * f = " // Mixed Expressions
<< i / 5 * f << endl ;cout << "\n 'a' = " << 'a' << endl ;
cout << "\n 'a' - 1 = " // Mixed Expressions
<< 'a' - 1 << endl ;
cout << "\n 'f' - 'd' = " // Mixed Expressions
<< 'f' - 'd' << endl ;cout << "\n f + 5 * d = " // Precedence
<< f + 5 * d << endl ;cout << "\n f * 2 * 2.5 = " // Associativity
<< f * 2 * 2.5 << endl ;cout << "\n (float) i / 5 * f = " // Casting
<< (float) i / 5 * f << endl ;
cout << "\n float i / 5 * f = " // Casting
<< float (i) / 5 * f << endl ;
cout << "\n static_cast <float> (5) / 3 = " // Casting
<< static_cast <float> (5) / 3 << endl;
}
Results:
i / 5 * f = 0 float 0.0
'a' = a character
'a' - 1 = 96 int 96
'f' - 'd' = 2 int 2
f + 5 * d = 17.5 double 17.5
f * 2 * 2.5 = 12.5 double 12.5
(float) i / 5 * f = 2 float
2
float(i) / 5 * f = 2
float 2
static_cast <float> (5) / 3 = 1.66667
The output operator (<<) (known as insertion operator)
directs (display) output information on your standard output (screen),
e.g.
cout << "\n x = " <<
x << endl ;
"\n" represents a new line character, while endl inserts a new
line and flushes the output buffer. The operating system buffers the output
to the display characters and prints them out in a batch to minimize I/O
overhead. This may lead to wrong indications of where the error may be
if we consider the printed out information without flushing the buffer.
We may have several output operators in the same output statement
Similarly, you can use the input operator (>>) to obtain (read)
input values from the standard input (keyboard). e.g.:
cout << "\n x = " ;
cin >> x ; cin >> y >> z;
The standard input-output library (iostream.h) must be included using a preprocessor directive, in order to be able to use the input and output operators, as well as the manipulators without arguments such as endl, flush, hex, oct, etc.
Certain options may be specified when using the output stream operator
to select the way that the output should look. The precision can be set
using a iostream manipulator, the setprecision(number_of_digits),
while the setiosflags(options separated by |) can be used e.g. to
specify whether the decimal point or tailing zeros should be shown. The
setw()
specifies the field width in which the next value should be printed out.
It is the only manipulator that does not apply to all subsequent input
or output, but becomes zero as soon as something is printed. The setfill(c)
makes c the fill character. To use these parameterized stream manipulators
(i.e. with arguments) we need to include the iomanip.h header file.
e.g.:
cout << setprecision(2) <<
setiosflags(ios::fixed | ios::showpoint)
<< "\n\n 3. = " << 3. << "\t 0.333333 = " << 0.333333
<< endl;
(will give: 3.=3.00 0.333333 = 0.33)
We can also redirect the input from the keyboard to a file and the output
to another file:
athena% executable_file_name
< input_file_name > output_file_name
Finally, there is a standard error stream cerr which is used to display
error messages
cerr << "\n Not proper values
were provided!" ;
The following member functions can be invoked by the input stream, cin: cin.good() returns true if everything is ok;, cin.eof() return true if EOF is reached; cin.fail() returns true if a format error has occurred.
The C input/output functions scanf()/printf() can also be used, since C is a subset of C++. In that case the stdio.h header file (which contains their prototypes) must be included. Then, the buffer can explicitly be flushed using "fflush(stdout);".
However, when both C input/output functions and C++ input and output
operators are used, you need to provide the following function call before
doing any input or output, to avoid problems:
ios::sync_with_stdio();
An include preprocessor directive results in the substitution
of it, with the contents of the indicated file. i.e. the following include
preprocessor directive:
#include <file.h>
is equivalent to typing the contents of the included file at that point.
There are two variations of the include preprocessor directive:
#include <file.h>
or #include "file.h"
The difference is that in the first case the preprocessor searches
for the included file in the standard include directory, while in the second
case it searches in the current directory. The latter case is usually used
for the user written functions.
Another preprocessor directive is the #define which it can be used to
associate a token string with an identifier, e.g.
#define PI 3.1415926
The preprocessor will replace PI wherever it appears in a file with the provided token. After the preprocessing finishes the compilation starts, in which the token is treated as a floating point constant.
Other preprocessor directives are the following: #ifdef, #ifndef,
and, #endif They can be used for conditional compilation.
e.g. the ...... statements will be skipped if _MY_HEADER_H has
already been defined.
#ifndef _MY_HEADER_H
#define _MY_HEADER_H
........
#endif
Also, while compiling a program we can define a preprocessor constant
on the command line using the -D option followed by the name of the preprocessor
constant and therefore certain parts of the code can be selectively excluded.
e.g. compiling the file with -DDEBUG_MODE option will consider the
cout statement:
#ifdef DEBUG_MODE
cout << "\n testing debug
mode \n" << endl;
#endif
The define directive can also be used to specify macro substitutions
with variable parameters. e.g. having defined the following macro using:
#define mult(x,y) (x*y)
then, the following statement:
product = 267.2 + mult(25.7, 33.6)
will be replaced during preprocessing by: product
= 267.2 + (25.7 * 33.6)
When the C input/output functions scanf()/printf() are used the stdio.h header file (which contains their prototypes) must be included instead.
Similarly to be able to use any other standard library function
you need to include its header file which contains all necessary declarations.
e.g. to be able to use the math function, such as sqrt() you
need to include the math.h header file using the following
command:
#include <math.h>
When the header file that you include is in the current directory, e.g.
a header file that you wrote, then you should use double quotes, instead
of brackets, e.g.:
#include "myheader.h"
According to the new ANSI/ISO standard, which however is not followed
by all available compilers yet, the iostream header file can be included
using:
#include <iostream>
using namespace std;
int main()
{
std::cout
<< "\n testing:
pi = " <<
3.1415 << endl;
}
Header files are very useful to provide declarations (e.g. for global variables and functions) in order to avoid incompatible declarations which may happen when multiple declarations are provided in several source-code files. In addition, any changes to a declaration would require only a single local modification instead of having to update all appearances of the declarations. A header file should never contain definitions, (unless its a definition of an inline function).
The C++ control structures are identical with those of C. The relational operators ( > , < , >= , <= ), equality operators ( == , != ), and the logical operators (&& , || , !) are used in logical tests which produce either true or false (0).
Typically, the following operators are used to form a logical test for the control structures which determines what action should be taken:
In all control structures, a simple (i.e. single), or a compound, i.e. a sequence of statements enclosed in curly braces, statement is either conditionally or repeatedly executed, based on a logical test.
The if and if-else, as well as the switch
control structures are used to make certain selections
The simplest selection control structure is the if, where if the logical
test is true (i.e. non zero), then the following statement (or statements
in curly braces) is (are) executed. Otherwise the statement (or statements)
is (are) skipped and the statement after the if control structure is executed.
if
(logical test)
statement ;
if-else if-...-else control structure provides several
alternative actions. (It is more efficient to put the most probable selection
first to reduce the chances of multiple checks)
if (logical test)
(if-else if -else provides alternative actions)
{
statements
(executed if (logical test) is true)
}
else if (another logical test)
(checked
if (logical test) is false)
{
statements
}
else
(executed if not any (logical test) is true)
{
statements
}
The switch() control structure is useful when there are
many different selections. It consists of multiple selection cases and
an optional default case. Only constant integral expressions can be checked
in switch() cases. The controlling expression in the parentheses
determines which of the cases should be executed and starts executing statements
in that case continuing until the closing brace of the switch control structure,
or until a break is reached. The break causes the program to exit the switch
structure and execute the next statement after it.
switch (x)
{
case 1:
statements
break;
case 2: case ’b’: case
’B’:
statements
break;
case 3:
case ’c’:
statements
break;
........
default:
.........
}
while, do/while, and for are the repetition control structures of C++, i.e. are used when iterations are required.
The statements of the while control structure are executed
repeatedly as long as the logical test is true, and, at each iteration
when the closing brace is reached, control is passed back at the beginning
of the while loop. The while loop is continuously repeated until the logical
test becomes false (i.e. equal to zero)
while(logical test)
{
statements // statements
executed repeatedly as
// long as the logical test is true
}
The do/while is similar to while with the only difference
that its body is executed at least once since the check is done at the
end.
do
{
statements
// executed repeatedly as long as the logical test
} while(logical test);
// is true but always executed at least once
The for control structure is used for repetitions, when
we have a regular incrementing. First, expr1 is evaluated, which is usually
used to initialize the loop variables. Then, the logical test (which is
a loop continuation condition) is evaluated, and if it is true (i.e. nonzero),
the following statements, within the curly braces, are executed. Finally,
expr3 is executed (usually providing an increment or decrement of the control
variable), and then the procedure from evaluation of the logical test is
repeated, as long as it is true (i.e. non zero.) expr1 and expr2 can be
comma separated lists of expressions, which are executed from left to right.
All three expressions are optional, although the two semicolon are always
required.
for (expr1 ; logical test ; expr3)
{
statements in body of for loop
}
Finally, the following control structure is the conditional operator
which produces a value based on the logical test. Therefore, it can be
placed inside another expression. The first expression after the question
mark is executed if the logical test is true. Otherwise, the expression
after the colon is executed.
( logical test) ? when_true_statement
: when_false_statement ;
e.g.: max = (x>y) ? x : y ;
(i%2) ? cout << i << " is an odd integer" : cout << i
<< " is an even integer" ;
The break statement is typically used to skip the remainder of the switch statement. It is also used to exit repetition control structures (i.e. while, do/while and for). In all these cases execution continues with the first statement after the terminated control structure. The break statement exits the innermost loop, or switch statement.
The continue statement is used to skip the current iteration of a repetition control structure and continue with the next iteration, if there is one, i.e. the current iteration only is terminated and execution continues with the evaluation of the logical test of the next iteration. It goes to the next iteration of the innermost loop.