Laboratory Training 2

Data Types and Operators

1 Training Tasks

Operations and expression statements should be used to complete all tasks. Do not use if, switch and goto statements, as well as loops.

1.1 Symbol with a Defined Code

Enter an integer number (from 33 to 255) and display a character with its code.

Examples of source data and results:

Source Data Output
37 % 37
48 0 48
58 : 58
70 F 70
230 ц 230

1.2 Checking Whether the Number Belongs to the Defined Ranges

Enter the x value of type double. Output 1 if 0 ≤ x ≤ 2 or 7 < x < 11. Output 0 otherwise. Implement single-statement calculations with assignment, conditional operation, logical operations, and comparison operations.

Examples of source data and results:

Source Data Output
-1 0
0 1
0.5 1
2 1
6 0
7 0
9 1
10 1
11 0

1.3 Swapping the Bits of an Integer

Develop a program in which the user enters from the keyboard an integer k > 0, as well as non-negative integer values m < 32 and n < 32. Exchange the values of bits with the numbers m and n in the binary representation. Count bits from zero starting from the right. Print the received number.

Examples of source data and results:

Source Data Output
k = 12
m = 1 n = 3
6
k = 12
m = 2 n = 0
9
k = 12
m = 2 n = 3
12
k = 12
m = 0 n = 10
12
k = 1295
m = 0 n = 6
1358
k = 1295
m = 1 n = 8
1295
k = 1295
m = 10 n = 4
287
k = 1295
m = 0 n = 10
1295

1.4 Power of 8

Read integer value of n (from 0 to 10) and display value of 8n. Implement approaches based on bitwise operations.

Examples of source data and results:

Source Data Output
0 1
2 64
6 262144
10 1073741824

1.5 Calculating Sum

Write a program that reads positive integer k and calculates y:

y = 1/k + 1/k2 + 1/k3

Examples of source data and results:

Source Data Output
1 3
2 0.875
3 0.481481

1.6 Individual Task

Develop a program in which the user enters the value of the argument x, and then the calculation of y is carried out according to the formulas given in the table.

Specific formulas are determined according to the number in the list of students in groups.

Student number on the list of group y Range Student number on the list of group y Range
1, 17
x + x2 x < 0
9, 25
xx2 x < 0
1/xx 0 ≤ x ≤ 1 x/(x + 1) 0 ≤ x ≤ 1
(x – 1)2 x > 1 1 + 1/x + 1/x2 x > 1
2, 18
x/(x + 1) x < 0
10, 26
xx2 x < 0
xx2 0 ≤ x ≤ 2 (x + 1)2 0 ≤ x ≤ 2
1 + 1/x + 1/x3 x > 2 x/(x – 1) x > 2
3, 19
x/(x – 1) x < –1
11, 27
x2x x < –1
x + x3 –1 ≤ x ≤ 0 (x + 4)(x2 - 1) –1 ≤ x ≤ 0
4 + 1/x31/x4 x > 0 1 + 1/x3 + 1/x4 x > 0
4, 20
(x – 4)2 x < 0
12, 28
4 + 1/x31/x4 x < –1
xx2 0 ≤ x ≤ 1 (x + 3)(x2 + 5) –1 ≤ x ≤ 0
1/x1/x3 x > 1 xx3 x > 0
5, 21
(x + 5)2 x < –1
13, 29
1/x + 1/x2 x < 0
(x + 3)2 –1 ≤ x ≤ 0 x3x2 0 ≤ x ≤ 1
1/x + 1/x3 x > 0 1/x1/x3 x > 1
6, 22
1/x + 1/x4 x < 0
14, 30
x2x x < –1
xx3 0 ≤ x ≤ 1 (x + 10)2 –1 ≤ x ≤ 0
(x + 3)(x2 + 4) x > 1 x/(x + 1) x > 0
7, 23
x/(x – 1) x < –1
15, 31
(x + 3)(x2 + 2) x < –1
x + x4 –1 ≤ x ≤ 0 (x + 4)2 –1 ≤ x ≤ 0
(x + 1)2 x > 0 x/(x – 1) x > 0
8, 24
4 + 1/x41/x2 x < 0
16, 32
(x + 1)2 x < 0
(x + 4)(x2 - 1) 0 ≤ x ≤ 1 (x + 4)(x2 + 5) 0 ≤ x ≤ 1
x + x3 x > 1 4 + 1/x31/x4 x > 1

Use nested conditional operations to calculate values of y. Do not use if statements. Do not use standard mathematical functions (e.g. pow()).

To test the program, prepare several argument values and calculate the values manually. Compare the values obtained by the program with those calculated manually.

2 Instructions

2.1 Main Features of C++ Programming Language

2.1.1 History of C++

The C++ programming language was invented in 1983 by Danish researcher Bjarne Stroustrup.

The base for C++ was C language – a multipurpose, concise and relatively low-level programming language. C is retained as a subset. The main features of C++ compared to C are as follows:

  • strict typing;
  • support for object-oriented programming;
  • support for templates and generic programming;
  • advanced procedural programming capabilities.

C++ combines the ability to represent complex data structures and the ability to write effective low-level programs. New object-oriented languages were later created based on the C++ syntax. First of all, these are Java and C# languages.

In August 1998, the C++ language standard was ratified. The C++ Standard is a document that fully describes the syntax of a language and its possible use. In addition to the basic tools of the C++ programming language, the standard includes the so-called Standard C++ Library. All the latest versions of C++ programming compilers must support the language standard. Some companies offer special packages that test the "standard" implementation of C++. The C++ Standard was updated in 2003, 2011 and 2014. The last update was in 2020.

