Laboratory Training 3
C++ Statements
1 Training Tasks
Operations and statements should be used to complete all tasks. All statements should be plcaed into main()
function's
body.
1.1 Programmatic Implementation of Branching Algorithm
Develop a program that implements an algorithm for solving quadratic equation. The program should include checking all possible variants of the source data. In particular, the discriminant should be checked, and it should be checked whether the equation is quadratic. If the equation degenerates into a linear one, it is necessary to provide for finding the root of this linear equation, or to establish the presence of infinite count of solutions (absence of solutions).
Examples of source data and results:
Source Data | Output |
---|---|
1 1 -2 |
x1 = -2 |
1 1 2 | No roots |
2 2 -4 |
x1 = -2 |
0 1 2 | x = -2 |
0 0 10 | No roots |
0 0 0 | Infinite count of roots |
1.2 Programmatic Implementation of Looping Algorithm
Develop a program in which the user enters the values of x, n, and k. The program implements an algorithm for calculating the following expression:
In the given sum, the common element can be written as i/(x + 2i), but it omits one element when i = k. Provide a check of possible errors.
Examples of source data and results:
Source Data | Output |
---|---|
x = 1 |
1.20635 |
x = 1 |
1.60635 |
x = -2 |
Error |
1.3 Calculating Product
Write a program that reads x
and n
and calculates y
:
Examples of source data and results:
Source Data | Output |
---|---|
x = 1 |
-720 |
x = 0.5 |
46899.3 |
1.4 Calculating Sum
Write a program that reads eps
(a small number that is the accuracy of calculations) and calculates y
:
The loop terminates if new summand is less than eps
.
Examples of source data and results:
Source Data | Output |
---|---|
0.1 |
0.875 |
0.00001 | 0.999985 |
0.0000001 | 1 |
1.5 Individual Assignment
You should develop a program that calculates values of a function in a given range. The program should implement an algorithm developed in carrying out assignment 1.3 of the first lab.
2 Instructions
2.1 Null Statement
Previously, the classification of statements was given, and the syntax and techniques of working with description statements and expressions statements were considered.
A null statement (empty statement) is just the semicolon and nothing else. A null statement is used when the statement is needed syntactically, but no action is required.
2.2 Compound Statement
A compound statement is a sequence of statements enclosed in braces {}
. A compound statement
is also called a block. The block does not end with a semicolon. Syntactically, the block can be considered
as a single statement. For example:
{ temp = a; a = b; b = temp; }
Compound statements are usually placed in those places of the program where the syntax allows the only statement, but the algorithm requires several actions.
The use of blocks is associated with certain rules for formatting the source code. The brace opens on a new line, no code is placed after it in this line. Subsequent statements are allocated on the next line with indentation. For indents, you can use:
- two spaces;
- four spaces;
- tab character.
In these lab examples, four spaces are used for indentation.
After the last statement of the block (before the closing brace), a new line is entered, and the last indentation is canceled. A closing brace is located on a separate line.
Blocks can be nested inside each other. Example:
{ a = x; b = y; { temp = a; a = b; b = temp; } }
The block is also important in determining the scope and lifetime of identifiers. The identifier declared inside the block has scope from the point of definition to the closing brace. For example,
{ int i = 1; { int k = i; } k = 2; // Error! The variable k is not available in the external block }
It is bad idea to create local variables with the same name, especially since some languages (e.g. Java, C#) don't allow it.
Modern coding standards require the placement of blocks in the branches of a conditional statement and in the body of a loop, even if this block is syntactically unnecessary.
2.3 Selection Statements
2.3.1 Condition Statement
Selection statements allow you to perform different actions depending on the conditions that arise during the execution of the program.
The condition statement (if
statement) controls conditional branching. The syntax for the if
statement
has two forms:
The first form:
if (expression) statement
The second form:
if (expression) statement1 else statement2
In the first form of the syntax, if expression is true
(nonzero), statement
is
executed. If expression is 0 (false)
, statement
is ignored.
In the second form, statement1
is executed if the condition expression returns a value other than 0 (true
), statement2
is executed if the result of the condition expression is interpreted as 0 (false
).
A condition expression can be of any integer type (or a type that can be converted to integer).
With both forms, control then passes from the if
statement
to the next statement.
The statements (statement
, statement1
, statement2
) can be a single statements
ending with a semicolon or a blocks enclosed in braces. For example:
if (i > 0) y = x * i; else { x = i; y = x + i; }
In this example, the statement y = x * i
is executed if i
is greater than 0. If i
is
less than or equal to 0, i
is assigned to x
and x + i
is assigned to y
.
Note: good coding practice recommends always using a compound statement in if
statements
and loops, even if a single statement executed.
The algorithm for calculating the reciprocal value presented in the first laboratory training can be programmatically implemented using a conditional statement:
#include <iostream> using namespace std; int main() { double x; cin >> x; if (x == 0) { cout << "Error" << endl; } else { double y = 1 / x; cout << y << endl; } return 0; }
As can be seen from the above example, in both branches of the if
statement there
are compound statements in accordance with good coding practice. In addition, the variable y is defined inside the
block in only one of the branches. This style is considered more correct than defining all variables in advance.
Very often, beginners make the mistake of using if (x = 0)
instead of if
(x
== 0)
:
int x = 3; if (x = 0) { cout << "zero"; } else { cout << "non-zero"; }
Using such a condition will not cause compiler errors, only a "hint" can appear, but it will lead to unpleasant
consequences. The block that must be executed if the condition is true
, will never
be executed and control will pass to else
. In addition, the value of x will be spoiled. After such "checking",
it will always be 0.
The following program calculates the result of division:
#include <iostream> using namespace std; int main() { double a, b; cout << "Enter a and b: "; cin >> a >> b; if (b) { double c = a / b; cout << "Quotient is " << c << endl; } else { cout << "Error" << endl; } return 0; }
As can be seen from the example, instead of checking if
(b != 0)
, it
is enough to write if
(b)
. This form is typical
for C and C++, but is forbidden in some other languages, such as Java or C#.
Conditional statements can be nested within each other. For example, It is necessary to enter x and output the following messages "left" if x < 0, "inside" if 0 ≤ x ≤ 1 and "right" if x > 1. The input and checking code can be as follows:
double x; cin >> x; if (x < 0) cout << "left"; else if (x <= 1) cout << "inside"; else cout << "right";
To avoid confusion in this case, it is also advisable to use braces:
double x; cin >> x; if (x < 0) { cout << "left"; } else { if (x <= 1) { cout << "inside"; } else { cout << "right"; } }
Typical mistakes of beginners are the placement of the condition after else
(syntax
error), as well as the unnecessary checking of a condition that has already been checked:
if (x < 0) { cout << "left"; } else { if (x >= 0 && x <= 1) { cout << "inside"; } else { if (x > 1) { cout << "right"; } } }
You should avoid unnecessary actions in the program.
When working with a conditional statement, errors related to the use of an extra semicolon may occur. Even
if the variables x
and y
have been correctly created and initialized, the following code
will not compile:
if (x > 0); { y = 1; } else { y = 2; }
The error is due to the fact that a semicolon was placed after the checking. In fact, there is
an empty statement (;
) after if (...)
. This empty stament is executed
if the statement is equal to true
(1). The compound statement is executed in all cases.
The else
keyword in
this case no longer refers to if
, which causes a compilation error. Therefore, do
not abuse semicolons in the source code.
2.3.2 The switch Statement
The switch
statement allows for branching on multiple values of expression.
switch (expression) { /* body */ }
The switch statement body consists of a series of case
labels and an optional default
label.
The label consists of the case
keyword followed by a constant expression. No two constant expressions
in case
statements can evaluate to the same value. The default
label can
appear only once.
Execution of the switch consists of calculation of the control expression and transition to the group of statements
marked by a case
label which value is equal to the control expression. If there is
no such label, statements are followed after the default
label. During the execution
of the switch, the statements with the selected label are passed, and then the statements are executed in the normal
order. In order not to follow the statements that remain in the body of the switch, you must use the break
statement.
For example:
switch (i) { case 1: cout << "equals to 1"; break; case 2: cout << "equals to 2, "; default: cout << "not equals to 1"; }
The results of running previous code are following:
i | Output |
---|---|
1 | equals to 1 |
2 | equals to 2, not equals to 1 |
another | not equals to 1 |
The expression after switch
keyword must be integer.
The switch
statement allows you to create a simple menu. Depending on the user input, the program
performs different actions. Example:
double x; cout << "Enter x\n"; cin >> x; cout << "1 - Calculation of the reciprocal value\n"; cout << "2 - Calculation of the second power\n"; cout << "3 - Calculation of the third power\n"; int k; cout << "Enter the answer\n"; cin >> k; switch (k) { case 1: cout << 1 / x << endl; break; case 2: cout << x * x << endl; break; case 3: cout << x * x * x << endl; break; default: cout << "Wrong choice!" << endl; break; }
Output of menu items and input of the user's answer can be put into a loop. Cycles will be discussed below.
Labels can be grouped if several values cause the same actions. For example, the user enters the number of the month (from 1 to 12 inclusive) and the program displays the name of the season:
int month; cout << "Enter month: (1..12): "; cin >> month; switch (month) { case 12: case 1: case 2: cout << "Winter\n"; break; case 3: case 4: case 5: cout << "Spring\n"; break; case 6: case 7: case 8: cout << "Summer\n"; break; case 9: case 10: case 11: cout << "Autumn\n"; break; default: cout << "Wrong season!\n"; }
Missing break
statement is one of the most common mistakes in using switch
.
Therefore, in some languages (for example, C#) its use of break
is mandatory
and its absence leads to a compilation error.
2.4 Iteration Statements
2.4.1 Overveiw
Cyclic constructions (loops) are very often used in programs. It is very difficult to find a real program that has been created without using explicit loops. But even in the implementation of algorithms without explicit cycles, cyclic structures are implicitly present, since it is not possible to implement data input and output at the standard level without cycles.
Loops are used for calculating sums and products, traversing all elements of arrays or other data structures, implementing iterative calculation algorithms, getting events from various devices with processing of these events, reading data from a file (until the end of the file), working with strings, etc.
Loops in programming languages are usually built from a header (checking a condition, defining a range, preparing or modifying a parameter, etc.) and a body (statements that can be executed multiple times, depending on conditions).
Looping statements are presented in four versions:
- a loop with a precondition: before each step of the loop, a certain condition is checked, if the result is true, the actions defined in the body of the loop are performed;
- a loop with a postcondition: first, the actions defined in the body of the loop are performed, then the condition is checked, and depending on the result of the check, the actions are repeated or the loop is terminated;
- a loop with a parameter: a special variable is initialized, a cycle parameter, the condition for performing actions in the body of the cycle is checked and the value of the parameter is modified;
- a loop built on a range: a range is defined and work is carried out with elements of arrays or other data structures.
A loop built on a range associated with arrays and other collections of items will be covered later.
Syntactically, in all loop forms, the body is a single statement. If several statements must be executed in the body, a compound statement (block) is used. Good coding practice requires the use of a block in all cases.
2.4.2 Loop with a Precondition and Postcondition
The loop with the precondition is built according to the scheme:
while (condition) statement
A while
loop causes your program to repeat a statement as long as the starting condition remains true
.
The following examples demonstrate usage of loop with a precondition for calculating the simple sum:
The code will be as follows:
int y = 0; int i = 1; while (i <= n) { y += i * i; i++; }
It is very important to change the value of i
in the body of the loop, otherwise you can get an endless
loop. Also, it would be a mistake to place a semicolon after the header: we will get an endless loop, at each
step of which a null statement is executed:
int y = 0; int i = 1; while (i <= n); // endless loop { // This is no longer the loop body y += i * i; i++; }
2.4.3 Loop with a Postcondition
The loop with the postcondition is built according to the scheme:
do statement while (condition);
The statement is executed, and then condition is evaluated. If condition is true
, the loop
is repeated; otherwise, the loop ends. The do...while
loop executes the body of the loop before
its condition is tested and ensures that the body always executes at least one time. A disadvantage of a postconditional
loop is the ability to execute the body of the loop even when the condition was not met immediately. Sometimes it
is dangerous.
A previous sum
can be calculated using a do ... while
loop:
int y = 0; int i = 1; do { y += i * i; i++; } while (i <= n);
The disadvantages of the loop with the postcondition present even in this example: if, for example, n
is
zero, the result must be 0, but the loop with the postcondition produces the result 1.
Sometimes a loop with a postcondition is used in data input, requiring the user to enter correct data. Example:
double x; do { cout << "Enter a positive value\n"; cin >> x; if (x <= 0) { cout << "Error!\n"; } } while (x <= 0);
The use of such constructions is not always correct and can be applied only if it is determined by the task.
2.4.4 Loop with the parameter
The for
statement (loop with the parameter) is built according to the scheme:
for (expression1; expression2; expression3) statement
The for
loop implements the following algorithm:
- The
expression1
specifies the initialization for the loop. There is no restriction on the type ofexpression1
. - The
expression2
is evaluated before each iteration. If it is equal to zero, the transition to the next statement of the program, located after the body of the loop. - If
expression2
istrue
(nonzero), looping body (statement
) is executed - The
expression3
is evaluated. This expression is evaluated after each iteration. The process then begins again with the evaluation ofexpression2
.
The for
loop is the most compact and reliable for calculating sums and products with
a fixed number of steps.
The previous examples of calculating the sum:
can be implemented using a for
loop:
int y = 0; for (int i = 1; i <= n; i++) { y += i * i; }
In this example, the variable i (the loop parameter) is created in the loop header. The scope of this variable is limited to the header and body of the loop, and the lifetime is limited to the execution time of the loop steps. This approach is recommended because there is no possibility of using a previously created variable and losing its previous value. In all cases, a new variable is created, even if a variable with the same name was previously created. After the loop ends, the parameter created in the header cannot be used.
Sometimes it is necessary to use the value of the parameter after the end of the loop. Then the parameter must be defined before the cycle. Example:
int y = 0; int i; for (i = 1; i <= n; i++) { y += i * i; } cout << i; // the last value of i which is n + 1
Unlike loops with a precondition and a postcondition, it is more difficult to accidentally get an endless loop, because the initial value of the parameter is explicitly specified and its change is assumed at each step.
The statement
for ( ; ; );
is the way to produce an infinite loop. It is unlikely that such a code occurred by mistake. But sometimes the error will be an incorrectly defined range of the parameter. Such a cycle will not be endless, because sooner or later the value of the parameter will reach a minimum negative value and become positive:
int i; for (i = 1; i <= n; i--) { y += i * i; } cout << i; // 2147483647 - maximum integer value
In the header of the loop, the Visual Studio compiler will show an "Ill-defined for-loop" warning.
You should also not put a semicolon after the for loop header:
int y = 0; int i; for (i = 1; i <= n; i++); // error! { y += i * i; }
The loop will not be endless, but the code that was intended as the body of the loop will be executed once for
i
with the value of n + 1
.
In general, the for
loop is more reliable and effective than loops with a precondition
and a postcondition.
2.5 Transition Statements
In loops, break
terminates execution of the nearest enclosing loop statement. Control passes
to the statement that follows the terminated statement. A continue
statement forces transfer
of control to the controlling expression of the loop. Any remaining statements in the current iteration are not
executed. Most often break
and continue
are used in the following constructions:
if (condition_of_early_end_of_loop) break; if (condition_of_early_end_of_iteration) continue;
The goto
statement allows you to go to the label. A label is an identifier with a
colon in front of the statement. Using goto
and labels, you can code without blocks and cycles. For example, the
previous sum can be calculated as follows:
int y = 0; int i = 1; label1: if (i > n) goto label2; y += i * i; i++; goto label1; label2: cout << y;
In this example label1
and label2
are labels.
Such code resembles the style of the FORTRAN language. A program built on such structures is difficult to read and even more difficult to debug. This style is not used in modern programs.
The only case where the use of goto
is reasonable
is the interruption of several nested loops. For example:
int a; . . . double b = 0; for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { if (i + j + a == 0) { goto label; } b += 1 / (i + j + a); } } label: // other statements
3 Sample Programs
3.1 Character Codes
The character output program shown in the previous lab examples can be modified so that the user types characters
in a loop. The loop is finished after entering A
:
#include <iostream> using namespace std; int main() { char c; do { cin >> c; // Inputs character int i = c; // Converts char to int cout << i << '\n'; // Outputs code } while (c != 'A'); // until c == 'A' return 0; }
The do-while
statement executes a statement repeatedly until the specified termination condition
(the expression) evaluates to false
.
3.2 Nested if Statements
It is necessary write a program that reads x
and calculates y
:
x | y |
---|---|
less than -8 | 100 |
from -8 to 1 | 200 |
greater than 1 | 300 |
The program will be as follows:
#include <iostream> using namespace std; int main() { double x; cin >> x; double y; if (x < -8) { y = 100; } else { if (x <= 1) { y = 200; } else { y = 300; } } cout << y; return 0; }
3.3 Linear Equation
The condition statement can be used for solving a linear equation:
In Example 3.1 of the first laboratory training, a branching algorithm that solves this task was given. A program that implements this algorithm can be as follows:
#include <iostream> using namespace std; int main() { double a, b; cout << "Enter a and b: "; cin >> a >> b; if (a != 0) { double x = -b / a; cout << "Root is " << x << endl; } else { if (b == 0) { cout << "Infinite count of roots." << endl; } else { cout << "No roots." << endl; } } }
3.4 The switch Statement
It is necessary write a program that reads x
and n
and calculates y
using
a switch
statement:
n | y |
---|---|
1 | x |
2 | x2 |
3 | x3 |
4 | 1 / x |
other values | 0 |
#include <iostream> using namespace std; int main() { double x, y; int n; cin >> x >> n; switch (n) { case 1: y = x; break; case 2: y = x * x; break; case 3: y = x * x * x; break; case 4: y = 1 / x; break; default: y = 0; } cout << y; return 0 }
3.5 The Sum
It is necessary to write a program that reads x
and n
and calculates y
:
The program must write error message if denominator equals zero.
#include <iostream> using namespace std; int main() { double x, y = 0; int i, n; cout << "Input x and n: "; cin >> x >> n; for (i = 1; i <= n; i++) { if (x == i) { cout << "Error!\n"; break; } y += 1/(x - i); } if (i > n) // Sum is calculated cout << "y = " << y << "\n"; return 0; }
Alternative solution:
#include <iostream> using namespace std; int main() { double x, y = 0; int i, n; cout << "Input x and n: "; cin >> x >> n; for (i = 1; i <= n; i++) { if (x == i) { cout << "Error!\n"; return 1; } y += 1/(x - i); } cout << "y = " << y << "\n"; return 0; }
3.6 The Product
It is necessary write a program that reads x
, k
, and n
and
calculates y
:
#include <iostream> using namespace std; int main() { double x, y = 1; int i, k, n; cout << "Input x, k, and n: "; cin >> x >> k >> n; for (i = 0; i <= n; i++) { if (i == k) { continue; } y *= (x + i); } cout << "y = " << y << "\n"; return 0; }
Alternative solution:
#include <iostream> using namespace std; int main() { double x, y = 1; int i, k, n; cout << "Input x, k, and n: "; cin >> x >> k >> n; for (i = 0; i <= n; i++) { if (i != k) { y *= (x + i); } } cout << "y = " << y << "\n"; return 0; }
3.7 A Product with Alternating Signs
In Example 3.3 of the first laboratory training, the algorithm for calculating a product with alternating signs in multiplicands is given:
A program that implements this algorithm can be as follows:
#include <iostream> using namespace std; int main() { double x; int n; cout << "Enter x, n: "; cin >> x >> n; int k = 1; double p = 1; for (int i = 0; i <= n; i++) { p *= x + i * k; k = -k; } cout << "Product = " << p; return 0; }
3.8 The Exponent
Assume that we want to write a program that reads x
and calculates ex:
The loop terminates if new summand is less than 0.00001.
#include<iostream> using namespace std; int main() { double x, y = 0; double z = 1; // Summand int i = 1; cout << "Input x: "; cin >> x; while (z > 0.00001) { y += z; z *= x / i; i++; } cout << "y = " << y << "\n"; return 0; }
Alternative solution:
#include <iostream> using namespace std; int main() { double x, y = 0; double z = 1; // Summand cout << "Input x: "; cin >> x; for (int i = 1; z > 0.00001; i++) { y += z; z *= x / i; } cout << "y = " << y << "\n"; return 0; }
As can be seen from the example, the condition check in the for loop is not necessarily related to the parameter.
3.9 Nested Loops
In Example 3.4 of the first laboratory training, the algorithm for calculating the sum of products is given:
We'll implement calculations using nested loops. A program can be as follows:
#include <iostream> using namespace std; int main() { int n; cout << "Enter n: "; cin >> n; int sum = 0; for (int i = 1; i < n; i++) { int p = 1; for (int j = 1; j < n; j++) { p *= i + j * j; } sum += p; } cout << "Sum = " << sum; }
3.10 Table of Square Roots
The following program reads interval boundaries and step of argument increasing from keyboard and prints
in a cycle values of square roots of intermediate values.
To calculate the square root, we can use the standard sqrt()
function, which is declared in the cmath
header file.
#include <iostream> #include <cmath> using namespace std; int main() { double from, to, step; cout << "Enter the left border, right border, and step of argument: "; cin >> from >> to >> step; if (from < 0 || to < 0 || from >= to || step <= 0) { cout << "Wrong data\n"; } else { // The main program loop: for (double x = from; x <= to; x += step) { cout << "x = " << x << "\t y = " << sqrt(x) << endl; } } return 0; }
The table of x and y values should be shown after launching program.
4 Exercises
Task 1
Write a program that reads characters and prints their hexadecimal code. Read and output data in a loop.
Task 2
Write a program that reads decimal integers and prints characters with corresponding codes. Read and output data in a loop.
Task 3
Write a program that reads x
and calculates y
(signum function) using an if
statement:
x | y |
---|---|
less than 0 | -1 |
0 | 0 |
greater than 0 | 1 |
Task 4
Write a program that reads integer n
and calculates y
using a switch
statement:
n | y |
---|---|
0 | 2 |
1 | 4 |
2 | 5 |
3 | 3 |
4 | 1 |
other values | 0 |
5 Quiz
- What is a statement?
- Where and why is an empty expression used?
- What is an expression statement?
- What is a compound statement (block) used for?
- Describe the syntax of the the
if
statement. - What errors can be associated with the use of a conditional statement?
- Describe the syntax of the
switch
statement. - How to use
break
statement withinswitch
statement? - What is the
default
statement? - What is loop header and loop body?
- What is the difference between a loop with a precondition and a loop with a postcondition?
- What is the main disadvantage of the loop with a postcondition?
- What are advantages of the
for
statement? - What is the difference between
break
andcontinue
statements? - How to leave multiple nested loops?
- When is it appropriate use of the
goto
statement?