2.1.2 Steps of Development of a C++ Program

There are several typical steps of program development

  • The source code can be prepared using any text editor.
  • Preprocessing of source code is carried out and the so-called translation unit is created. In most cases, preprocessing is combined with compiling.
  • The translation unit turns into an executable program using a compiler. If compilation is not possible due to compiler errors, a list of these errors is displayed. If there are no syntax errors, the source code is compiled an object module is produced. This is a machine code file that contains links to functions that are missing from this module. This file is often has the .obj extension.
  • unresolved references are processed using the so-called linker, a special subroutine that connects several object modules, as well as adds compiled functions from standard libraries (files with the .lib extension). In addition, functions that are not referenced are removed from the code. The result of the linker's work is an executable file (*.exe) or a library.

During operation, runtime errors may occur, which are reflected in separate dialog boxes, as well as logical errors (the program performs unexpected actions, and you do not get the proper result). Whatever type of bug you find, you must fix it, and that involves editing your source code, recompiling and relinking, and then rerunning the program.

2.2 The Visual Studio Programming Environment

2.2.1 Installing the Program and Creating a New Project

Microsoft Visual Studio is a complete suite of development tools for building applications using Visual Basic .NET, C, C++, F++, C#, as well as support for Web-programming. This all languages use the same integrated development environment (IDE). The integrated development environment allows the programmer to create projects, access help files, edit, and compile the code in place, and to resolve compile and link errors.

You can download the IDE from https://visualstudio.microsoft.com/downloads. Select the Community option and click on the Free download button. The Visual Studio Installer is loaded. By clicking on the Continue you start the installation process. In the window Installer - Visual Studio Community among the various options, select Desktop development with C++ and click Install. On the next page, you can leave everything unchanged.

After you launched the IDE first, a Start Page appears, which in particular contains buttons Open project or solution and Create a new Project. Now you can create a new project.

Note: if a solution has already been created, a new project can be created using the main menu function File | New | Project... or by pressing Ctrl+Shift+N.

A project is the key concept of application development in Visual Studio. A project can be defined as a configuration and a group of files that produce an executable program or DLL (Dynamic link library). The project source files are usually stored in a separate folder. Within the project, you can create multiple configurations. A configuration is an agreed collection of settings related to a specific purpose. Each project contains at least two configurations - a debug configuration and a release configuration.

To create a new project in a wizard,

  • in the Installed pane, select a project type: Empty Project
  • type a project name in the Name box; a default location for the new project is supplied automatically, but you can change the drive and path
  • choose the name of the solution, which for simple projects coincides with the name of the project; for simple projects it is also advisable to select the option Place solution and project in the same directory;
  • Click OK and the empty project opens.

Note: you can also use the Console App template, but then you will need to manually delete unnecessary comments and statements such as output of "Hello World!" string.

To create a new source file,

  • In the Project menu, click Add New Item... (or Add | New Item... in context menu of solution explorer project's item).
  • Select a file type: C++ File. It is recommended to type a file name in the Name box. Otherwise, the name will be set to Source.cpp.
  • Click OK, and the empty file opens in editor pane.

Now you can type and save the source text. You can execute new program by pressing Ctrl-F5 (Start Without Debugging).

2.2.2 Using the Debugger

Debugging tools are used to find and fix logical errors.

Programs allow not only automatic execution, but also step by step program execution. The text of the program should have at least one breakpoint. This can be done by pressing F9, when the cursor is in the correct line. When the program is running in debug mode, breakpoints cause the temporary stop of the program.

Now you can start program in debugging mode (Debug | Start Debugging or F5). Your application starts up and runs until it reaches a breakpoint. You can break execution at any time to examine values, and otherwise examine the state of your program. To continue normal (not stepwise) execution, use F5. If you want to continue stepwise execution, you can use several commands:

  • Debug | Step Into, function key F11: with entering into the body of the subprogram for debugging;
  • Debug | Step Over, function key F10: without entering into the body of the subprogram for debugging.

If you place the mouse pointer on a variable, its value can be seen in a small window. You can also watch and edit values of variables in special subwindows.

The Find Symbol Results window contains three tabs:

  • The Autos tab displays information about variables used in the current statement and the previous statement.
  • The Locals tab displays information about variables that are local to the current function.
  • The Watch 1 tab allows watch and editing of values stored in variables.

If the Locals window contains an array, object, or structure variable, a button appears next to the variable name. By clicking the button, you can expand or contract your view of the variable. The button displays a plus sign (+) when the variable is displayed in contracted form and a minus sign when it is displayed in expanded form.

You can terminate execution using DEBUG | Stop Debugging (Shift-F5). You can also stop the program and start it from the beginning (Debug | Restart or Ctrl-Shift-F5).

2.3 The First C++ Program

Studying programming languages traditionally begins with the creation of the "Hello, World!" program. To create such a program in C++, we need to prepare a new empty project in Visual Studio. Let this project be called Hello. Next, we add an empty Source.cpp file for the source code. In this file we will place our program in the simplest version:

#include <iostream>

void main()
{
    std::cout << "Hello, World!";
}

The first line of code is a preprocessor directive, which specifies the inclusion of standard iostream header file. This file contains declarations of the required objects, in particular the std::cout object, which is used to display the result in the console window. ext is the title of the main() function, which is a starting point of the program. Then in parentheses allocated the body of the main() function with one statement. The greeting string is output to the standard output stream.

In order to after the output of the text "Hello, World!" the cursor was moved to a new line, you should change the line in which the output is performed, as follows:

std::cout << "Hello, World!" << std::endl;

Adding a std::endl manipulator to a stream provides a newline. In order not to use the std prefix (namespace name) twice, you can add a namespace directive to the program (after the #include <iostream> preprocessor directive):

using namespace std;

Now the line in which the results are output will be as follows:

cout << "Hello, World!" << endl;

In order for the compiler not to generate a warning "return type of 'main' should be 'int' instead of 'void'" the result type of the main() function must be changed. If you'll use int instead of void, you'll be able to analyze the success of the program at the operating system level. Now our program will look like this:

#include <iostream>

using namespace std;

int main()
{
    cout << "Hello, World!" << endl;
    return 0;
}

After starting program (Debug | Start Without Debugging) the greeting text will appear in a specially created console window.

2.4 Main Elements of the C++ Language

2.4.1 General Program Structure

The program in C++ consists of declarations and definitions of global names: types, constants, variables, and functions. In order to prevent name conflicts, the global scope is divided into namespaces.

In the global scope, you need to define the main() function, which is starting point of your program. All program code (except declarations and definitions) is allocated within functions.

In addition to the C++ text itself, the source code usually also contains preprocessor directives. These directives start with the # character and are processed by a special subprogram, the so-called preprocessor. The minimum required directive is #include. It causes the inclusion text of another file (the so-called header file) into the current file. The header file contains declarations and definitions needed to compile the source code. The header file name is specified in angular parentheses (for standard files) or in quotation marks (for custom files in the current folder). Physically, the text is not copied to the file, but the so-called translation unit is created in memory – the source code processed by the preprocessor.

2.1.2 Identifiers. Keywords. Comments

Unlike Pascal and BASIC, C++ is case-sensitive.

Java source code consists of tokens. Token is a sequence of characters that have some meaning. Separators (space, tab, new line, etc.) are placed between individual tokens.

Tokens are divided into the following groups:

  • keywords (reserved words)
  • identifiers
  • literals (explicit constants)
  • operators.

A keyword is a token that has a single predefined meaning in the program code. A set of keywords is finite. All keywords are reserved. Reserved words cannot be used as identifiers. There are 63 keywords in standard C++. Other 11 words are reserved for alternative representations of operators. Below is a list of keywords:

asm auto bool break case
catch char class const const_cast
continue default delete do double
dynamic_cast else enum explicit export
extern false float for friend
goto if inline int long
mutable namespace new operator private
protected public register reinterpret_cast return
short signed sizeof static static_cast
struct switch template this throw
true try typedef typeid typename
union unsigned using virtual void
volatile wchar_t while    

Identifiers used for naming variables, functions and other software objects. The first character must be a letter or underscore character ("_"). Numbers also can be used as non-starting characters. Using an underscore at the beginning of the name is not recommended since such names are often used in standard libraries.

It is advisable to use meaningful names that reflect the nature of the object or function. Do not use spaces inside identifiers. Therefore, if you want to create an identifier from several words, you can use one of two approaches:

  • C style: use an underscore ("_") between words instead of a space
  • C++ style: words are written together, starting the second, third and other words with a capital letter (camel notation).

For example, you can create the following variable names:

this_is_my_variable
thisIsMyVariable

The C++ style is recommended.

Use English mnemonics for meaningful names. Names of user defined classes and structures should begin with capital letters, and other names – only with lowercase letters.

Comments are simply text that is ignored by the compiler. The comment is intended to inform the reader (programmer) about the meaning of types, objects and actions in the source code of the program. There are two types of comments in C++ language:

  • The double-slash comment, which will be referred to as a C++-style comment, tells the compiler to ignore everything that follows //, until the end of the line.
  • The slash-star comment mark (/*) tells the compiler to ignore everything that follows until it finds a star-slash (*/) comment mark. These marks will be referred to as C-style comments. Every /* must be matched with a closing */.

As a general rule, the large program should have comments at the beginning, telling you what the program does. Each large function should also have comments explaining what the function does and what values it returns.

In the following example, we add comments to the previously discussed "Hello world" program:

// First program on C++ language
#include <iostream>

using namespace std; // Connection to std namespace

/*
  The function that starts the program execution:
*/
int main()
{
    cout << "Hello, World!" << endl;
    return 0;
}

Two C++-style comments and one C-style comment were added to the program.

2.5 Fundamental Data Types

Fundamental data types in C++ are divided into two categories:

  • integer (whole numbers);
  • floating (real numbers).

The group of integer types includes such types: int, long, long long, short, char, and bool. All integer types, except for bool, come in two varieties: signed and unsigned. Integers without the word unsigned are assumed to be signed. Signed integers are either negative or positive. Unsigned integers are always positive. Character data (char) are considered as small integers.

According to the number of bits used to represent the data (range of values) we can speak about ordinary integers (int), short integers (short int), long integers (long int), and very long integers (long long int).

Floating point variables have values that can be expressed in fractions. In other words, they are real numbers. The inner representation of floating point numbers allows to store fractional values in the form of significand*2exponent. This form provides the ability to store data in a very wide range. The group of floating-point types includes such types: float, double, and long double. The representation of long double and double is identical.

The following table shows size in bytes and range of fundamental types.

Category Type Name Another Name Size in Bytes Range of Values
Integer types int signed int 4 -2 147 483 648 to 2 147 483 647
unsigned unsigned int 4 0 to 4 294 967 295
char signed char 1 -128 to 127
unsigned char   1 0 to 255
short short int, signed short int 2 -32 768 to 32 767
unsigned short unsigned short int 2 0 to 65 535
long long int, signed long int 4 same as int
unsigned long unsigned long int 4 same as unsigned int
long long long long int, signed long long int 8 -9 223 372 036 854 775 807 to 9 223 372 036 854 775 808
unsigned long long unsigned long long int 8 0 to 18 446 744 073 709 551 615
bool   1 false or true (0 or 1)
Floating point types float   4 3.4E +/- 38 (7 digits)
double   8 1.7E +/- 308 (15 digits)
long double   8 same as double

A char variable is commonly used to hold codes of characters. These small integer values can be represented as characters. A character is a single letter, number, or another symbol. Character variables hold a single byte and are used for holding the 256 characters and symbols of the ASCII and extended ASCII character sets. ASCII stands for the American Standard Code for Information Interchange.

A variable of type bool can have values true and false. You can use one and zero instead of true and false.

A special sizeof operator with the name of the type as operand (the name must be enclosed in parentheses) allows you to get the size in bytes of the cell, which is necessary for the location of the variable of the corresponding type in memory. In the following program, we obtain the number of bytes of memory to store data of some standard types:

#include <iostream>

using namespace std;

int main()
{
    cout << "int: " << sizeof(int) << " bytes" << endl;
    cout << "short int: " << sizeof(short int) << " bytes" << endl;
    cout << "long int: " << sizeof(long int) << " bytes" << endl;
    cout << "long long int: " << sizeof(long long int) << " bytes" << endl;
    cout << "char: " << sizeof(char) << " byte" << endl;
    cout << "bool: " << sizeof(bool) << " byte" << endl;
    cout << "float: " << sizeof(float) << " bytes" << endl;
    cout << "double: " << sizeof(double) << " bytes" << endl;
    return 0;
}

2.6 Constant Values

Constants are tokens representing fixed numeric or character values, as well as a string of characters.

Integer constants are written as sequences of numbers. The type of the constant is int by default and can be specified by adding the letters L either l (long) U or u (unsigned) or in combination to the end of the constant.

Integer constants can be written in the octal number system, in this case the first digit must be zero, the number can contain only digits 0...7.

Integer constants can also be written in the hexadecimal number system. In this case, the constant starts with the symbols 0x or 0X. Latin letters a, b, c, d, e and f (uppercase or lowercase) are used to indicate numbers over 9. For example, 0XABC0 (43968 in decimal notation).

Recent versions of C++ also allow you to define binary constants that begin with 0b or 0B, for example 0B11011 (27 in decimal notation).

The values of constants in different notations are displayed in the decimal system by default. In the following program, constant values defined in different ways are displayed on the screen:

#include <iostream>

using namespace std;

int main()
{
    cout << 11 << endl;   // 11
    cout << 011 << endl;  // 9
    cout << 0x11 << endl; // 17
    cout << 0b11 << endl; // 3
    return 0;
} 

A character constant is formed by enclosing a single character from the character set within single quotation marks (' ').

Character combinations consisting of a backslash (\) followed by a letter or by a combination of digits are called "escape sequences". To represent a new line character, single quotation mark, or certain other characters in a character constant, you must use escape sequences. An escape sequence is regarded as a single character and is therefore valid as a character constant.

Escape sequences are typically used to specify actions such as carriage returns and tab movements on terminals and printers. They are also used to provide literal representations of nonprinting characters and characters that usually have special meanings, such as the double quotation mark ("). The following table lists the ANSI escape sequences and what they represent.

Escape Sequence Represents
  \a Bell (alert)
  \b Backspace
  \f Form feed
  \n New line
  \r Carriage return
  \t Horizontal tab
  \v Vertical tab
  \' Single quotation mark
  \" Double quotation mark
  \\ Backslash
  \? Literal question mark
  \ooo ASCII character in octal notation
  \xhh ASCII character in hexadecimal notation

Constants of real types can be written in floating-point form or in exponential notation and have the default type double (double-precision floating-point number). If necessary, the type of constant can be specified by writing the suffix f or F for the type float, the suffix l or L for the type long double. You can also explicitly use the suffixes l and L for long double. For example:

1.5f    // 1.5 of type float
2.5E-2L // 0.25 of type long double

Regardless of the definition of the constant in the code, its representation on the screen will be optimal in terms of length and human perception. For example:

cout << 1.5 << endl;        // 1.5
cout << 1.5E3 << endl;      // 1500
cout << 15000000.0 << endl; // 1.5e+07

Negative floating constants are taken as positive constants with the unary operator minus (-) prefixed.

A string literal is a sequence of characters from the source character set enclosed in double quotation marks (" "). For example:

"This is the string"

The string constant may include control sequences. For example, this is how you can display the text "Hello, World!" in quotes:

cout << "\"Hello, World!\"" << endl;

If there is nothing between the two constants except spaces and newline transitions, the compiler combines them into one. The string constant is represented by an array of characters containing, in addition to string characters, a final character with the code 0 ('\0'). Such strings are called null-terminated strings.

2.7 Defining Variables and Symbolic Constants

A variable is the named memory area that the program has access to. Each variable has a specific type. The variable is associated with its value, which is stored in a certain memory location (rvalue, right value, in the assignment is on the right), and its location, i.e. the address in memory, which stores its value (lvalue, left value).

The variable can be declared and must be defined. The syntax for declaring variables will be discussed below in the context of creating header files.

The definition of variable causes memory allocation. It starts with stating its type. The name of variable must be separated from type name by one or more space characters. The definition ends with a semicolon:

type_name variable_name;

It is advisable to use meaningful variable names. Variables with short names should have restricted scope.

If it is necessary to define several variables of the same type, their identifiers are written separated by commas:

int x, y; // Two integer variables with undefined values

Declarations and definitions are collectively called descriptions. It should be noted that when there is no type name in the descriptions but there are other modifiers (long, short, signed, and unsigned), it is assumed that the variable has type int. For example,

short s;    // short integer
unsigned s; // unsigned integer

You assign a value to a variable by using the assignment operator (=). You would assign 5 to width by writing

unsigned short width;
width = 5;

You can combine definition with initialization:

unsigned short width = 5;

The initialization looks very much like assignment. The essential difference is that initialization takes place at the moment you create the variable.

You can also initialize a variable with a constant in parentheses:

int a = 10; // An integer variable with an initial value of 10
int b(10);  // The same

Variables can be initialized with the values of other variables, as well as expressions of arbitrary complexity. The following program creates and initializes variables and then finds their arithmetic mean:

#include <iostream>

using namespace std;

int main()
{
    double a = 2 * 2;
    double b = a + 1;
    double c = a - 2;
    double y = (a + b + c) / 3;
    cout << y << endl;  // 3.66667
    return 0;
} 

Note: an asterisk (*) is a multiplication sign; dash (/) is used for division.

Modern versions of C++ do not allow the use of variable values in expressions unless they have been initialized or the value has not been previously obtained in some other way:

int m;
int n = m; // Error

You can initialize more than one variable at creation. For example:

long width = 5, length = 7; 

You can even mix definitions and initializations:

int myAge = 39, yourAge, hisAge = 40;

This example creates three type int variables, and it initializes the first and third.

A variable cannot be used until it is defined. There must be one and only one definition of a variable in the program:

int n = m; // Error, there is no variable m yet
int m = 1;
double m = 0.5; // Error, variable m already exists

In C++, we can assign integer values to floating-point variables and vise versa. Example:

double x = 10; 
int n = 10.5;  // get integer part, n = 10

A symbolic constant is a constant that is represented by a name. Unlike a variable, however, after a constant is initialized, its value can't be changed. There are examples of defining constants:

const int yearOfBirth = 1901;

Here yearOfBirth is a constant of type int. Its value can't be changed.

In the 2011 version of C++ (C++ 11), an automatic type inference mechanism was added to the language syntax, which allows the compiler to create local variables, which types depend on the context. To create these variables the auto is used. These variables must be initialized. The variable type determines by compiler according to the type of expression that is used for the initialization. Example:

auto i = 10;   // integer variable
auto x = 10.5; // variable of type double

Despite the fact that the type is not specified explicitly, the compiler creates a variable of the certain type. Once a variable is created, you cannot change its type.This approach only makes sense for complex types. This and other features of new versions of C++ will be discussed later.

2.8 Operators and Expressions

2.8.1 Expressions, Operators and Operands

An expression is a language construct that consists of one or more operations and can result in a specific result during program execution.

Operation is an atomic (indivisible) expression. The objects of operations are called operands.

An operator is a character (or several characters) that determines the action on the operands. Depending on the number of operands, there are unary operators (one operand), binary operators (two operands) and ternary operators (three operands).

Good coding practice requires spaces to be placed between the first operand, the operator, and the second operand. A unary operation is not separated from an operand by space character.

2.8.2 Assignment

The assignment operator (=) causes the operand on the left side to have its value changed to the value on the right side. The expression

x = a + b;

assigns the value that is the result of adding a and b to the operand x.

The assignment expression returns a value. After the assignment, an assignment expression has the value of the left operand. This value can be used by another assignment expression. For example

a = (b = (c = (d = 0))); // We assign 0 to all variables

In this example we don't need parentheses, because the assignment operator is right-associative:

a = b = c = d = 0; 

2.8.3 Mathematical Operators

There are five mathematical operators: addition (+), subtraction (-), multiplication (*), division (/), and modulus (%). In addition, the unary operations + and - can be used before numbers.

Mathematical operations (except the remainder from division) can be applied to both integer and floating-point operands. If one of the operands has a floating-point type, the value of the other operand is also converted to this type and the floating-point operation is performed. If both operands are of integer type, the operation is performed on integers. The execution time of operations for integer operands is usually much less than for floating-point operands.

Mathematical operations can be used in expressions to initialize new variables. Previously calculated values can be used in expression:

double x = 2.4 / 2; // 1.2
double y = x + 10;  // 11.2

In programming code, mathematical operations are most often used to change the value of variables that were previously created or in more complex expressions.

There are two ways of division: floating point division and integer division. The first is everyday division. It works as you would expect:

double a = 10;
double b = 4;
double c = a / b; // c = 2.5

The division operation on two integers gives an integer part of quotient:

int a = 10;
int b = 4;
int c = a / b;    // c = 2
double d = a / b; // d = 2.0

Note. The result depends on types of operands. Compiler ignores type of variable that obtains the result.

A common mistake with integer division is trying to get a half, a third, etc. like this:

double x = 1 / 2;
double y = 1 / 3;

Both variables will be zero because an integer division is performed. You can write, for example, like this:

double x = 1.0 / 2;
double y = 1.0 / 3;

Since at least one operand is a floating-point constant, floating-point division will be performed.

The modulus operator returns the remainder after an integer division:

int a = 10;
int b = 3;
int c = a % b;    // c = 1

The both of operands must be integer.

The operation of obtaining the remainder from division is very often used to check whether a certain integer is even (or odd). If the result of finding the remainder from dividing an integer n

n % 2

is zero, it means that the number n is even.

In C++, there is no operation for calculating powers of a number, in particular, the second power. There is a function pow() for calculating exponents, but using it to calculate the second power is inefficient. It is advisable to apply the multiplication of the value to itself. It is also advisable to calculate the third and fourth power.

Operations are often combined into expressions, similar to mathematical expressions. Each operator has its own priority. Multiplication has a higher priority than addition. You can use parentheses to change the order of operations.

For example, the result of calculating the expression will be 16:

double y = 1 + 3 * 5; // 16

However, if you add parentheses,

y = (1 + 3) * 5; // 20

the result will be different.

Long expressions can be spread over multiple lines of code by adding a newline as a delimiter instead of a blank. But you never should repeat operator on a new line, as is used in mathematics.

2.8.4 Self-Assignment Operators

The self-assignment operation can be represented as follows:

a op= b 

In our case op is an arithmetic or bitwise operator: + - * / % | & ^ << >>. Each self-assignment operation is equivalent to the following assignment:

a = (a) op (b);

For example,

x += 5;

equivalent to the expression

x = x + 5;

The self-assignment operation also returns a result: a new value for the variable. For example:

x = 2;
y = (x += 5); // x = 7, y = 7

2.8.5 Incrementing and Decrementing

Very often the value of an integer variable needs to be increased or decreased by one. Increment and decrement operators can be used instead of self-assignment:

k = 1;
// Increment:
++k; // now k = 2, equivalent to k += 1
// Decrement:
--k; // now again k = 1, equivalent to k -= 1

The increment and decrement operations have two forms: prefix and postfix. Prefix form provides an increase or decrease value of variable before this value will be used in expression, and postfix form modifies the value after its usage. For example:

k = 1;
// Prefix form:
n = ++k; // k = 2, n = 2
k = 1;
// Postfix form:
n = k++; // k = 2, n = 1

A similar example can be given for decrement.

Increment and decrement operations can be the cause of errors associated with a misunderstanding of the sequence of actions. For example, the prefix operation gives the expected result:

int i = 1;
i = ++i + ++i; // i = 6

The result of the postfix operation is not as expected:

int i = 1;
i = i++ + i++; // i = 4 or 3 depending on the compiler

It is advisable to avoid such structures.

2.8.6 Relational Operators

The relational operators determine equality and relative values of their operands. Every relational expression evaluates to either 1 (true) or 0 (false). The table below shows relational operators:

Name Operator Sample Evaluates
Equals == 100 == 50; false
50 == 50; true
Not Equals   != 100 != 50; true
50 != 50; false
Greater Than > 100 > 50; true
50 > 50; false
Greater Than or Equals >= 100 >= 50; true
50 >= 50; true
Less Than < 100 < 50; false
50 < 50; false
Less Than or Equals <= 100 <= 50; false
50 <= 50; true

Don't confuse the assignment operator (=) with the equals relational operator (==). This is one of the most common C++ programming mistakes.

Instead of values false and true, the result can be interpreted as an integer (0 or 1). In C++, any value that is not equal to zero is interpreted as true. Only the value 0 (of any type) is interpreted as false. Therefore, in the code where you need to check the variable a for a non-zero value, you can simply write a instead of a != 0.

Relational operations can be combined with arithmetic ones:

int a = 1;
int b = 2;
int c = (a < b) + 2 * (b == 2); // c = 3

Note: arithmetic operations have a higher priority than comparison operations, so parentheses are required here.

This style of programming results in code that is not easy to read. In addition, languages that use C++ syntax as their base, such as C# and Java, do not have this capability.

2.8.7 Logical Operators

The logical operators are used to combine multiple conditions. The table below shows logical operators:

Operation Operator Example
AND && expression1 && expression2
OR || expression1 || expression2
NOT ! !expression

A logical AND statement evaluates two expressions, and if both expressions are true, the logical AND statement is true as well. Otherwise, it evaluates false. A logical OR statement evaluates two expressions, and if both expressions are false, the logical OR statement is false. Otherwise, it evaluates true. A logical NOT statement evaluates true if the expression being tested is false. This statement evaluates false if the expression being tested is true.

Note: the logical AND is two && symbols and the logical OR is two || symbols. A single & and | symbols are so-called bitwise operators, which will be discussed below.

If we apply the "NOT" operator to a non-zero integer value, we will get 0, if we apply it to zero, we get one. For example, !7 equal to zero, !!7 equal to one.

Relational operations and logical operations are often combined to produce a more complex result. Example:

int a = 1;
int b = 2;
bool c = a < b &&  b == 2; // c = true

Relational operators and logical operators have a precedence order. Relational operators have higher precedence than logical operators. It is often a good idea to use extra parentheses to clarify what you want to group.

2.8.8 Bitwise Operators

C++ provides bitwise operators that act upon the individual bits. These look like, but are different from, the logical operators. The operands must be integer (preferably unsigned integer). For example

unsigned char c1 = 168;     // 10101000
unsigned char c2 =  26;     // 00011010

The AND operator (&) is a single ampersand, as opposed to the logical AND, which is two ampersands. When you apply AND to two bits, the result is 1 if both bits are 1, but 0 if either or both bits are 0:

unsigned char c3 = c1 & c2; // 00001000, or 8 

The OR (|) operator is a single vertical bar, as opposed to the logical OR, which is two vertical bars. When you apply OR to two bits, the result is 1 if either bit is set or if both are:

unsigned char c4 = c1 | c2; // 10111010, or 186

The third bitwise operator is exclusive OR (^). When you apply exclusive OR to two bits, the result is 1 if the two bits are different:

unsigned char c5 = c1 ^ c2; // 10110010, or 178

The complement operator (~) clears every bit in a number that is set and sets every bit that is clear. For example:

unsigned char c6 = ~c1;     // 01010111, or 87 

The SHIFT LEFT operator moves the bits to the left. This operation discards the far left bit and assigns 0 to the right most bit. For example:

unsigned char c7 = c1 << 1;  // 01010000, or 80

The SHIFT RIGHT operator moves the bits to the right. This operation discards the far right bit and assigns 0 to the left most bit. For example:

unsigned char c8 = c1 >> 2; // 00101010, or 42

You can use self assigned &=, |=, ^=, <<= and >>=.

Bitwise operations can be used for fast integer multiplication or integer division by numbers that ar powers of 2:

int k = 6;
int m = k << 3; // m = k * 8 = 48
m >>= 2;        // m = m / 4 = 12

Such operations are performed most quickly.

Working with individual bits is often used to identify and read individual features that may or may not be present. Variables (or individual bits) that contain only 0 or 1 are called flags in programming. Setting individual bits within a single integer is used instead of working with different variables for greater automation, less memory usage, and efficiency. Suppose there is an unsigned integer state whose individual bits determine individual characteristics (state elements). Bitwise operations can be used to set or check individual bits:

unsigned char state = 0;
unsigned char flag = 0b00000100; // the one bit we're interested in is set
state |= flag;  // 00000100
bool flagSet = state & flag; // true
state &= ~flag; // 00000000
flagSet = state & flag; // false

Later, we will use this approach to determine the state of a large program

2.8.9 The Comma Operator

The comma operator allows grouping two or more expressions. The value of the expression is the value of the last expression. The comma operator has left-to-right associatively. For example, the expression

x = (i = 0, j = i + 4, k = j); 

equivalent to the expression

i = 0; j = i + 4; k = j; x = k;

The parentheses in this example are obligatory.

2.8.10 Conditional Operator

The conditional operator (?:) is C++'s only ternary operator. It requires three expressions and returns a value:

expression1 ? expression2 : expression3

This line is read as "If expression1 is true, return the value of expression2; otherwise, return the value of expression3." Typically, the result would be assigned to a variable. For example,

min = a < b ? a : b;

This statement assigns minimum value of a and b to variable min.

Syntactically, you can use a conditional operator to implement branching that does not involve assigning different values to the same variable:

a < b ? a = x : b = x;

In such cases, it is more appropriate to use the if statement, which will be considered later.

2.8.11 The sizeof Operator

The sizeof operator returns the size of its operand. Previously, the use of sizeof operator, when the operand is a type name, was considered. In general, it can be an arbitrary expression; the operand can be specified with or without parentheses:

int i;
double d;
cout << sizeof i << endl;       // 4
cout << sizeof d << endl;       // 8
cout << sizeof (d + i) << endl; // 8, result of type double

The expression is not evaluated.

2.8.12 Type Cast Operator

Sometimes we need to convert value of expression into a given type. In some cases this can be done implicitly. Integer value can be converted to double or float and vise versa:

double x = 2.8;
int k = x;    // 2
double y = k; // 2.0

But sometimes there is a reason to do this explicitly. There are three syntax forms of such conversion:

int k = (int)x;
int m = int(x);
int n = static_cast<int>(x);

The result will be the same. The most popular is the first form. It presents not only in C++, but also in C, C#, and Java.

The benefit of such explicit conversion appears in different cases. For example, we need to apply floating point division to integer variables:

int a = 10;
int b = 4;
double d = (double)a / b; // d = 2.5

2.8.13 Using Operators for Data Input and Output

There are no separate input and output operators in C++. The standard C library provides the scanf() and printf() functions, which provide console input and output, respectively. The use of these functions will be discussed later.

Instead of the scanf() and printf() functions, which do not provide proper type control, C++ offers a more reliable and convenient way to input and output data. This method is based on the use of I/O streams. C++ provides the ability to override operations for objects of standard and non-standard classes. For the class that represents the input stream, a right shift operation (>>) is defined. The operator reads from the stream individual tokens and converts them into data that correspond to the types of variables – operands, which are located to the left of the stream object. Similarly, a left shift operation (<<) for output is defined for the output stream. The output format is determined by the types of variables. You can also display constants, in particular literals. To move the cursor to a new line, you should put the endl manipulator into the output stream.

In the following example, one integer, one valid value, and one character are read from the standard input stream (from the keyboard). The read values are displayed in a standard console window:

int k;
double x;
char c;
cin >> k >> x >> c;
cout << k << " " << x << " " << c << endl;
// without spaces, the data will be joined together into one token

There are additional means for formatting data. For example, adding setw(n) to the stream causes the assignment of n positions for output the current data.

To work with standard streams, you need to add an iostream header file inclusion to the source code. Tools for working with streams are defined in the std namespace.

2.9 Expression Statement

2.9.1 Overview

In C++, a statement is the simplest unit in a program code. Expressions and operations are parts in the statements. The sequence of statements implements a certain algorithm.

It is possible to offer the following classification of statements:

  • description statements
  • empty statement
  • expression statements
  • compound statement
  • selection statements
  • iteration statements
  • jump statements
  • exception handling statement.

Description statements are the only ones that can be located both inside functions and outside them. Description statements have been considered previously.

2.9.2 Expression Statements

All expressions with semicolon are expression statements. One of the most common statements is the following statement with assignment expression:

a = x + 1;

C++ allows you to create statements from operations that do not contain the assignment:

x + 1;
a;

In most cases, such statements do not make sense, because the result of the operation is not stored anywhere. But this is how functions with the result of type void are called, for example:

system("pause");

Similar statements are also used for data input and output:

cin >> x;
cout << x;

The following program calculates sum of two integer values entered by user:

#include <iostream>

using namespace std;

int main()
{
    int a, b, c;
    cout << "Enter a and b: ";
    cin >> a >> b;
    c = a + b;
    cout << "Sum is " << c << endl;
    return 0;
}

This program can be modified. The creation and calculation of c can be joined together:

    ...
    int a, b;
    cout << "Enter a and b: ";
    cin >> a >> b;
    int c = a + b;
    ...

The program can be more simplified. The creation of c variable has no sense. We can calculate sum immediately before its output. So final version will be as follows:

#include <iostream>

using namespace std;

int main()
{
    int a, b;
    cout << "Enter a and b: ";
    cin >> a >> b;
    cout << "Sum is " << (a + b) << endl;
    return 0;
}

Now compiler does not create extra cell in memory. Unnecessary copying also does not perform.

3 Sample Programs

3.1 Character Codes

This program allows printing codes of given characters:

#include <iostream>

using namespace std;

int main()
{
    char c;
    cin >> c;     // Inputs character 
    int i = c;    // Converts char to int
    cout << i << '\n'; // Outputs code
    return 0;
}

3.2 Hexadecimal Numbers

The following program prints hexadecimal representation of numbers:

#include <iostream>

using namespace std;

int main()
{
    int i;
    cin >> i;   // Inputs integer
    cout << dec << i << ' ' << hex << i << '\n';
    return 0;
}

The state of the stream objects can be changed by using manipulators. You can set the base of the numbers for display by using dec (decimal), oct (octal – base eight), or hex (hexadecimal).

3.3 Integer Part of a Value

It is necessary to write a program that prints integer part of a floating number:

#include <iostream>

using namespace std;

int main()
{
    double d;
    int i;
    cin >> d; // Inputs floating point value
    i = d;    // Converts double to int
    cout << d << ' ' << i << '\n';
    return 0;
}

3.4 Powers of 2

The use of bitwise operations makes it easy to obtain powers of 2. It is enough to shift to the left. In the following program, the exponent is entered and the corresponding power of two is printed:

#include <iostream>

using namespace std;

int main()
{
    unsigned int k;
    cout << "Enter exponent (0 to 31): ";
    cin >> k; // enter the exponent
    unsigned int result = 1 << k; // we get the power of two
    cout << result << '\n';
    return 0;
}

3.5 Bit Copying

Suppose it is necessary to enter an unsigned integer, copy its least bit (which is located on the right) into position 6 (counting from 0 from right to left) and output the value that we got. The program can be as follows:

#include <iostream>

using namespace std;

int main()
{
    unsigned int k;
    cin >> k;
    unsigned int bit = 1 & k; // get the value of the least bit
    bit <<= 6;                // shift by 6 positions
    k &= ~(1 << 6);           // clear the sixth position 
    k |= bit;                 // write the bit in the corresponding position
    cout << k << '\n';
    return 0;
}

If the sixth and zero positions from the beginning coincide, the number will remain unchanged.

3.6 Use of Conditional Operators

It is necessary write a program that reads x and calculates y

x y
less than -8 100
-8 to 1 200
greater than 1 300

We'll use conditional operators

#include <iostream>

using namespace std;

int main()
{
    double x;
    cin >> x;
    double y = x < -8 ? 100 : (x <= 1 ? 200 : 300);
    cout << y;
    return 0;
}

4 Exercises

Task 1

Write a program that reads characters and prints their hexadecimal code.

Task 2

Write a program that reads floating point values and prints rounded values.

Task 3

Write a program that reads x and calculates y (signum function) using conditional operators:

x y
less than 0 -1
0 0
greater than 0 1

5 Quiz

  1. What are steps of development of a C++ program?
  2. What is the difference between compiler and linker?
  3. What is Integrated Development Environment?
  4. What programming languages are supported by Visual Studio?
  5. What is debugging?
  6. How to create a new project in Visual Studio?
  7. How to debug programs in Visual Studio?
  8. What is the difference between C-style comment and C++-style comment?
  9. What is preprocessor?
  10. What is the difference between signed and unsigned integers?
  11. What is a constant?
  12. How to define hexadecimal constant?
  13. What is an escape sequence?
  14. What is a string literal?
  15. What is a variable?
  16. How to define a variable?
  17. What is a symbolic constant?
  18. How to use sizeof operator?
  19. What is an expression?
  20. What is an operator?
  21. What is the difference between both assignment and self-assigned operators?
  22. What is the difference between prefix and postfix increment / decrement operators?
  23. To what type of values evaluates relational expression?
  24. What are logical operators?
  25. What is the "comma" operator?
  26. What is the conditional operator?
  27. What is an expression statement?

 

up