C Material
C Material
C Material
Syllabus:
Chapter 1: Introduction to C++
Intro to C++, the main () function, Header files, Basic Input and Output (I/O) using
cin and cout, Variable, Constant.
Chapter 2: Operators
Operators-Arithmetic Operators, Assignment Operators, Relational Operators,
Logical Operators, Bitwise Operators, Other Operators, Operator Precedence.
Chapter 7: Functions
Function–Basics, call by value, call by reference & return by reference, Inline
function, overloading Functions, Recursive Functions
Chapter 15: Exception and File Handling - Exception, Files, Streams and I/O
Chapter 16: STL and Lambda Functions - STL, Generic Programming, Lambda Expression.
Chapter:1 Intro to C++
Intro to C++
Main () function
Basic Input and Output (I/O) using
cin and cout
Header files
Tokens
Basics of C++
C ++ is an object-oriented programming language, C ++ was developed by Jarney
Stroustrup at AT & T Bell lab, USA in early eighties. C ++ was developed from c and Simula
67 language. C ++ was early called „C with classes.
C++ Comments:
C++ introduces a new comment symbol // (double slash). Comments start with a double
slash symbol and terminate at the end of line. A comment may start anywhere in the line and
whatever follows till the end of line is ignored. Note that there is no closing symbol.
The double slash comment is basically a single line comment. Multi line comments can
be written as follows:
// this is an example of
// c++ program
// thank you
The c comment symbols /* ….*/ are still valid and more suitable for multi-line comments.
/* this is an example of c++ program */
Output Operator:
The statement cout <<” Hello, world” displayed the string with in quotes on the screen.
The identifier cout can be used to display individual characters, strings and even numbers. It is
a predefined object that corresponds to the standard output stream. Stream just refers to a flow
of data and the standard Output stream normally flows to the screen display. The cout object,
whose properties are defined in iostream.h represents that stream. The insertion operator <<
also called the „put to‟ operator directs the information on its right to the object on its left.
Return Statement:
In C++ main () returns an integer type value to the operating system. Therefore, every
main () in C++ should end with a return (0) statement, otherwise a warning or an error might
occur.
Input Operator:
The statement cin>> number 1; is an input statement and causes. The program to wait
for the user to type in a number. The number keyed in is placed in the variable number1. The
identifier cin is a predefined object in C++ that corresponds to the standard input stream. Here
this stream represents the key board.
The operator >> is known as get from operator. It extracts value from the keyboard
and assigns it to the variable on its right.
Structure Of a Program:
Probably the best way to start learning a programming language is by writing a
program. Therefore, here is our first program:
// my first program in C++
#include <iostream>
using namespace std;
int main ()
{
cout << "Hello World!";
return 0;
}
Output:-Hello World!
The first panel shows the source code for our first program. The second one shows the
result of the program once compiled and executed. The way to edit and compile a program
depends on the compiler you are using. Depending on whether it has a Development Interface
or not and on its version. Consult the compilers section and the manual or help included with
your compiler if you have doubts on how to compile a C++ console program.
The previous program is the typical program that programmer apprentices write for the
first time, and its result is the printing on screen of the "Hello World!" sentence. It is one of the
simplest programs that can be written in C++, but it already contains the fundamental
components that every C++ program has. We are going to look line by line at the code we have
just written:
// my first program in C++
This is a comment line. All lines beginning with two slash signs (//) are considered
comments and donot have any effect on the behavior of the program. The programmer can use
them to include short explanations or observations within the source code itself. In this case,
the line is a brief description of what our program is.
#include <iostream>
Lines beginning with a hash sign (#) are directives for the preprocessor. They are not
regular code lines with expressions but indications for the compiler's preprocessor. In this case
the directive #include<iostream> tells the preprocessor to include the iostream standard file.
This specific file (iostream) includes the declarations of the basic standard input-output library
in C++, and it is included because its functionality is going to be used later in the program.
And the result would again have been exactly the same as in the previous examples.
Header files
Preprocessor directives:
Preprocessor directives (those that begin by #) are out of this general rule since they are not
statements. They are lines read and processed by the preprocessor and do not produce any code
by themselves. Preprocessor directives must be specified in their own line and do not have to
end with a semicolon (;).
C++ KEYWORDS:
Asm double new switch
Auto else operator template
Break enum private this
Case extern protected throw
Catch float public try
Char for register typedef
Class friend return union
Const goto short unsigned
Continue if signed virtual
Default inline sizeof void
Delete long struct while
IDENTIFIERS:
Identifiers refers to the name of variable, functions, array, class etc. created by
programmer. Each language has its own rule for naming the identifiers.
Both C and C++ compilers support all the built in types. With the exception of void the
basic datatypes may have several modifiers preceding them to serve the needs of various
situations. The modifiers signed, unsigned, long and short may applied to character and integer
basic data types. However the modifier long may also be applied to double.
SYMBOLIC CONSTANT:
There are two ways of creating symbolic constants in c++.
1. using the qualifier const.
2. defining a set of integer constants using enum keywords.
In both C and C++, any value declared as const can‟t be modified by the program in
any way. In C++, we can use const in a constant expression. Such as
const int size = 10;
char name (size);
This would be illegal in C. const allows us to create typed constants instead of having
to use #defme to create constants that have no type information.
const size=10;
Means
const int size =10;
C++ requires a const to be initialized. ANSI C does not require an initializer, if none is given,
it initializes the const to 0. In C++ const values are local and in ANSI C const values are global.
However, they can be made local made local by declaring them as static. In C++ if we want to
make const value as global then declare as extern storage class.
Ex: external const total=100; Another method
of naming integer constants is as follows: -
enum {x,y,z};
DECLARATION OF VARIABLES:
In ANSIC C all the variable which is to be used in programs must be declared at the
beginning of the program. But in C++ we can declare the variables any who‟s in the program
where it requires. This makes the program much easier to write and reduces the errors that may
be caused by having to scan back and forth. It also makes the program easier to understand
because the variables are declared in the context of their use.
Example:
main()
{
float x,average;float sum=0;
24 P.T.O for(int i=1;i<5;i++)
{
cin>>x; sum=sum+x
}
float average; average=sum/x;
cout<<average;
}
REFERENCE VARIABLES:
C++interfaces a new kind of variable known as the reference variable. A references
variable provides an alias.(alternative name) for a previously defined variable. For example ,if
we make the variable sum a reference to the variable total, then sum and total can be used
interchangeably to represent the variable.
Example:
floattotal=1500;
float &sum=total;
Here sum is the alternative name for variables total, both the variables refer to the same data
object in the memory. A reference variable must be initialized at the time of declaration. Note
that C++ assigns additional meaning to the symbol & here & is not an address operator. The
notation float & means reference to float.
Example:
int n[10];
int &x=n[10];
char &a=‟\n‟;
Chapter:2 Operators
Arithmetic Operators
Assignment Operators
Relational Operators
Logical Operators
Bitwise Operators
Other Operators
Operator Precedence.
Operators in C++
An operator is a symbol that tells the compiler to perform specific mathematical or logical
manipulations. C++ is rich in built-in operators and provide the following types of operators −
Arithmetic Operators
Relational Operators
Logical Operators
Bitwise Operators
Assignment Operators
Misc Operators
This chapter will examine the arithmetic, relational, logical, bitwise, assignment and other operators
one by one.
Arithmetic Operators
There are following arithmetic operators supported by C++ language −
Assume variable A holds 10 and variable B holds 20, then −
Show Examples
Logical Operators
There are following logical operators supported by C++ language.
Assume variable A holds 1 and variable B holds 0, then −
Show Examples
Operator Descriiptiion Examplle
Bitwise Operators
Bitwise operator works on bits and perform bit-by-bit operation. The truth tables for &, |, and ^ are
as follows −
p q p&q p || q p^q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1
Assume if A = 60; and B = 13; now in binary format they will be as follows −
A = 0011 1100
B = 0000 1101
~A = 1100 0011
The Bitwise operators supported by C++ language are listed in the following table. Assume variable
A holds 60 and variable B holds 13, then −
Show Examples
Operator Descriiptiion Examplle
| Binary OR Operator copies a bit if it exists (A | B) will give 61 which is 0011 1101
in either operand.
~ Binary Ones Complement Operator is (~A ) will give -61 which is 1100 0011 in
unary and has the effect of 'flipping' bits. 2's complement form due to a signed
binary number.
Assignment Operators
Misc Operators
The following table lists some other operators that C++ supports.
Sr..No Operator & Descriiptiion
1
siizeof
sizeof operator returns the size of a variable. For example, sizeof(a), where ‘a’ is
integer, and will return 4.
2
Condiitiion ? X : Y
Conditional operator (?) . If Condition is true then it returns value of X otherwise
returns value of Y.
3
,,
Comma operator causes a sequence of operations to be performed. The value of the
entire comma expression is the value of the last expression of the comma-separated list.
4
.. (dot) and -> (arrow)
Member operators are used to reference individual members of classes, structures,
and unions.
5 Cast
Casting operators convert one data type to another. For example, int(2.2000) would
return 2.
6 &
Pointer operator & returns the address of a variable. For example &a; will give actual
address of the variable.
7 *
Pointer operator * is pointer to a variable. For example *var; will pointer to a variable
var.
Here, operators with the highest precedence appear at the top of the table, those with the lowest
appear at the bottom. Within an expression, higher precedence operators will be evaluated first.
Show Examples
Conditional structure
Conditional structure contain three types of write conditional programs.
1. IF – statements
2. IF – Else statements
3. IF – Else – IF statements
IF – Statements
IF- keyword: it is used to execute a statement or block only if a condition is
fulfilled. Its form is:
if (condition) statement
Where condition is the expression that is being evaluated. If this condition is true,
statements executed. If it is false, statements ignored (not executed) and the program continues
right after this conditional structure.
The structure of execution the statements is as flowchart blow:
Ex: The following code fragment prints x is 100only if the value stored in the x variable is
indeed 100:
if (x == 100)
cout << "x is 100";
If we want more than a single statement to be executed in case that the condition is true we can
specify a block using braces { }:
if (x == 100)
{
cout << "x is ";
cout << x;
}
Ex: Write a C++ program to enter two Boolean numbers then, print phrase "A And B"
if A and B equal to 1, or print phrase "A Or B" if A equal to 1 and B equal to 0.
#include <iostream>
using namespace std;
int main ()
{
bool A,B;
cin >>A ;
cin >>B ;
if ((A==1)&&(B==1))
{
cout << "A And B"<<'\n';
}
if ((A==1)||(B==0))
{ cout << "A or B"<<'\n';
}
return 0;
}
IF – Else statements
We can additionally specify what we want to happen if the condition is not fulfilled by
using the keyword else. Its form used in conjunction with ifis:
If (condition)
statement1
else
statement2
Prints on the screen x is 100if indeed has a value of 100, but if it has not -and
only if not- it prints out x is not 100.
The (if – else)structures can be concatenated with the intention of verifying a
range of values.
Chapter Four – conditional statements
Ex:
if (x == 100)
cout << "x is 100";
else
cout << "x is not 100";
Ex: Write a C++ program to find a solution for the following equation:
Enter (X and Y) and print Z then display the message "Wrong Values", if the two
conditions above are not satisfied.
Sol:
#include <iostream>
using namespace std;
int main ()
{
float X, Y;
float Z;
cin >> X;
cin>>Y;
if ((X + Y) >= 0)
{if (X > 0)
Z = (sqrt (X + Y)) / X ;
cout << "The value of Z is:"<< Z;
}
else
{cout << "Wrong Values";
}
return 0;
}
*Remember that in case that we want more than a single statement to be executed, we must
group them in a block by enclosing them in braces { }.
IF – Else – IF statements
The If and If-else statement is great when you must test against more than two
conditions, however, the If and If-else becomes difficult to maintain. Although the logic of the
If-else statement is simple, the coding is extremely difficult to follow. C++ language supports
a statement, called If-else-If, which handles such multiple-choice conditions better than If-else.
Here is the format of the If-else-If statement and also its
flowchart shown in figure below:
If (Condition-1)
Comment-1;
else If (Condition-2)
Comment -2;
.
.
.
else If (Condition-n)
Comment-n;
else
Any Comment;
Jump statements.
Jump statements divided to three statements:
1. The break statement
2. The continue statement
3. The goto statement
Using break we can leave a loop even if the condition for its end is not fulfilled.
It can be used to end an infinite loop, or to force it to end before its natural end. The conditional
statements break statement must be used with switch case (selective statement) or with loops.
Therefore, we will discuss this statement with switch statement.
The continue statement causes the program to skip the rest of the loop in the
current iteration as if the end of the statement block had been reached, causing it to
jump to the start of the following iteration. The continue statement example will
contain loop. Therefore, we will discuss this statement in the next chapter.
#include <iostream>
using namespace std;
int main ()
{
int n;
cin >> n;
switch (n)
{case 0:
cout<< "Baghdad";
break;
case 1:
cout<< "Berlin";break;
case 2:
cout<< "Beirut";break;
case 3:
cout<< "Cairo";break;
defoult:
cout<< "Paris";break;
}
return 0;
}
Chapter:4 Looping Statements
For loop
While loop
do while loop
goto
Loops are generally used when a block of code needs to be executed repeatedly. It
consists of a sequence of code that is executed and repeated until a specific condition is
achieved.
For example, if you would like to write a program that prints the word “Hello” 5 times,
there are two ways to do it, either by writing 5 print statements or by using loops as can be seen
in the next code snippet.
Alternative 1
#include
<iostream> using
namespace std;
int main()
{
cout << "Hello" <<
endl; cout << "Hello"
<< endl; cout <<
"Hello" << endl; cout
<< "Hello" << endl;
cout << "Hello" <<
endl;
return 0;
}
Output:
Hello
Hello
Hello
Hello
Hello
Alternative 2
#include <iostream>
using namespace std;
int main()
{
for(int i=0; i<5; i++)
{
cout << "Hello" << endl;
}
return 0;
}
Output:
Hello
Hello
Hello
Hello
Hello
As you can see, both methods have exactly the same output. However, as your program
gets more complex, for example if you want to print the word “Hello” 1000 times this time,
writing 1000 print statements would not be wise or efficient.
For Loops
The for loop is typically used when you know exactly how many times or iterations
should be executed. Generally, it enables you to execute your block K number of times using
just one line of code.
Syntax
Example
Write a program that initializes an empty vector of integers and then fill it with numbers
from 1 to 5000 using for loop.
Here we want to initialize the loop counter “i”, increment the counter with 1 at each
iteration and pass it to the vector, and finally when the counter reaches 5000 breaks from the
loop.
#include <iostream>
#include <vector>
int main()
{
vector<int> my_vect;
for(int i=1; i<=5000; i++)
{
my_vect.push_back(i);
}
return 0;
}
Now we have executed a block of code 5000 times using only one code statement.
While Loops
The difference between while and for loops is that this time you only need the end
condition. This means, you need to handle the initialization of your iterator and incrementing
or decrementing it separately and independent from the loop control statement.
Syntax
Write a program that initializes an empty vector of integers and then fills it with numbers from
1 to 5000 using while loop.
Here we are going to implement the same program as in the loop however this time using while
loop.
#include <iostream>
#include <vector>
while(i<=5000)
{
my_vect.push_back(i);
i++;
}
return 0;
}
Note that in both examples, the for and while loops, you can choose to inversely loop
from a greater to a smaller value and you can also increment your iterator using different values
other than 1.
Example
Write a program that initializes an empty vector, fills it with only even numbers from
5000 to 1 using for loop.
Here we need to inversely loop from 5000 to 1 and decrement our iterator with value 2 to get
only even numbers.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> my_vect;
for(int i=5000; i>=1; i-=2)
{
my_vect.push_back(i);
}
return 0;
}
Do While Loop
The do-while loop is very similar to the while loop. However, in the do-while loop, the
block of code is executed first before checking the end statement.
Syntax
do
{
// execute block of code
}
while (end condition);
Also, note that here we add a semicolon “;” at the end of the loop.
Example
Write a program to manually print characters in a string until the space character is found then
the loop terminates.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string hello = "Hello World!";
cout << "Original String: " << endl;
cout << "New String: ";
int i=0;
do
{
cout << hello[i];
i++;
}
while (hello[i] != ' ');
Output:
Original String: Hello World!
Infinite Loops
Infinite loops are used when you need to execute a block of code forever and are
typically used with embedded systems applications. On the other hand, they can be used for
normal day to day applications and can normally be interrupted using break statements.
Method 1
for(;;)
{
// run forever
}
Method 2
while (true)
{
// run forever
while (1)
{
// run forever
}
}
Example
Write a program that runs infinitely until and reads input characters from the user until
the key button is hit. Definitely a better way to do this is using the getline function
“std::getline(cin, line);”. However, an infinite loop is used here just for illustration.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string myStr;
char c;
Range-based for loops were introduced starting C++ 11. In this type of loops, we do
not rely on counting values in our structure but instead, we loop over a range.
For example, if you have a vector of integers, instead of creating a counter and then
using this counter at each iteration to access an element in the vector, a range-based for loop
would allow you to directly get that element without needing to count.
Example
Write a program that loops over a string and print “Found it” when character “W” is found
(upper or lower case), print the index where it found it.
#include <iostream>
#include <string>
int main()
{
string hello = "Welcome to the world wide web";
int index = 0;
return 0;
}
Output:
Found it at index: 0
Found it at index: 15
Found it at index: 21
Found it at index: 26
Alternatively, range-based loops can be used more generically if you do not the type of
iterator or what you are looping over by using the type inference “auto” in C++11.
Example
Write a program that initializes a vector and a string then loop over both and prints their
elements.
#include <iostream> #include
<string> #include <vector>
using namespace std;
int main()
{
string myStr = "Hello World!"; vector <int>
myVect = {1,2,3,4,5};
return 0;
}
Output:
Hello World!
12345
This one is similar in concepts to the looping techniques that we‟ve discussed
previously. However, here you are able to pass functions to the loop statement.
Note that this time you need to include one extra header:
#include <algorithm>
Syntax
This line can be interpreted to, for each element in memory from “start” iterator to
“end” iterator, call the function “fn” and pass it the current iterator.
Example
Write a program that initializes an array of 10 integers, write a function that takes one integer
as argument and prints it and then finally loops the array and print its elements using
“for_each”.
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int myArray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
return 0;
}
Output:
10
Here we used the start iterator as the first element in the array and the end iterator as
the start iterator plus the size or number of iterations needed. Also, note that functions used
need to be of type void.
GOTO
Syntax
goto label ;
Explanation
The goto statement transfers control to the location specified by label. The goto
statement must be in the same function as the label it is referring, it may appear before or after
the label.
If transfer of control exits the scope of any automatic variables (e.g. by jumping
backwards to a point before the declarations of such variables or by jumping forward out of a
compound statement where the variables are scoped), the destructors are called for all variables
whose scope was exited, in the order opposite to the order of their construction.
The goto statement cannot transfer control into a try-block or into a catch-clause, but
can transfer control out of a try-block or a catch-clause (the rules above regarding automatic
variables in scope are followed)
If transfer of control enters the scope of any automatic variables (e.g. by jumping
forward over a declaration statement), the program is ill-formed (cannot be compiled), unless
all variables whose scope is entered have
1) scalar types declared without initializers
2) class types with trivial default constructors and trivial destructors initializers
3) cv-qualified versions of one of the above
4) arrays of one of the above
(Note: the same rules apply to all forms of transfer of control)
Keywords
goto
Notes
In the C++ programming language, the goto statement has fewer restrictions and can
enter the scope of any variable other than variable-length array or variably-modified pointer.
Example
#include <iostream>
struct Object {
// non-trivial destructor
~Object() { std::cout << "d"; }
};
struct Trivial {
double d1;
double d2;
}; // trivial ctor and dtor
int main()
{
int a = 10;
if (a != 0) {
goto label; // jumps out of scope of obj, calls obj destructor
}
std::cout << '\n';
{
Object obj3;
goto label3; // jumps forward, out of scope of obj3
}
label3:
std::cout << '\n';
}
Output:
10 d8 d6 d4 d2
(0;0)
(0;1)
(0;2)
(1;0)
(1;1)
(1;2)
d
d
Chapter:5 Arrays
1D array
2D array
1D array
One dimensional array are the simplest form of an array in C++ language. You can
easily declare, initialize, and manipulate a one-dimensional array. A one-dimensional array can
be a parameter for function and so on. You can treat individual array element like any other
C++ variables.
1-D Array Declaration
The syntax to declare a one-dimensional array is very simple. Here it is,
<datatype> <array name> [n];
The two square brackets hold the number of elements in the array denoted by n.
Example#1
float demo [10];
The above array can hold 11 elements because the index associated with each array
element starts with 0. The first element has an index value of 0.
You can use any suitable method given. Here is an example for one-dimensional array
declaration.
Example #2
int toyota_car [5]; //array declaration
toyota_car [5]= { 2345, 4566, 7766, 3456, 9898}; //array value assignment
Example #3
char superheroes[3] = {"spiderman", "superman", "ironman"};
or
you can do the declaration and assignment without specifying a number. See the
example below.
Example #4
char superheroes[] = {"spiderman", "superman", "ironman"};
In the above example, we never provide any number to the subscript, the assignment of
3 values will determine the length of the one-dimensional array.
The first element of the array has an index value of 0. If you use the name of the array,
then it refers to the memory address of the first element of the array. Using the first element,
you can find the memory address of rest of the elements and this is done by adding an offset to
the memory address of the first element.
For example,
Therefore, to pass an array as a function parameter, you need to pass only the first
element memory address and the rest of the array can be calculated automatically.
Example Program:
/* This program demonstrate the use of memory address of the first element of an array and
pass it as a parameter to a function.
The function use a different subscript notation (a + i) to compute sum of all elements of the
array */
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
int arr[5]={23,45,67,112,22};
int arrpara(int arr[]);
arrpara(arr);
system("PAUSE");
return EXIT_SUCCESS;
}
int arrpara(int arr[])
{
int sum = 0;
int i;
for(i=0;i<5;i++)
{
sum = sum + *(arr + i);
}
cout << " first element =" << " " << arr << endl;
cout << "sum =" << " " << sum << endl;
}
Output:
Two-dimensional Array
A two-dimensional array has rows and columns. The horizontal arrangement of
elements within a two-dimensional array is row and vertical arrangement is a column.
For example,
A[2][4] means that this two-dimensional element is from 3rd row and 5th column. The
row or column index starts at 0.
Example #1
int account [3][4];
float boxes[2][3];
The example shows that the array account has 3 rows and 4 columns indicated by
subscripts.
Also, you can initialise 2a d array dynamically. See the example program below.
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
int sq_matrix[3][3];
int i,j;
//Reading values for matrix
cout << "Enter matrix values";
for(i =0;i<3;i++)
{
for(j=0;j<3;j++)
{
cin >> sq_matrix [i][j];
}
}
//print the array
for(i =0;i<3;i++)
{
for(j=0;j<3;j++)
{
cout << sq_matrix [i][j] << " ";
}
cout << endl;
}
system("PAUSE");
return EXIT_SUCCESS;
}
Output
At this point, you may not understand this example because so far we have not discussed Classes
and Objects. So can have a look and proceed until you have understanding on Object Oriented
Concepts.
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str1 = "Hello";
string str2 = "World";
string str3;
int len ;
return 0;
}
When the above code is compiled and executed, it produces result something as follows:
str3 : Hello
str1 + str2 : HelloWorld str3.size() : 10
string mystring;
cin >> mystring;
However, cin extraction always considers spaces (whitespaces, tabs, new-line...) as terminating the value being
extracted, and thus extracting a string means to always extract a single word, not a phrase or an entire sentence.
To get an entire line from cin, there exists a function, called getline, that takes the stream (cin) as first argument,
and the string variable as second. For example:
// cin with strings #include <iostream> What's your name? Homer Simpson Hello Homer
#include <string> using namespace std; Simpson.
What is your favorite team? The Isotopes I like
int main () The Isotopes too!
{
string mystr;
cout << "What's your name? "; getline (cin,
mystr);
cout << "Hello " << mystr << ".\n"; cout <<
"What is your favorite team? "; getline (cin,
mystr);
cout << "I like " << mystr << " too!\n"; return 0;
}
Notice how in both calls to getline, we used the same string identifier (mystr). What the program does in the
second call is simply replace the previous content with the new one that is introduced.
C-String manipulation
The C-style character string originated within the C language and continues to be supported
within C++. This string is actually a one-dimensional array of characters which is terminated by
a null character '\0'. Thus a null-terminated string contains the characters that comprise the string
followed by a null.
The following declaration and initialization create a string consisting of the word "Hello". To
hold the null character at the end of the array, the size of the character array containing the string
is one more than the number of characters in the word "Hello."
Actually, you do not place the null character at the end of a string constant. The C++ compiler
automatically places the '\0' at the end of the string when it initializes the array. Let us try to print
above-mentioned string:
#include <iostream>
int main ()
{
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
return 0;
}
When the above code is compiled and executed, it produces result something as follows:
Greeting message:
Hello
C++ supports a wide range of functions that manipulate null-terminated strings:
#include <iostream>
#include <cstring>
using namespace std;
int main ()
{
char str1[10] =
"Hello"; char str2[10]
= "World"; char
str3[10];
int len ;
return 0;
}
When the above code is compiled and executed, it produces result something as follows:
Using pointer
char * string_name;
where: string_name is a pointer.
Example: char *lastname;
char * firstname;
Using array
char string_name[size];
where: size is the number of characters including the null character \0 stored in the array..
Example: char lastname[30];
char firstname[20];
A string can be declared and initialized by using a pointer or an array of characters. Using
Table below lists the commonly available library functions for string input and output
Example Output
#include<iostream>
using namespace std;
int main( ) Enter a string for message1:
{char message1[80]; Good morning
char *message2; Enter a string for message2:
cout <<"Enter a string for message1: \n"; have a nice day
cin.getline(message1,80); Good morning and have a nice
cout << "Enter a string for message2: \n"; day
cin.getline(message2,80);
cout <<message1<< " and " <<message2;
}
Extensive collections of string-handling functions are included with all C++ compilers. The
common of these are listed below. To call these functions, you needto include the header file
<string.h> in your program.
String copy
strcpy(string1,string2) - Copies string2 to string1. String1 needs to have enoughspace
to store string2. The
strcpy will overwrite string1.
String concatenation
strcat(string1,string2) - concatenates string2 to string1. String1 needs tohave
enough space to append
string2.
String comparison
strcmp(string1, string2) - Compares string1 to string2. Returns a negative integer if
string1<string2, 0 if string1
is equal to string2, and a positive integer if string1 > string2.
Note: When strcmp compare the character c in string1 with the character C in string2.The
character c is greater than the character C because the asscii value of character c is 99 and the
asscii value of character C is only 67. See the Appendix B ASCII character set in the back of
your text book.
String length
strlen(string1) - Return the length of the string, excluding the null character
Example: char message[80] = "Hello world";int
i;
i = strlen(message);
cout << i << " characters";
Output
11 characters
C++ provides several functions that allow you to test and manipulate character data. The
function prototypes are found in the header file name <ctype.h>. Remember to add the line
#include <ctype.h> in program that use these functions. The table below lists and describes the
character functions. Each function expects one integer argument - the ASCII value of the
character to be tested. Each function returns a non-zero value (true) if the condition tested is true
and 0 (false) if the condition tested is false.
The example below will convert each lowercase character of a string to uppercasecharacter and
vice versa.
Example
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int main( )
{ char name[20];
cout<<"Enter your name:\n ";
cin.getline(name,20);
for( int i = 0; i < strlen(name) ; i++)
{ if (islower(name[i]) )
//convert to uppercase
name[i] = toupper(name[i]);
else
//convert to lowercase
name[i] = tolower(name[i]);
}
//Display the result
cout << "The conversion is:\n";
cout << name << endl;
}
Output
Enter your name:
Phuong D. Nguyen
The conversion is:
pHUONG d. nGUYEN
Output
Enter your name:
Phuong D. Nguyen
The conversion is:
pHUONG d. nGUYEN
Write a function that returns the number of digits in a given null-terminated string.
#include<iostream>
#include<cctype>
using namespace std;
int numAlphas(const char* s)
{
int count = 0;
for (int i = 0; s[i] != '\0'; i++)
{
if (isdigit(s[i]))
{
count++;
}
}
return count;
}
int main()
{
char str[] = "a12bc3d";
cout << numAlphas(str);
int main()
{
char s[15] = "Hello World";
cout << myStrLen(s);
return 0;
}
//
int myStrLen(char str[])
{
int i = 0;
while (str[i] != '\0')
i++;
return i;
}
Or
Or
}
// create your own strcpy function
#include <iostream>
using namespace std;
void myStrcpy(char str2[], char str1[]);int
main()
{
char s1[15] = "Hello World";
char s2[30];
myStrcpy(s2, s1);
cout << s2; return
0;
}
//
void myStrcpy(char *to, char * from)
{
while (*to = *from)
{
to++;
from++
;
}
Or
}
Chapter:7 Function
Basics,call by value
call by reference & return by
reference
Inline function
Overloading Functions
Recursive Functions
FUNCTION IN C++:
The main( )Functon ;
ANSI does not specify any return type for the main ( ) function which is the starting
point for the execution of a program .The definition of main( ) is :-
main()
{
//main program statements
}
This is property valid because the main () in ANSI C does not return any value. In C++,
the main () returns a value of type int to the operating system. The functions that have a return
value should use the return statement for terminating.
The main () function in C++ is therefore defined as follows.
int main( )
{
--------------
--------------
return(0)
}
Since the return type of functions is int by default, the key word int in the main( ) header
is optional.
INLINE FUNCTION:
To eliminate the cost of calls to small functions C++ proposes a new feature called
inline function. An inline function is a function that is expanded inline when it is invoked. That
is the compiler replaces the function call with the corresponding function code.
The inline functions are defined as follows:-
inline function-header
{
function body;
}
Example: inline double cube (double a)
{
return(a*a*a);
}
The above inline function can be invoked by statements like
c=cube(3.0);
d=cube(2.5+1.5);
remember that the inline keyword merely sends a request, not a command to the compliler. The
compiler may ignore this request if the function definition is too long or too complicated and
compile the function as a normal function.
Some of the situations where inline expansion may not work are:
1. For functions returning values if a loop, a switch or a go to exists.
2. for function s not returning values, if a return statement exists.
3. if functions contain static variables.
4. if inline functions are recursive,.
Example:
#include<iostream.h>
#include<stdio.h>
inline float mul(float x, float y)
{
return(x*y);
}
inline double div(double p.double q)
{
return(p/q);
}
main( )
{
float a=12.345;
float b=9.82;
cout<<mul(a,b)<<endl;
cout<<div (a,b)<<endl;
}
output:-
121.227898
1.257128
DEFAULT ARGUMENT: -
C++ allows us to call a function with out specifying all its arguments.In such cases, the
function assigns a default value to the parameter which does not have a matching aguments in
the function call. Default values are specified when the function is declared .The compiler looks
at the prototype to see how many arguments a function uses and alerts the program for possible
default values.
Example: float amount (float principle, int period, float rate=0.15);
The default value is specified in a manner syntactically similar to a variable
initialization. The above prototype declares a default value of 0.15 to the argument rate. A
subsequent function call like value=amount (5000,7); //one argument missing passes the value
of 5000 to principle and 7 to period and then lets the function, use default value of 0.15 for
rate.
The call: - value=amount (5000,5,0.12); //no missing argument passes an explicite
value of 0.12 rate. One important point to note is that only the trailing arguments can have
default values. That is, we must add default from right to left. We cannot provide a default to
a particular argument in the middle of an argument list.
Example: -
int mul(int i, int j=5,int k=10);//illegal
int mul(int i=0,int j,int k=10);//illegal
int mul(int i=5,int j);//illegal
int mul(int i=2,int j=5,int k=10);//illegal
Default arguments are useful in situation whose some arguments always have the some
value.
For example, bank interest may retain the same for all customers for a particular period of
deposit.
Example:
#include<iostream.h>
#include<stdio.h>
mainQ
{
float amount;
float value(float p,int n,float r=0.15);
void printline(char ch=‟*‟,int len=40);
printline( );
amount=value(5000.00,5);
cout<<”\n final value=”<<amount<<endl;
printline(„=‟);
//function definitions
float value (float p,int n, float r)
{
float si;
si=(p*n*r)/100;
return(si);
}
void printline (char ch,int len)
{
for(inti=l;i<=len;i++)
cout<<ch<<endl;
}
output:-
****************
final value=10056.71613
===============
Advantage of providing the default arguments are:
1. We can use default arguments to add new parameters to the existing functions.
2. Default argument s can be used to combine similar functions into one.
CONST ARGUMENT: -
In C++, an argument to a function can be declared as unit as const as shown
below.
void recursion()
{
... .. ...
recursion();
... .. ...
}
int main()
{
... .. ...
recursion();
... .. ...
}
The figure below shows how recursion works by calling the recursive function again and
again.
There are two types of recursive function i.e. direct recursion and indirect recursion.
Direct recursion is when the function calls itself just like we saw in the above program.
Indirect recursion is when the function calls another function and then that function calls the
calling function.
Advantages of C++ Recursion
Less number code lines are used in the recursion program and hence the code looks
shorter and cleaner.
Recursion is easy to approach to solve the problems involving data structure and
algorithms like graph and tree
Recursion helps to reduce the time complexity
It helps to reduce unnecessary calling of the function
It helps to solve the stack evolutions and prefix, infix, postfix evaluation
Recursion is the best method to define objects that have repeated structural forms
The recursion approach is the most important method to solve any program and therefore,
there are many popular problem statements which are asked in technical interviews to test
your level of understanding of the concept of recursion.
Top 5 Recursion C++ Examples
Below, we will study some of that recursive programs as an example along with their C++
code.
C++ program
#include <iostream>
using namespace std;
int fibonnaci(int x) {
if((x==1)||(x==0)) {
return(x);
}else {
return(fibonnaci(x-1)+fibonnaci(x-2));
}
}
int main() {
int x , i=0;
cout << "Enter the number of terms of series : ";
cin >> x;
cout << "\nFibonnaci Series : ";
while(i < x) {
cout << " " << fibonnaci(i);
i++;
}
return 0;
}
Output
Enter the number of terms of series : 15
Here in the above program, the "fibonacci" function is the recursive function which calls
itself and finds the Fibonacci series.
C++ program
#include <iostream>
using namespace std;
int main()
{
int n;
cout << "Factorial of " << n << " = " << fact(n);
return 0;
}
int fact(int n)
{
if(n > 1)
return n * fact(n - 1);
else
return 1;
}
Output
Enter an positive integer: 6
Factorial of 6 = 720
Here the recursive function "fact" will take a number as a parameter for which we
want to find the factorial. And then recursively call the function until the base condition
becomes true which is when the number as a parameter becomes 1.
The time complexity for the recursive factorial program is O(n) because only one loop
is executed at a time while finding the factorial of the number using the recursive function.
Also, there is no extra space required during recursive calls and therefore, the space
complexity is also O(n).
3) Program To Calculate Number Power Using Recursion In C++
In this program, we will calculate the power of the number using the recursion
approach where the base and exponent is taken as input by the user.
C++ Program
#include <iostream>
using namespace std;
int main()
{
int base, power, result;
return 0;
}
Output
Enter base number: 3
3^4 = 81
Here the recursice function "calculate" calls itself again and again with the base
condition to check the power until 0 because the exponent is always the positive integer.
The running time complexity for the program to find the power of the number using
recursion is O(logn) because every time the recursive function is called, the parameter of the
next call is increased by exponential times. Therefore, the time complexity is the function of
the log.
4) Reverse A Number Using Recursion In C++
In this program, we will take input from the user as an integer number and reverse it
using the recursive function.
C++ program
#include <iostream.h>
using namespace std;
int reverseNumber(int n) {
static temp,sum;
if(n>0){
temp = n%10;
sum = sum*10 + temp;
reverseNumber(n/10);
} else {
return sum;
}
int main() {
int n,reverse;
cout<<"Enter number";
cin >> n;
reverse = reverseNumber(n);
return 0;
}
Output
Enter number : 3456
Reverse of number is : 6543
In this program, we will recursively call the "reverseNumber" function with the parameter
that the user entered.
The running time complexity of the program is O(log(n)) because every time the function is
called recursively, it takes 1/10 of the number as a parameter for the next call. Therefore, the
time complexity for reversing the number using the recursive function is O(log(n)).
C++ program
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n = 18;
if (isprime(n))
cout << "Yes, Number is Prime Number";
else
cout << "No, Number is not Prime Number";
return 0;
}
Output
No, Number is not Prime Number
Here, we create the recursive function "isprime" and all it recursively and then check the
prime number condition using conditional statements.
The running time complexity of the program to check whether the number is prime or not is
O(sqrt(n)) because when we recursively call the function isPrime we check whether it is less
than the square root of the given number.
Chapter:8 Pointers
Pointers
Dynamic Memory Allocation
1
1. Pointer Variables
A computer memory location has an address and holds a content. The address is a numerical
number (often expressed in hexadecimal), which is hard for programmers to use directly.
Typically, each address location holds 8-bit (i.e., 1-byte) of data. It is entirely up to the
programmer to interpret the meaning of the data, such as integer, real number, characters or
strings.
To ease the burden of programming using numerical address and programmer-interpreted data,
early programming languages (such as C) introduce the concept of variables. A variable is a
named location that can store a value of a particular type. Instead of numerical addresses, names
(or identifiers) are attached to certain addresses. Also, types (such as int, double, char) are
associated with the contentsfor ease of interpretation of data.
Each address location typically hold 8-bit (i.e., 1-byte) of data. A 4-byte int value occupies 4
memory locations. A 32-bit system typically uses 32-bit addresses. To store a 32-bit address, 4
memory locations are required.
The following diagram illustrate the relationship between computers' memory address and
content; and variable's name, type and value used by the programmers.
2
2. Pointer Variables (or Pointers)
A pointer variable (or pointer in short) is basically the same as the other variables, which can
store a piece of data. Unlike normal variable which stores a value (such as an int, a double, a
char), a pointerstores a memory address.
3. Declaring Pointers
Pointers must be declared before they can be used, just like a normal variable. The syntax of
declaring a pointer is to place a * in front of the name. A pointer is associated with a
type (suchas int and double) too.
type *ptr; // Declare a pointer variable called ptr as a pointer of type
// or
type* ptr;
// or
type * ptr; // I shall adopt this convention
For example,
int * iPtr; // Declare a pointer variable called iPtr pointing to an int (an int
pointer)
// It contains an address. That address holds an int value.
double * dPtr; // Declare a double pointer
Take note that you need to place a * in front of each pointer variable, in other words, * applies only
to the name that followed. The * in the declaration statement is not an operator, but indicates that
the name followed is a pointer variable. For example,
int *p1, *p2, i; // p1 and p2 are int pointers. i is an int
int* p1, p2, i; // p1 is a int pointer, p2 and i are int
int * p1, * p2, i; // p1 and p2 are int pointers, i is an int
Naming Convention of Pointers: Include a "p" or "ptr" as prefix or suffix,
e.g., iPtr, numberPtr, pNumber, pStudent.
4. Initializing Pointers via the Address-Of Operator (&)
When you declare a pointer variable, its content is not initialized. In other words, it contains an
address of "somewhere", which is of course not a valid location. This is dangerous! You need to
initialize a pointer by assigning it a valid address. This is normally done via the address-of
operator (&).
The address-of operator (&) operates on a variable, and returns the address of the variable. For
example,if numberis an int variable, &number returns the address of the variable number.
You can use the address-of operator to get the address of a variable, and assign the address to a
pointer variable. For example,
int * pAnother = &number; // Declare another int pointer and init to address of the
variable number
3
As illustrated, the int variable number, starting at address 0x22ccec, contains an int value 88. The
expression &number returns the address of the variable number, which is 0x22ccec. This address
is thenassigned to the pointer variable pNumber, as its initial value.
The address-of operator (&) can only be used on the RHS.
5. Indirection or Dereferencing Operator (*)
The indirection operator (or dereferencing operator) (*) operates on a pointer, and returns the
value stored in the address kept in the pointer variable. For example, if
pNumber isan int pointer, *pNumber returns the int value "pointed to" by pNumber.
For example,
int number = 88;
int * pNumber = &number; // Declare and assign the address of variable number to
pointer pNumber (0x22ccec)
cout << pNumber<< endl; // Print the content of the pointer variable, which contain
an address (0x22ccec)
cout << *pNumber << endl; // Print the value "pointed to" by the pointer, which is an
int (88)
*pNumber = 99; // Assign a value to where the pointer is pointed to, NOT to
the pointer variable
cout << *pNumber << endl; // Print the new value "pointed to" by the pointer (99)
cout << number << endl; // The value of variable number changes as well (99)
Take note that pNumber stores a memory address location, whereas *pNumber refers to the value
stored in the address kept in the pointer variable, or the value pointed to by the pointer.
As illustrated, a variable (such as number) directly references a value, whereas a
pointer indirectly references a value through the memory address it stores. Referencing a value
indirectly via a pointer is called indirection or dereferencing.
The indirection operator (*) can be used in both the RHS (temp = *pNumber) and the LHS (*pNumber
= 99) of an assignment statement.
Take note that the symbol * has different meaning in a declaration statement and in an
expression. When it is used in a declaration (e.g., int * pNumber), it denotes that the name
followed is a pointer variable. Whereas when it is used in a expression (e.g., *pNumber = 99;
temp << *pNumber;), it refersto the value pointed to by the pointer variable.
5.1 Pointer has a Type Too
4
A pointer is associated with a type (of the value it points to), which is specified during
declaration. Apointer can only hold an address of the declared type; it cannot hold an address of a
int i = 88;
double d = 55.66;
int * iPtr = &i; // int pointer pointing to an int value
double * dPtr = &d; // double pointer pointing to a double value
int j = 99;
iPtr = &j; // You can change the address stored in a pointer
different type.
Example
Notes: The address values that you get are unlikely to be the same as mine. The OS loads the
programin available free memory locations, instead of fixed memory locations.
6. Uninitialized Pointers
The pointer iPtr was declared without initialization, i.e., it is pointing to "somewhere" which is of
course an invalid memory location. The *iPtr = 55 corrupts the value of "somewhere"! You need
to initialize a pointer by assigning it a valid address. Most of the compilers does not signal an
error or a warning for uninitialized pointer?!
7. Null Pointers
You can initialize a pointer to 0 or NULL, i.e., it points to nothing. It is called a null pointer.
Dereferencinga null pointer (*p) causes an STATUS_ACCESS_VIOLATION exception.
int * iPtr = 0; // Declare an int pointer, and initialize the pointer to point
to nothing
cout << *iPtr << endl; // ERROR! STATUS_ACCESS_VIOLATION exception
8. Reference Variables
C++ added the so-called reference variables (or references in short). A reference is an
alias, or an alternate name to an existing variable. For example, suppose you make peter a
reference (alias)to paul, you can refer to the person as either peteror paul.
The main use of references is acting as function formal parameters to support pass-by-reference.
In an reference variable is passed into a function, the function works on the original copy
(instead of a clone copy in pass-by-value). Changes inside the function are reflected outside the
function.
A reference is similar to a pointer. In many cases, a reference can be used as an alternative to
pointer,in particular, for the function parameter.
9. References (or Aliases) (&)
Recall that C/C++ use & to denote the address-of operator in an expression. C++ assigns an
additionalmeaning to &in declaration to declare a reference variable.
The meaning of symbol & is different in an expression and in a declaration. When it is used in an
expression, & denotes the address-of operator, which returns the address of a variable, e.g., if
number is an int variable, &number returns the address of the variable number (this has been
described in the above section).
Howeve, when & is used in a declaration (including function formal parameters), it is part of the
type identifier and is used to declare a reference variable (or reference or alias or alternate
name). It is usedto provide another name, or another reference, or alias to an existing variable.
The syntax is as follow:
6
type &newName = existingName;
// or
type& newName = existingName;
// or
type & newName = existingName; // I shall adopt this convention
It shall be read as "newName is a reference to exisitngName", or "newNew is an alias of
existingName".You can now refer to the variable as newName or existingName.
For example,
7
11. References vs. Pointers
A reference variable provides a new name to an existing variable. It is dereferenced implicitly and
does not need the dereferencing operator * to retrieve the value referenced. On the other hand, a
pointer variable stores an address. You can change the address value stored in a pointer. To
retrieve the value pointed to by a pointer, you need to use the indirection operator *, which is
known as explicit dereferencing. Reference can be treated as a const pointer. It has to be
initialized during declaration,and its content cannot be changed.
Reference is closely related to pointer. In many cases, it can be used as an alternative to pointer.
A reference allows you to manipulate an object using pointer, but without the pointer syntax of
referencing and dereferencing.
The above example illustrates how reference works, but does not show its typical usage, which is
usedas the function formal parameter for pass-by-reference.
12. Pass-By-Reference into Functions with Reference Arguments vs. Pointer Arguments
Pass-by-Value
In C/C++, by default, arguments are passed into functions by value (except arrays which is
treated as pointers). That is, a clone copy of the argument is made and passed into the function.
Changes to the clone copy inside the function has no effect to the original argument in the caller.
In other words, thecalled function has no access to the variables in the caller. For example,
1/* Pass-by-value into function (TestPassByValue.cpp) */
2#include <iostream>
3using namespace std;
4
5int square(int);
6
9
7int main() {
8 int number = 8;
9 cout << "In main(): " << &number << endl; // 0x22ff1c
10 cout << number << endl; // 8
11 cout << square(number) << endl; // 64
12 cout << number << endl; // 8 - no change
13}
14
15int square(int n) { // non-const
16 cout << "In square(): " << &n << endl; // 0x22ff00
17 n *= n; // clone modified inside the function
18 return n;
19}
The output clearly shows that there are two different addresses.
Pass-by-Reference with Pointer Arguments
In many situations, we may wish to modify the original copy directly (especially in passing huge
object or array) to avoid the overhead of cloning. This can be done by passing a pointer of the
object into the function, known as pass-by-reference. For example,
1/* Pass-by-reference using pointer (TestPassByPointer.cpp) */
2#include <iostream>
3using namespace std;
4
5void square(int *);
6
7int main() {
8 int number = 8;
9 cout << "In main(): " << &number << endl; // 0x22ff1c
10 cout << number << endl; // 8
11 square(&number); // Explicit referencing to pass an address
12 cout << number << endl; // 64
13}
14
15void square(int * pNumber) { // Function takes an int pointer (non-const)
16 cout << "In square(): " << pNumber << endl; // 0x22ff1c
17 *pNumber *= *pNumber; // Explicit de-referencing to get the value pointed-to
18}
The called function operates on the same address, and can thus modify the variable in the caller.
Pass-by-Reference with Reference Arguments
Instead of passing pointers into function, you could also pass references into function, to avoid
theclumsy syntax of referencing and dereferencing. For example,
10
2#include <iostream>
3using namespace std;
4
5void square(int &);
6
7int main() {
8 int number = 8;
9 cout << "In main(): " << &number << endl; // 0x22ff1c
10 cout << number << endl; // 8
11 square(number); // Implicit referencing (without '&')
12 cout << number << endl; // 64
13}
14
15void square(int & rNumber) { // Function takes an int reference (non-const)
16 cout << "In square(): " << &rNumber << endl; // 0x22ff1c
17 rNumber *= rNumber; // Implicit de-referencing (without '*')
18}
Again, the output shows that the called function operates on the same address, and can thus
modify the caller's variable.
Take note referencing (in the caller) and dereferencing (in the function) are done implicitly. The
only coding difference with pass-by-value is in the function's parameter declaration.
Recall that references are to be initialized during declaration. In the case of function formal
parameter,the references are initialized when the function is invoked, to the caller's arguments.
References are primarily used in passing reference in/out of functions to allow the called
function accesses variables in the caller directly.
"const" Function Reference/Pointer Parameters
A const function formal parameter cannot be modified inside the function. Use const whenever
possible as it protects you from inadvertently modifying the parameter and protects you against
manyprogramming errors.
A const function parameter can receive both const and non-const argument. On the other hand, a
non-const function reference/pointer parameter can only receive non-const argument. For
example,
/* Test Function const and non-const parameter (FuncationConstParameter.cpp)
*/ #include <iostream>
using namespace std;
int squareConst(const int);
int squareNonConst(int);
int squareConstRef(const int &);
int squareNonConstRef(int &);
int main() {
int number = 8;
11
const int constNumber = 9;
cout << squareConst(number) << endl;
cout << squareConst(constNumber) << endl;cout <<
squareNonConst(number) << endl;
cout << squareNonConst(constNumber) << endl;
12
cout << "In main() &number1: " << &number1 << endl; // 0x22ff14int &
result = squareRef(number1);
cout << "In main() &result: " << &result << endl; // 0x22ff14cout << result
<< endl; // 64
cout << number1 << endl; // 64
int number2 = 9;
cout << "In main() &number2: " << &number2 << endl; // 0x22ff10int *
pResult = squarePtr(&number2);
cout << "In main() pResult: " << pResult << endl; // 0x22ff10cout <<
*pResult << endl; // 81
cout << number2 << endl; // 81
}
13
}
14. Summary
Pointers and references are highly complex and difficult to master. But they can greatly
improve theefficiency of the programs.
14
For novices, avoid using pointers in your program. Improper usage can lead to serious logical
bugs. However, you need to understand the syntaxes of pass-by-reference with pointers and
references, because they are used in many library functions.
In pass-by-value, a clone is made and passed into the function. The caller's copy cannot
bemodified.
In pass-by-reference, a pointer is passed into the function. The caller's copy could be
modifiedinside the function.
In pass-by-reference with reference arguments, you use the variable name as the argument.
In pass-by-reference with pointer arguments, you need to use &varName(an address) as
theargument.
// Dynamic Allocation
int * p2; // Not initialize, points to somewhere which is invalid
cout << p2 << endl; // Print address before allocation
p2 = new int; // Dynamically allocate an int and assign its address to pointer
// The pointer gets a valid address with memory allocated
*p2 = 99;
cout << p2 << endl; // Print address after allocation
cout << *p2 << endl; // Print value point-to
delete p2; // Remove the dynamically allocated storage
Observe that newand delete operators work on pointer.
To initialize the allocated memory, you can use an initializer for fundamental types, or
invoke aconstructor for an object. For example,
// use an initializer to initialize a fundamental type (such as int, double)
int * p1 = new int(88);
double * p2 = new double(1.23);
15
// invoke a constructor to initialize an object (such as Date, Time)
Date * date1 = new Date(1999, 1, 1);
Time * time1 = new Time(12, 34, 56);
You can dynamically allocate storage for global pointers inside a function. Dynamically
allocatedstorage inside the function remains even after the function exits. For example,
1// Dynamically allocate global pointers (TestDynamicAllocation.cpp)
2#include <iostream>
3using namespace std;
4
5int * p1, * p2; // Global int pointers
6
7// This function allocates storage for the int*
8// which is available outside the function
9void allocate() {
10 p1 = new int; // Allocate memory, initial content unknown
11 *p1 = 88; // Assign value into location pointed to by pointer
12 p2 = new int(99); // Allocate and initialize
13}
14
15int main() {
16 allocate();
17 cout << *p1 << endl; // 88
18 cout << *p2 << endl; // 99
19 delete p1; // Deallocate
20 delete p2;
21 return 0;
22}
The main differences between static allocation and dynamic allocations are:
1. In static allocation, the compiler allocates and deallocates the storage automatically, and
handle memory management. Whereas in dynamic allocation, you, as the programmer,
handle the memory allocation and deallocation yourself (via new and delete operators).
You have full control on the pointer addresses and their contents, as well as memory
management.
2. Static allocated entities are manipulated through named variables. Dynamic allocated
entities are handled through pointers.
15.2 new[] and delete[] Operators
Dynamic array is allocated at runtime rather than compile-time, via the new[] operator. To remove
thestorage, you need to use the delete[] operator (instead of simply delete). For example,
1/* Test dynamic allocation of array (TestDynamicArray.cpp) */
2#include <iostream>
3#include <cstdlib>
4using namespace std;
16
5
6int main() {
7 const int SIZE = 5;
8 int * pArray;
9
10 pArray = new int[SIZE]; // Allocate array via new[] operator
11
12 // Assign random numbers between 0 and 99
13 for (int i = 0; i < SIZE; ++i) {
14 *(pArray + i) = rand() % 100;
15 }
16 // Print array
17 for (int i = 0; i < SIZE; ++i) {
18 cout << *(pArray + i) << " ";
19 }
20 cout << endl;
21
22 delete[] pArray; // Deallocate array via delete[] operator
23 return 0;
24}
C++03 does not allow your to initialize the dynamically-allocated array. C++11 does with the
braceinitialization, as follows:
// C++11
int * p = new int[5] {1, 2, 3, 4, 5};
17
cout << &numbers[0] << endl; // Print address of first element (0x22fef8) cout <<
numbers << endl; // Same as above (0x22fef8)
cout << *numbers << endl; // Same as numbers[0] (11) cout <<
*(numbers + 1) << endl; // Same as numbers[1] (22) cout <<
*(numbers + 4) << endl; // Same as numbers[4] (41)
}
16.2 Pointer Arithmetic
As seen from the previous section, if numbers is an int array, it is treated as an int pointer
pointing to the first element of the array. (numbers + 1) points to the next int, instead of having
the next sequential address. Take note that an int typically has 4 bytes. That is (numbers + 1)
increases the address by 4, or sizeof(int). For example,
int numbers[] = {11, 22, 33};
int * iPtr = numbers;
cout << iPtr << endl; // 0x22cd30
cout << iPtr + 1 << endl; // 0x22cd34 (increase by 4 - sizeof int)
cout << *iPtr << endl; // 11
cout << *(iPtr + 1) << endl; // 22
cout << *iPtr + 1 << endl; // 12
int main() {
const int SIZE = 4;
int numbers[SIZE] = {11, 22, 33, 22};
print(numbers, SIZE);
cout << max(numbers, SIZE) << endl;
replaceByMax(numbers, SIZE);
print(numbers, SIZE);
}
// Return the maximum value of the given array.
// The array is declared const, and cannot be modified inside the function.21int max(const int
arr[], int size) {
} int max = arr[0]
for (int i = 1; i < size; ++i) { if (max < arr[i]) max = arr[i];
}
return max;
// Replace all elements of the given array by its maximum value
// Array is passed by reference. Modify the caller's copy.
void replaceByMax(int arr[], int size) {
int maxValue = max(arr, size); for (int
i = 0; i < size; ++i) {
arr[i] = maxValue;
}
}
20
9int main() {
10 const int SIZE = 5;
11 int a[SIZE] = {8, 4, 5, 3, 2};
12 cout << "sizeof in main() is " << sizeof(a) << endl;
13 cout << "address in main() is " << a << endl;
14 fun(a, SIZE);
15}
16
17// Function definitions
18void fun(const int *arr, int size) {
19 cout << "sizeof in function is " << sizeof(arr) << endl;
20 cout << "address in function is " << arr << endl;
21}
sizeof in main() is 20
address in main() is 0x22fefc
sizeof in function is 4
address in function is 0x22fefc
The address of arrays in main() and the function are the same, as expected, as array is passed by
reference.
In main(), the sizeof array is 20 (4 bytes per int, length of 5). Inside the function, the sizeof is 4,
which is the sizeof int pointer (4-byte address). This is why you need to pass the size into the
function.
16.6 Operating on a Range of an Array
1/* Function to compute the sum of a range of an array (SumArrayRange.cpp) */
2#include <iostream>
3using namespace std;
4
5// Function prototype
6int sum(const int *begin, const int *end);
7
8// Test Driver
9int main() {
10 int a[] = {8, 4, 5, 3, 2, 1, 4, 8};
11 cout << sum(a, a+8) << endl; // a[0] to a[7]
12 cout << sum(a+2, a+5) << endl; // a[2] to a[4]
13 cout << sum(&a[2], &a[5]) << endl; // a[2] to a[4]
14}
15
16// Function definition
17// Return the sum of the given array of the range from
18// begin to end, exclude end. 21
19int sum(const int *begin, const int *end) {
20 int sum = 0;
21 for (const int *p = begin; p != end; ++p) {sum += *p;
22 }
23 return sum;
24}
25
Program Notes:
To write a function that operates on a range of the given array, you can pass the begin
pointer and the end pointer into the function. By convention, the operation shall start at the
begin pointer,up to the end pointer, but excluding the end pointer.
In "const int *p", *p(content pointed-to) is constant, but p is not constant.
17. *More On Pointers
// Function-pointer declaration
return-type (* function-ptr-name) (parameter-list)
// Examples
double (*fp)(int, int) // fp points to a function that takes two ints and returns a
double (function-pointer)
double *dp; // dp points to a double (double-pointer)
double *fun(int, int) // fun is a function that takes two ints and returns a double-
pointer
double f(int, int); // f is a function that takes two ints and returns a double
fp = f; // Assign function f to fp function-pointer
Example
/* Test Function Pointers (TestFunctionPointer.cpp) */
#include <iostream>
using namespace std;
int arithmetic(int, int, int (*)(int, int));
22
int arithmetic(int n1, int n2, int (*operation) (int, int)) {return
(*operation)(n1, n2);
}
int main() {
int number1 = 5, number2 = 6;
// add
cout << arithmetic(number1, number2, add) << endl;
// subtract
cout << arithmetic(number1, number2, sub) << endl;
}
17.2 Constant Pointer vs. Constant Pointed-to Data
1. Non-constant pointer to constant data: Data pointed to CANNOT be changed; but pointer
CANbe changed to point to another data. For example,
int i1 = 8, i2 = 9;
const int * iptr = &i1; // non-constant pointer pointing to constant data
// *iptr = 9; // error: assignment of read-only location
int i1 = 8, i2 = 9;
int * const iptr = &i1; // constant pointer pointing to non-constant data
// constant pointer must be initialized during declaration
*iptr = 9; // okay
// iptr = &i2; // error: assignment of read-only variable
3. Constant pointer to constant data: Data pointed to CANNOT be changed; and pointer
CANNOTbe changed to point to another data. For example,
int i1 = 8, i2 = 9;
const int * const iptr = &i1; // constant pointer pointing to constant data
// *iptr = 9; // error: assignment of read-only variable
// iptr = &i2; // error: assignment of read-only variable
4. Non-constant pointer to non-constant data: Data pointed to CAN be changed; and pointer
CANbe changed to point to another data. For example,
int i1 = 8, i2 = 9; 23
int * iptr = &i1; // non-constant pointer pointing to non-constant data
*iptr = 9; // okay
iptr = &i2; // okay
24
Chapter:9
Classes,Encapsulation
object. Member
Example
ob1.set_a(10);
The private members of a class cannot be accessed directly using the dot operator, but
through the member functions of that class providing data hiding. A member function can call
another member function directly, without using the dot operator.
C++ program to find sum of two numbers using classes
#include<iostream.h>
#include<conio.h>
class A{
int a,b,c;
public:
void sum(){
cout<<"enter two numbers";
cin>>a>>b;
c=a+b;
cout<<"sum="<<c;
}
};
int main(){
A u;
u.sum();
getch();
return(0);
}
Scope Resolution operator
Member functions can be defined within the class definition or separately using scope
resolution operator (::). Defining a member function within the class definition declares the
function inline, even if you do not use the inline specifier. Defining a member function using
scope resolution operator uses following declaration
return-type class-name::func-name(parameter- list) {
// body of function
}
Here the class-name is the name of the class to which the function belongs. The scope
resolution operator (::) tells the compiler that the function func-name belongs to the class class-
name. That is, the scope of the function is restricted to the class-name specified.
Class myclass {
int a;
public:
void set_a(intnum); //member function declaration
int get_a( ); //member function declaration
};
//member function definition outside class using scope resolution operator
void myclass :: set_a(intnum)
{
a=num;
}
int myclass::get_a( ) {
return a;
}
Another use of scope resolution operator is to allow access to the global version of a
variable. In many Situations, it happens that the name of global variable and the name of the
local variable are same. In this while accessing the variable, the priority is given to the local
variable by the compiler. If we want to access or use the global variable, then the scope
resolution operator (: :) is used. The syntax for accessing a global variable using scope
resolution operator is as follows: -
: Global-variable-name
To do this:
1) Make all the data members private.
2) Create public setter and getter functions for each data member in such a way that the set
function set the value of data member and get function get the value of data member.
Here we have two data members num and ch, we have declared them as private so that they
are not accessible outside the class, this way we are hiding the data. The only way to get and
set the values of these data members is through the public getter and setter functions.
#include<iostream>
using namespace std;
class ExampleEncap{
private:
/* Since we have marked these data members private,
* any entity outside this class cannot access these
* data members directly, they have to use getter and
* setter functions.
*/
int num;
char ch;
public:
/* Getter functions to get the value of data members.
* Since these functions are public, they can be accessed
* outside the class, thus provide the access to data members
* through them
*/
int getNum() const {
return num;
}
char getCh() const {
return ch;
}
/* Setter functions, they are called for assigning the values
* to the private data members.
*/
void setNum(int num) {
this->num = num;
}
void setCh(char ch) {
this->ch = ch;
}
};
int main(){
ExampleEncap obj;
obj.setNum(100);
obj.setCh('A');
cout<<obj.getNum()<<endl;
cout<<obj.getCh()<<endl;
return 0;
}
Output:
100
A
Chapter:10 Constructors
Let us first understand some basic points that you should aware of before knowing
about shallow copy and deep copy in details.
How can we create a copy of an object?
1. Default copy constructor is defined by the compiler when object of any class is
created and there is no copy constructor defined in the program.
#include<iostream>
class DummyClass
private:
public:
num1 = x;
num2 = y;
void showData()
cout << num1 << " " << num2 << endl;
};
int main()
DummyClass D1;
D1.setData(5, 11);
D1.showData();
DummyClass D3;
D3.setData(1, 11);
D3.showData();
DummyClass D4;
return 0;
Output:
5 11
5 11
1 11
1 11
In the above example, object D4 is created and then it is initialized with object D3. In
this case, copy assignment operator which is overloaded by compiler itself is implemented.
Points To Remember:-
When you initialize an object with another object of same class during its
declaration, copy constructor will be called.
For Example:-
#include<iostream>
class DummyClass {
private:
public:
num1 = x;
num2 = y;
}
void showData() {
cout << num1 << " " << num2 << endl;
};
int main() {
DummyClass D1;
D1.setData(5, 11);
D1.showData();
DummyClass D2 = D1;
D2.showData();
For Example:-
#include<iostream>
private:
public:
num1 = x;
num2 = y;
void showData() {
cout << num1 << " " << num2 << endl;
};
int main() {
DummyClass D1;
D1.setData(5, 11);
D1.showData();
DummyClass D2;
D2 = D1;
D4.showData();
}
Deep Copy and Shallow Copy in C++
1. Creating a copy of object by copying data of all member variables as it is, it is
called shallow copy. The compiler will do shallow copy by default.
2. Creating an object by copying data of another object along with the values of memory
resources resides outside the object but handled by that object, it is called deep copy.
#include<iostream>
class DummyClass {
private:
int *ptr;
public:
DummyClass() {
num1 = x;
num2 = y;
*ptr = z;
}
void showData() {
cout << "A = " << num1 << " B = " << num2 << endl;
DummyClass(DummyClass &D) {
num1 = D.num1;
num2 = D.num2;
*ptr = *(D.ptr);
~DummyClass() {
delete ptr;
};
int main() {
DummyClass D1;
D1.setData(3, 5, 11);
D1.showData();
//Copy constructor declared above will came in action and do deep copy.
DummyClass D2 = D1;
D2.showData();
Output:
A=3 B=5
A=3 B=5
Overloading-this' Pointer
Structs vs Classes
Friends of a class
Operator Overloading
Friend function
In general, only other members of a class have access to the private members of
the class. However, it is possible to allow a non-member function access to the private
members of a class by declaring it as a friend of the class. To make a function a friend
of a class, you include its prototype in the class declaration and precede it with the
friend keyword. The function is declared with friend keyword. But while defining
friend function, it does not use either keyword friend or :: operator. A function can be
a friend of more than one class. Member function of one class can be friend functions
of another class.
In such cases they are defined using the scope resolution operator.
A friend, function has following characteristics.
It is not in the scope of the class to which it has been declared as friend.
A friend function cannot be called using the object of that class. If can be invoked
like a normal function without help of any object.
It cannot access the member variables directly & has to use an object name dot
membership operator with member name.
It can be declared either in the public or the private part of a class without affecting
its meaning.
Usually, it has the object as arguments.
Program to illustrate use of friend function
#include<iostream.h>
#include<conio.h>
class A{
int x, y;
public:
friend void display(A &obj);
void getdata() {
cin>>x>>y;
}
};
void display(A &obj){
cout<<obj.x<<obj.y;
}
int main(){
A a;
a.getdata();
display(a);
getch();
return 0;
}
Operator overloading
There is another useful methodology in C++ called operator overloading. The
language allows not only functions to be overloaded, but also most of the operators,
such as +, -, *, /, etc. As the name suggests, here the conventional operators can be
programmed to carry out more complex operations.
This overloading concept is fundamentally the same i.e. the same operators can
be made to perform different operations depending on the context. Such operators have
to be specifically defined and appropriate function programmed. When an operator is
overloaded, none of its original meaning is lost. It is simply that a new operation,
relative to a specific class, is defined. For example, a class that defines a linked list
might use the + operator to add an object to the list. A class that implements a stack
might use the + to push an object onto the stack.
An operator function defines the operations that the overloaded operator will
perform relative to the class upon which it will work. An operator function is created
using the keyword operator. The general form of an operator function is
type classname::operator#(arg-list) { // operations
}
Here, the operator that you are overloading is substituted for the #, and type is
the type of value returned by the specified operation. Operator functions can be either
members or non-members of a class. Non-member operator functions are often friend
functions of the class.
These operators cannot be overloaded:- ., : :, .*, ?
The process of overloading involves the following steps:
Create a class that defines the data type that is to be used in the overloading operation.
Declare the operator function operator op() in the public part of the class.
Define the operator function to implement the required operations.
Overloading a unary operator using member function
Overloading a unary operator using a member function, the function takes no
parameters. Since, there is only one operand, it is this operand that generates the call to
the operator function. There is no need for another parameter.
Overloading unary minus operator
#include<iostream.h>
#include<conio.h>
class A {
int x,y,z;
public:
void getdata(int a,int b,int c) {
x=a;
y=b;
z=c;
}
void display() {
cout<<"\nx="<<x<<"\ny="<<y<<"\nz="<<z;
}
void operator -() //unary minus overload function
{
x=-x;
y=-y;
z=-z;
}
};
int main() {
A a;
a.getdata(2,3,4);
a.display();
-a; //activates operator –() function
a.display();
getch();
return 0;
}
Inheritance
Overloading vs overriding
Inheritance
Inheritance is the mechanism by which one class can inherit the properties of
another. It allows a hierarchy of classes to be build, moving from the most general to
the most specific. When one class is inherited by another, the class that is inherited is
called the base class. The inheriting class is called the derived class. In general, the
process of inheritance begins with the definition of a base class. The base class defines
all qualities that will be common to any derived class. In essence, the base class
represent the most general description of a set of traits. The derived class inherits those
general traits and adds properties that are specific to that class. When one class inherits
another, it uses this general
form:
class derived-class-name : access base-class-name{
// ...
}
Here access is one of the three keywords: public, private, or protected. The
access specifier determines how elements of the base class are inherited by the derived
class. When the access specifier for the inherited base class is public, all public
members of the base class become public members of the derived class. If the access
specifier is private, all public members of the base class become private members of
the derived class. In either case, any private members of the base class remain private
to it and are inaccessible by the derived class.
It is important to understand that if the access specifier is private, public
members of the base become private members of the derived class. If the access
specifier is not present, it is private by default.
The protected access specifier is equivalent to the private specifier with the sole
exception that
protected members of a base class are accessible to members of any class
derived from that base. Outside the base or derived classes, protected members are not
accessible. When a protected member of a base class is inherited as public by the
derived class, it becomes a protected member of the derived class. If the base class is
inherited as private, a protected member of the base becomes a private member of the
derived class. A base class can also be inherited as protected by a derived class.
When this is the case, public and protected members of the base class become
protected members of the derived class (of course, private members of the base remain
private to it and are not accessible by the derived class).
Program to illustrate concept of inheritance
#include<iostream.h>
#include<conio.h>
class base //base class
{
int x,y;
public:
void show() {
cout<<"In base class";
}
};
class derived : public base //derived class
{
int a,b;
public:
void show2() {
cout<<"\nIn derived class";
}
};
int main() {
derived d;
d.show(); //uses base class‟s show() function
d.show2(); //uses derived class‟s show2() function
getch();
return 0;
}
Types of Inheritances
Single Inheritance
The process in which a derived class inherits traits from only one base class, is called
single inheritance. In single inheritance, there is only one base class and one derived class. The
derived class inherits the behavior and attributes of the base class. However the vice versa is
not true. The derivedclass can add its own properties i.e. data members (variables) and
functions. It can extend or use properties of the base class without any modification to the base
class. We declare the base class and derived class as given below:
class base_class {
};
class derived_ class : visibility-mode base_ class {
};
Program to illustrate concept of single inheritance
#include<iostream.h>
#include<conio.h>
class base //base class
{
int x,y;
public:
void show() {
cout<<"In base class";
}
};
class derived : public base //derived class
{
int a,b;
public:
void show2() {
cout<<"\nIn derived class";
}
};
int main() {
derived d;
d.show(); //uses base class‟s show() function
d.show2(); //uses derived class‟s show2() function
getch();
return 0;
}
Ambiguity in single Inheritance
Whenever a data member and member functions are defined with the same
name in both the base and derived class, ambiguity occurs. The scope resolution
operator must be used to refer to particular class
as: object name.class name :: class member
Multiple Inheritance
The process in which a derived class inherits traits from several base classes, is
called multiple inheritance. In Multiple inheritance, there is only one derived class and
several base classes. We declare the base classes and derived class as given below:
class base_class1{
};
class base_class2{
};
class derived_ class : visibility-mode base_ class1 , visibility-mode base_
class2 {
};
Multilevel Inheritance
The process in which a derived class inherits traits from another derived class,
is called Multilevel Inheritance. A derived class with multilevel inheritance is declared
as :
class base_class {
};
class derived_ class1 : visibility-mode base_ class {
};
class derived_ class 2: visibility-mode derived_ class1 {
};
Here, derived_ class 2 inherits traits from derived_ class 1 which itself inherits
from base_class.
Hierarchical Inheritance
The process in which traits of one class can be inherited by more than one class
is known as Hierarchical inheritance. The base class will include all the features that
are common to the derived classes. A derived class can serve as a base class for lower
level classes and so on.
Hybrid Inheritance
The inheritance hierarchy that reflects any legal combination of other types of
inheritance is known as hybrid Inheritance.
Overriding
Overriding is defined as the ability to change the definition of an inherited
method or attribute in a derived class. When multiple functions of the same name exist
with different signatures it is called function overloading. When the signatures are the
same, they are called function overriding. Function
overriding allows a derived class to provide specific implementation of a
function that is already provided by a base class. The implementation in the derived
class overrides or replaces the implementation in the corresponding base class.
Virtual base classes
A potential problem exists when multiple base classes are directly inherited by
a derived class. To understand what this problem is, consider the following class
hierarchy:
Here the base class Base is inherited by both Derived1and Derived2. Derived3
directly inherits both Derived1and Derived2.However, this implies that Base is actually
inherited twice by Derived3.First it is inherited through Derived1, and then again
through Derived2.This causes ambiguity when a member of Base is used by Derived3.
Since two copies of Base are included in Derived3, is a reference to a member of Base
referring to the Base inherited indirectly through Derived1or to the Base inherited
indirectly through Derived2? To resolve this ambiguity, C++ includes a mechanism by
which only one copy of Base will be included in Derived3. This feature is called a
virtual base class.
In situations like this, in which a derived class indirectly inherits the same base
class more than once, it is possible to prevent multiple copies of the base from being
present in the derived class by having that base class inherited as virtual by any derived
classes. Doing this prevents two or more copies of the base from being present in any
subsequent derived class that inherits the base class indirectly. The virtual keyword
precedes the base class access specifier when it is inherited by a derived class.
// This program uses a virtual base class.
#include <iostream>
using namespace std;
class Base {
public:
int i;
};
// Inherit Base as virtual
classDerived1 : virtual publicBase {
public:
int j;
};
// Inherit Base as virtual here, too
classDerived2 : virtual publicBase {
public:
int k;
};
// Here Derived3 inherits both Derived1 and Derived2.
// However, only one copy of base is inherited.
class Derived3 : publicDerived1, publicDerived2 {
public:
int product( ) { return i*j*k; }
};
int main( ) {
Derived3 ob;
ob.i = 10; // unambiguous because virtual Base
ob.j = 3;
ob.k = 5;
cout << "Product is: " << ob.product( ) << "\n";
return 0;
}
If Derived1and Derived2 had not inherited Base as virtual, the statement
ob.i=10 would have been ambiguous and a compile-time error would have resulted. It
is important to understand that when a base class is inherited as virtual by a derived
class, that base class still exists within that derived class.
For example, assuming the preceding program, this fragment is perfectly valid:
Derived1 ob;
ob.i = 100;
Friend Classes
It is possible for one class to be a friend of another class. When this is the case,
the friend class and all of its member functions have access to the private members
defined within the other class. For
example,
// Using a friend class.
#include<iostream.h>
#include<conio.h>
class A{
int x, y;
public:
friend void display(A &obj);
friend class B;
void getdata() {
cin>>x>>y;
}
};
class B{
int p,q;
public:
void get(A &obj) {
p=obj.x;
q=obj.y;
}
};
void display(A &obj){
cout<<obj.x<<obj.y;
}
int main(){
A a;
B b;
b.get(a);
a.getdata();
display(a);
getch();
return 0;
}
It is critical to understand that when one class is a friend of another, it only has
access to names defined within the other class. It does not inherit the other class.
Specifically, the members of the first class do not become members of the friend class.
Chapter:13 Polymorphism
Polymorphism
Virtual Functions
Pure Virtual Functions and
Abstract Classes.
Polymorphism in C++
The word polymorphism means having many forms. In simple words, we can define
polymorphism as the ability of a message to be displayed in more than one form.
Real life example of polymorphism, a person at the same time can have different
characteristic. Like a man at the same time is a father, a husband, an employee. So the same
person posses different behavior in different situations. This is called polymorphism.
Polymorphism is considered as one of the important features of Object Oriented
Programming.
In C++ polymorphism is mainly divided into two types:
Compile time Polymorphism
Runtime Polymorphism
Function Overloading: When there are multiple functions with same name but
different parameters then these functions are said to be overloaded. Functions can
be overloaded by change in number of arguments or/and change in type of
arguments.
using namespace
std; class Geeks
{
public:
int main() {
Geeks
obj1;
In the above example, a single function named func acts differently in three
different situations which is the property of polymorphism.
class
Complex {
private:
int real,
imag; public:
Complex(int r = 0, int i =0) {real = r; imag = i;}
// This is automatically called when '+' is used with
// between two Complex objects
Complex operator + (Complex const &obj) {
Complex res;
res.real = real +
obj.real; res.imag =
imag + obj.imag; return
res;
}
void print() { cout << real << " + i" << imag << endl; }
};
int main()
{
Complex c1(10, 5), c2(2, 4);
Complex c3 = c1 + c2; // An example call to
"operator+" c3.print();
}
Output:
12 + i9
In the above example the operator „+‟ is overloaded. The operator „+‟ is an
addition operator and can add two numbers(integers or floating point) but here the
operator is made to perform addition of two imaginary or complex numbers. To
learn operator overloading in details visit this link.
#include
<bits/stdc++.h>
using namespace
std;
class base
{
public:
virtual void print ()
{ cout<< "print base class" <<endl; }
void show ()
{ cout<< "show base class" <<endl; }
};
void show ()
{ cout<< "show derived class" <<endl; }
};
//main
function int
main()
{
base
*bptr;
derived
d; bptr =
&d;
return 0;
}
Output:
print derived class
show base class
Virtual Function in C++
A virtual function is a member function which is declared within a base class and is re-
defined(Overriden) by a derived class. When you refer to a derived class object using a
pointer or a reference to the base class, you can call a virtual function for that object and
execute the derived class‟s version of the function.
Virtual functions ensure that the correct function is called for an object, regardless of
the type of reference (or pointer) used for function call.
They are mainly used to achieve Runtime polymorphism
Functions are declared with a virtual keyword in base class.
The resolving of function call is done at Run-time.
#include
<iostream> using
namespace std;
class base
{ public:
virtual void print()
{
cout << "print base class" << endl;
}
void show()
{
cout << "show base class" << endl;
}
};
void show()
{
cout << "show derived class" << endl;
}
};
int main()
{
base*
bptr;
derived
d; bptr =
&d;
NOTE: If we have created a virtual function in the base class and it is being overridden in the
derived class then we don‟t need virtual keyword in the derived class, functions are
automatically considered as virtual functions in the derived class.
Working of virtual functions(concept of VTABLE and VPTR)
As discussed here, If a class contains a virtual function then compiler itself does two things:
1. If object of that class is created then a virtual pointer(VPTR) is inserted as a data
member of the class to point to VTABLE of that class. For each new object created, a
new virtual pointer is inserted as a data member of that class.
2. Irrespective of object is created or not, a static array of function pointer called
VTABLE where each cell contains the address of each virtual function contained in
that class.
Consider the example below:
class base
{public:
void fun_1() { cout << "base-1\n"; }
virtual void fun_2() { cout << "base-
2\n"; } virtual void fun_3() { cout <<
"base-3\n"; } virtual void fun_4() { cout
<< "base-4\n"; }
};
int main()
{
base* p;
derived
obj1;
p = &obj1;
// Late binding
(RTP)p->fun_2();
// Late binding
(RTP)p->fun_3();
// Late binding
(RTP)p->fun_4();
Explanation: Initially, we create a pointer of type base class and initialize it with the address
of the derived class object. When we create an object of the derived class, the compiler
creates a pointer as a data member of the class containing the address of VTABLE of the
derived class.
Similar concept of Late and Early Binding is used as in above example. For fun_1()
function call, base class version of function is called, fun_2() is overridden in derived class so
derived class version is called, fun_3() is not overridden in derived class and is virtual
function so base class version is called, similarly fun_4() is not overridden so base class
version is called.
NOTE: fun_4(int) in derived class is different from virtual function fun_4() in base class as prototype
of both the function is different.
A pure virtual function (or abstract function) in C++ is a virtual function for which we don‟t
have implementation, we only declare it. A pure virtual function is declared by assigning 0 in
declaration. See the following example.
// An abstract
classclass Test
{
// Data members of
classpublic:
// Pure Virtual Function
virtual void show() = 0;
/* Other members */
};
A complete example:
A pure virtual function is implemented by classes which are derived from a Abstract class.
Following is a simple example to demonstrate the same.
#include<iostream>
using namespace std;
class Base
{
int
x;
public
:
virtual void fun() = 0;
int getX() { return x;
}
};
int main(void)
{
Derived
d;d.fun();
return 0;
}
Output:
fun() called
Chapter:14 Abstract Classes
By definition, an abstract class in C++ is a class that has at least one pure virtual
function (i.e., a function that has no definition). The classes inheriting the abstract
class must provide a definition for the pure virtual function; otherwise, the subclass would
become an abstract class itself.
Consider an example of a Shape base class with sub-classes (Triangle and Rectangle)
that inherit the Shape class.
Now, suppose we need a function to return the area of a shape. The function will be
declared in the Shape class; however, it cannot be defined there as the formula for the area is
different for each shape. A non-specific shape does not have an area, but rectangles and
triangles do. Therefore, the pure virtual function for calculating area will be implemented
differently by each sub-class.
The following code snippet implements the abstract Shape class along with its sub-classes:
#include <iostream>
class Shape {
public:
virtual int Area() = 0; // Pure virtual function is declared as follows.
// Function to set width.
void setWidth(int w) {
width = w;
}
// Function to set height.
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
int main() {
Rectangle R;
Triangle T;
R.setWidth(5);
R.setHeight(10);
T.setWidth(20);
T.setHeight(8);
cout << "The area of the rectangle is: " << R.Area() << endl;
cout << "The area of the triangle is: " << T.Area() << endl;
}
Chapter:15
Exception and File Handling
Exception
Files, Streams
I/O
1
C++ Exception Handling
An exception is a problem that arises during the execution of a program. A C++ exception is a response to
an exceptional circumstance that arises whilea program is running, such as an attempt to divide by zero.
Exceptions provide a way to transfer control from one part of a program to another. C++ exception
handling is built upon three keywords: try, catch, and throw.
throw: A program throws an exception when a problem shows up. This is done using a throw
keyword.
catch: A program catches an exception with an exception handler at the place in a program where
you want to handle the problem. The catch keyword indicates the catching of an exception.
try: A try block identifies a block of code for which particular exceptions will be activated. It's
followed by one or more catch blocks.
Assuming a block will raise an exception, a method catches an exception usinga combination of the try and
catch keywords. A try/catch block is placed around the code that might generate an exception. Code within
a try/catch block is referred to as protected code, and the syntax for using try/catch lookslike the following:
try
// protected code
}catch( ExceptionName e1 )
1
// catch block
}catch( ExceptionName e2 )
// catch block
}catch( ExceptionName eN )
// catch block
You can list down multiple catch statements to catch different type of exceptions in case your try block
raises more than one exception in different situations.
ThrowingExceptions:
Exceptions can be thrown anywhere within a code block using throw statements. The operand of the throw
statements determines a type for the exception and can be any expression and the type of the result of the
expression determines the type of exception thrown.
if( b == 0 )
return (a/b);
2
}
Catching Exceptions:
The catch block following the try block catches any exception. You can specifywhat type of exception you
want to catch and this is determined by the exception declaration that appears in parentheses following the
keyword catch.
try
// protected code
}catch(
try ExceptionName e )
{
{
//
//code to handle
protected codeExceptionName exception
}
}catch(...)
Above code will catch an exception of ExceptionName type. If you want to specify that a catch block
should handle any type of exception that is thrownin a try block, you must put an ellipsis, ..., between the
parentheses enclosing the exception declaration as follows:
3
The following is an example, which throws a division by zero exception and wecatch it in catch block.
#include <iostream>
if( b == 0 )
return (a/b);
int main ()
int x = 50;
int y = 0;
double z = 0;
try {
z = division(x, y);
4
cout << z << endl;
5
return 0;
Because we are raising an exception of type const char*, so while catching this exception, we have to use
const char* in catch block. If we compile and run above code, this would produce the following result:
6
C++StandardExceptions:
C++ provides a list of standard exceptions defined in <exception> which we can use in our programs.
These are arranged in a parent-child class hierarchy shown below:
Exception Description
std::exception An exception and parent class of all the standard C++ exceptions.
7
std::bad_alloc This can be thrown by new.
std::out_of_range This can be thrown by the at method from for example a std::vectorand
std::bitset<>::operator[]().
std::range_error This is occured when you try to store a value which is out of range.
8
DefineNewExceptions:
You can define your own exceptions by inheriting and overriding exception class functionality. Following
is the example, which shows how you can use std::exception class to implement your own exception in
standard way:
#include <iostream>
#include <exception>
};
int main()
try
throw MyException();
catch(MyException& e)
9
}
catch(std::exception& e)
//Other errors
MyException caught
C++ Exception
Here, what() is a public method provided by exception class and it has been overridden by all the child
exception classes. This returns the cause of an exception.
10
2
C++ Templates
Templates are the foundation of generic programming, which involves writing code in a way that is
independent of any particular type.
A template is a blueprint or formula for creating a generic class or a function. The library containers like
iterators and algorithms are examples of generic programming and have been developed using template
concept.
There is a single definition of each container, such as vector, but we candefine many different kinds
of vectors for example, vector <int> or vector
<string>.
You can use templates to define functions as well as classes, let us see how dothey work:
FunctionTemplate:
The general form of a template function definition is shown here:
// body of function
Here, type is a placeholder name for a data type used by the function. Thisname can be used within the
function definition.
The following is the example of a function template that returns the maximumof two values:
#include <iostream>
#include <string>
11
using namespace std;
int main ()
int i = 39;
int j = 20;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello";
string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
12
return 0;
If we compile and run above code, this would produce the following result:
13
Max(i, j): 39
ClassTemplate:
Just as we can define function templates, we can also define class templates.The general form of a generic
class declaration is shown here:
Here, type is the placeholder type name, which will be specified when a class is instantiated. You can
define more than one generic data type by using a comma-separated list.
Following is the example to define class Stack<> and implement generic methods to push and pop the
elements from the stack:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
14
template <class T>
class Stack {
private:
public:
return elems.empty();
};
elems.push_back(elem);
15
void Stack<T>::pop ()
if (elems.empty()) {
16
// remove last element
elems.pop_back();
T Stack<T>::top () const
if (elems.empty()) {
return elems.back();
int main()
try {
intStack.push(7);
17
cout << intStack.top() <<endl;
stringStack.push("hello");
18
stringStack.pop();
stringStack.pop();
return -1;
If we compile and run above code, this would produce the following result:
hello
19
FILES IN C++
C++ provides the following classes to perform output and input of characters to/from files:
These classes are derived directly or indirectly from the classes istream, and ostream. We
have already used objects whose types were these classes: cin is an object of class istream
and cout is an object of class ostream. Therfore, we have already been using classes that are
related to our file streams. And in fact, we can use our file streams the same way we are
already used to use cin and cout, with the only difference that we have to associate these
streams with physical files. Let's see an example:
int main ()
{
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}
This code creates a file called example.txt and inserts a sentence into it in the same way we
are used to do with cout, but using the file stream myfile instead.
Open a file
The first operation generally performed on an object of one of these classes is to associate it
to a real file. This procedure is known as to open a file. An open file is represented within a
program by a stream object (an instantiation of one of these classes, in the previous example
this was myfile) and any input or output operation performed on this stream object will be
applied to the physical file associated to it.
In order to open a file with a stream object we use its member function open():
Where filename is a null-terminated character sequence of type const char * (the same type
that string literals have) representing the name of the file to be opened, and mode is an
optional parameter with a combination of the following flags:
All these flags can be combined using the bitwise operator OR (|). For example, if we want to
open the file example.bin in binary mode to add data we could do it by the following call to
member function open():
ofstream myfile;
myfile.open ("example.bin", ios::out | ios::app | ios::binary);
Each one of the open() member functions of the classes ofstream, ifstream and fstream has a
default mode that is used if the file is opened without a second argument:
For ifstream and ofstream classes, ios::in and ios::out are automatically and respectivelly
assumed, even if a mode that does not include them is passed as second argument to the
open() member function.
The default value is only applied if the function is called without specifying any value for the
mode parameter. If the function is called with any value in that parameter the default mode is
overridden, not combined.
File streams opened in binary mode, perform input and output operations independently of
any format considerations. Non-binary files are known as text files, and some translations
may occur due to formatting of some special characters (like newline and carriage return
characters)
Since the first task that is performed on a file stream object is generally to open a file, these
three classes include a constructor that automatically calls the open() member function and
has the exact same parameters as this member. Therefor, we could also have declared the
previous myfile object and conducted the same opening operation in our previous example by
writing:
Combining object construction and stream opening in a single statement. Both forms to open
a file are valid and equivalent.
To check if a file stream was successful opening a file, you can do it by calling to member
is_open() with no arguments. This member function returns a bool value of true in the case
that indeed the stream object is associated with an open file, or false otherwise:
Closing a file
When we are finished with our input and output operations on a file we shall close it so that
its resources become available again. In order to do that we have to call the stream's member
function close(). This member function takes no parameters, and what it does is to flush the
associated buffers and close the file:
myfile.close();
Once this member function is called, the stream object can be used to open another file, and
the file is available again to be opened by other processes.
In case that an object is destructed while still associated with an open file, the destructor
automatically calls the member function close().
Text files
Text file streams are those where we do not include the ios::binary flag in their opening
mode. These files are designed to store text and thus all values that we input or output from/to
them can suffer some formatting transformations, which do not necessarily correspond to
their literal binary value.
Data output operations on text files are performed in the same way we operated with cout:
int main () {
ofstream myfile ("example.txt");
if (myfile.is_open())
{
myfile << "This is a line.\n";
myfile << "This is another line.\n";
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
[file example.txt]
This is a line.
This is another line.
Data input from a file can also be performed in the same way that we did with cin:
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while (! myfile.eof() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
return 0;
}
This is a line.
This is another line.
This last example reads a text file and prints out its content on the screen. Notice how we
have used a new member function, called eof() that returns true in the case that the end of the
file has been reached. We have created a while loop that finishes when indeed myfile.eof()
becomes true (i.e., the end of the file has been reached).
bad()
Returns true if a reading or writing operation fails. For example in the case that we try to
write to a file that is not open for writing or if the device where we try to write has no space
left.
fail()
Returns true in the same cases as bad(), but also in the case that a format error happens, like
when an alphabetical character is extracted when we are trying to read an integer number.
eof()
Returns true if a file open for reading has reached the end.
good()
It is the most generic state flag: it returns false in the same cases in which calling any of the
previous functions would return true.
In order to reset the state flags checked by any of these member functions we have just seen
we can use the member function clear(), which takes no parameters.
ofstream, like ostream, has a pointer known as the put pointer that points to the location
where the next element has to be written.
Finally, fstream, inherits both, the get and the put pointers, from iostream (which is itself
derived from both istream and ostream).
These internal stream pointers that point to the reading or writing locations within a stream
can be manipulated using the following member functions:
Using this prototype the stream pointer is changed to the absolute position position (counting
from the beginning of the file). The type for this parameter is the same as the one returned by
functions tellg and tellp: the member type pos_type, which is an integer value.
Using this prototype, the position of the get or put pointer is set to an offset value relative to
some specific point determined by the parameter direction. offset is of the member type
off_type, which is also an integer type. And direction is of type seekdir, which is an
enumerated type (enum) that determines the point from where offset is counted from, and that
can take any of the following values:
The following example uses the member functions we have just seen to obtain the size of a
file:
int main () {
long begin,end;
ifstream myfile ("example.txt");
begin = myfile.tellg();
myfile.seekg (0, ios::end);
end = myfile.tellg();
myfile.close();
cout << "size is: " << (end-begin) << " bytes.\n";
return 0;
}
size is: 40 bytes.
Chapter:16 STL and Lambda
Lambda Expression.
Functions – STL
Generic Programming
1
1 Introduction 3
2
1 Introduction
Lambda expressions are an important feature in modern C++.
The goal of ”Lambda Expressions in C++14 and C++17
(part 1)” is to give a basic overview of lambda expressions
covering benefits and pitfalls when using them.
Since the vocabulary associated with lambdas can be confusing
let us take a look at a brief refresher from [Mey14]
• A lambda expression is just that: an expression. It‟s part of
the source code.
std::find_if(container.begin(), container.end(),
[](int val) { return 1 < val && val < 10; }
);
3
bool multiple_of_5(int value){
return value % 5 == 0;
}
//...
void do_work() {
auto numbers = std::vector<int>();
//...
4
std::remove_if(
numbers.begin(), numbers.end(),
multiple_of_5
);
//...
}
6
return value % divisor == 0;
}
private:
int divisor;
};
void do_work() {
auto numbers = std::vector<int>();
//...
auto divisor = calc_divisor(...);
//Closure (Object)
auto multiple_of_divisor = MultipleOf(divisor);
std::remove_if(
numbers.begin(), numbers.end(),
multiple_of_divisor
);
//...
}
7
void do_work() {
auto numbers = std::vector<int>();
//...
auto divisor = calc_divisor(...);
std::remove_if(
numbers.begin(), numbers.end(),
[divisor](const int value) {
return value % divisor == 0;
}
);
//...
}
8
3 Default Capture Modes
Since the addition of lambda expressions in C++11 there are two
default capture modes: by-reference and by-value. Capturing local
variables can lead to dan- gling references. Using the default by-
value capture mode gives the impression that a lambda expression
is self-contained although it might result in dangling pointers or
referenced variables. This section covers why default capture
modes should be not be used and offers solutions to avoid the
problems mentioned above.
void add_filter() {
//...
auto divisor = calc_divisor(...);
filters.emplace_back(
void Widget::add_filter() {
filters.emplace_back(
[=](const int value) {
return value % divisor == 0; //this pointer
//might dangle
}
);
}
Although this might look like divisor is copied in reality the objects
this pointer is captured by-value. If the closure outlives the Widget
object which created it the this pointer will dangle. This is because
lambdas can only capture local variables and parameters from the
scope they are defined in. It is actually impossible to capture data
members directly. A solution to this problem is to copy the data
member to a local variable and capturing that by value. A better
void Widget::add_filter() {
filters.emplace_back(
[divisor = divisor](const int value) {
return value % divisor == 0;
}
);
}
way to solve this is to use the generalized lambda capture
introduced in C++14 as it avoids the definition of an otherwise
unused local variable.
void add_filter(){
static int divisor = 5;
filters.emplace_back(
[=](const int value) { //this captures nothing
return value % divisor == 0; //divisor
//directly refers to static variable.
}
);
++divisor;
}
when a function has a static local variable.
12
Instead of capturing the value of divisor the standard states that the
lambda expression directly refers to the static variable which means that
the filter function will return multiples of six or whatever the current
value of the static variable is when the filter function is called. A
solution to this would be again to use the generalized lambda capture
syntax.
3.3 Summary
Avoid default capture modes because:
• Default by-reference capture can lead to dangling references.
• Default by-value capture
– is susceptible to dangling pointers (especially this).
– misleadingly suggests that lambdas are self-contained (static vari-
ables).
void add_filter(){
//...
auto numbers =
produce_many_numbers(...);
filters.emplace_back(
[numbers=std::move(numbers)](const int value) {
//...
}
);
}
void add_filter(){
//...
filters.emplace_back(
[numbers=std::make_unique<Gadget>()]
(const int value) {
//...
}
);
std::bind.
} Using the generalized lambda capture this can be easily
achieved
Introduction to STL: Standard Template Library
STL is an acronym for standard template library. It is a set of C++ template classes that
provide generic classes and function that can be used to implement data structures and
algorithms. STL is mainly composed of:
1. Algorithms
2. Containers
3. Iterators
STL provides numerous containers and algorithms which are very useful in completive
programming, for example you can very easily define a linked list in a single statement by
using list container of container library in STL, saving your time and effort.
STL is a generic library, i.e a same container or algorithm can be operated on any data types,
you don‟t have to define the same algorithm for different type of elements.
For example, sort algorithm will sort the elements in the given range irrespective of their data
type , we don‟t have to implement different sort algorithm for different datatypes.
C++: Algorithms in STL
STL provide number of algorithms that can be used of any container, irrespective of their type.
Algorithms library contains built in functions that performs complex algorithms on the data
structures.
For example: one can reverse a range with reverse() function, sort a range with sort() function,
search in a range with binary_search() and so on.
Algorithm library provides abstraction, i.e you don't necessarily need to know how the the
algorithm works.
Container library in STL provide containers that are used to create data structures like
arrays, linked list, trees etc.
These container are generic, they can hold elements of any data types, for
example: vector can be used for creating dynamic arrays of char, integer, float and other types.
Iterators in STL are used to point to the containers. Iterators actually acts as a bridge
between containers and algorithms.
For example: sort () algorithm have two parameters, starting iterator and ending
iterator, now sort () compare the elements pointed by each of these iterators and arrange them
in sorted order, thus it does not matter what is the type of the container and same sort() can be
used on different types of containers.
STL being generic library provide containers and algorithms which can be used to store
and manipulate different types of data thus it saves us from defining these data structures and
algorithms from the scratch. Because of STL, now we do not have to define our sort function
every time we make a new program or define same function twice for the different data types,
instead we can just use the generic container and algorithms in STL.
This saves a lot of time, code and effort during programming, thus STL is heavily used
in the competitive programming, plus it is reliable and fast.
What are Containers in STL?
Containers Library in STL gives us the Containers, which in simplest words, can be
described as the objects used to contain data or rather collection of object. Containers help us
to implement and replicate simple and complex data structures very easily like arrays, list,
trees, associative arrays and many more.
The containers are implemented as generic class templates, means that a container can
be used to hold different kind of objects and they are dynamic in nature!
Sequence containers : Used to implement data structures that are sequential in nature
like arrays(array) and linked list(list).
Associative containers : Used to implement sorted data structures such as map, set etc.
Below is an example of implementing linked list, first by using structures and then by
list containers.
#include <iostream>
struct node
int data;
int main ()
The above program is only creating a list node, no insertion and deletion functions are
defined, to do that, you will have to write more line of code.
Now lets see how using Container Library simplifies it. When we use list containers to
implement linked list we just have to include the list header file and use list constructor to
initialize the list.
#include <iostream>
#include <list>
int main ()
list<int> list1;
And that's it! we have a list, and not just that, the containers library also give all the
different methods which can be used to perform different operations on list such as insertion,
deletion, traversal etc.
Thus, you can see that it is incredibly easy to implement data structures by using
Container library.
Although Pair and Tuple are not actually the part of container library but we'll still
discuss them as they are very commonly required in programming competitions and they make
certain things very easy to implement.
Now T1 will be referred as first and T2 will be referred as second member of pair1 and
pair2.
if(pair1 == pair3)
cout<< "Pairs are equal" << endl;
else
cout<< "Pairs are not equal" << endl;
}
TUPLE in STL
tuple and pair are very similar in their structure. Just like in pair we can pair two
heterogeneous object, in tuple we can pair three heterogeneous objects.
Similar to pair, tuple template has its own member and non-member functions, few of which
are listed below :
make_tuple() : creates and return a tuple having elements described by the parameter
list.
#include <iostream>
int main ()
int id;
tie(id,first_name,last_name) = tuple2;
return 0;
}
ARRAY Container in STL
Arrays, as we all know, are collection of homogenous objects. array container in STL
provides us the implementation of static array, though it is rarely used in competitive
programming as its static in nature but we'll still discuss array container cause it provides
some member functions and non-member functions which gives it an edge over the array
defined classically like, int array_name[array_size].
The above code creates an empty array of object_type with maximum size
of array_size. However, if you want to create an array with elements in it, you can do so by
simply using the = operator, here is an example :
#include <vector>
int main()
The above statement will create an array with 2,4,6,8 as data in the array. Note that
initialization with {} brackets is only possible in c++ 17.
Following are the important and most used member functions of array template.
At() function
This method returns value in the array at the given range. If the given range is greater than
the array size, out_of_range exception is thrown. Here is a code snippet explaining the use of
this operator :
#include <iostream>
#include <array>
int main ()
[ ] Operator
The use of operator [ ] is same as it was for normal arrays. It returns the value at the given
position in the array. Example : In the above code, statement cout << array1[5]; would print 6
on console as 6 has index 5 in array1.
front() function
back() function
This method returns the last element in the array. The point to note here is that if the array is
not completely filled, back() will return the rightmost element in the array.
fill() function
This method assigns the given value to every element of the array, example :
#include <array>
int main()
array<int,8> myarray;
myarray.fill(1);
This will fill the array myarray with value as 1, at all of its 8 available positions.
Swap() function
This method swaps the content of two arrays of same type and same size. It swaps index
wise, thus element of index i of first array will be swapped with the element of index i of the
second array, and if swapping any of the two elements thows an execption, swap() throws
exception. Below is an example to demonstrate its usage :
#include <array>
int main()
array<int,8> a = {1,2,3,4,5,6,7,8};
array<int,8> b = {8,7,6,5,4,3,2,1};
a.swap(b) // swaps array a and b
/* ouput will be
a is : 8 7 6 5 4 3 2 1
b is : 1 2 3 4 5 6 7 8 */
All these operators can be used to lexicographically compare values of two arrays.
Empty() function
This method can be used to check whether the array is empty or not.
max_size() function
Begin() function
This method returns the iterator pointing to the first element of the array. Iterators are just
like pointers and we‟ll discuss them later in the lessons, for now you can just think of an
iterator like a pointer to the array.
End() function
This method returns an iterator pointing to an element next to the last element in the array,
for example the above array has 4 elements and the end() call will return the iterator pointing
to the 4th index of the array.
We can do one thing, initialize the array with maximum size allowed by the complier,
i.e. 10^6 elements per array, but that is highly space consuming approach and there is a
wastage of space if number of elements to be entered are way too less, thus this approach is
never used in programming.
Solution of the above problem is dynamic arrays! They have dynamic size, i.e. their size can
change during runtime. Container library provides vectors to replicate dynamic arrays.
For example:
#include <vector>
int main()
std::vector<int> my_vector;
Vector being a dynamic array, doesn't needs size during declaration, hence the above
code will create a blank vector. There are many ways to initialize a vector like,
#include <vector>
int main()
}
Note that this type of initialization works only in C++ 11 and above. You can also
initialize the vector based on the range of other vectors, like :
#include <vector>
int main()
The above code initialize the vector by elements pointed by iterators returned by
v1.begin() and v2.end(), begin() and end() are the same function we have studied with array,
they work same with vectors.
You can also initialize a vector with one element a certain number of times, like :
#include <vector>
int main()
}
These are me of the ways using which you can initialize your vector, but remember,
initializing your vector using another vector or by using elements directly does not limit its
size, its size will always be dynamic, and more elements can be inserted into the vector,
whenever required.
Following are some of the most commonly used functions for vector container in STL:
push_back function
push_back() is used for inserting an element at the end of the vector. If the type of object
passed as parameter in the push_back() is not same as that of the vector or is not
interconvertible an exception is thrown.
#include <vector>
int main()
vector<int> v;
124
insert function
insert(itr, element) method inserts the element in vector before the position pointed by iterator
itr.
The following illustration will show how insert works :
insert function can be overloaded by third argument, count as well. This count parameter
defines how many times the element is to be inserted before the pointed position.
This method can also be used to insert elements from any other vector in given range,
specified by two iterators, defining starting and ending point of the range.
Above code will insert the elements from v2.begin() to v2.end() before index pointed by i.
pop_back function
pop_back() is used to remove the last element from the vector. It reduces the size of the
vector by one.
Below is an example:
#include <iostream>
#include <vector>
int main()
vector<int> v1 {10,20,30,40};
v1.pop_back();
vector<int>::iterator it;
for(it = v.begin(); it != v.end(); it++)
10 20 30
erase function
erase(itr_pos) removes the element pointed by the iterator itr_pos. erase method can also be
overloaded with an extra iterator specifying the end point of the range to be removed,
i.e erase(itr_start, itr_end).
#include <iostream>
#include <vector>
int main()
vecto<int>v1 {10,20,30,40};
vector<int>iterator:: it = v.begin();
v.erase(it); //removes first element from the vector
v.erase(v1.begin(), v1.end() - 2 )
30 40
resize function
resize(size_type n, value_type val) method resizes the vector to n elements. If the current size
of the vector is greater than n then the trailing elements are removed from the vector and if
the current size is smaller than n than extra val elements are inserted at the back of the vector.
For example, If the size of the vector is 4 right now, with elements {10, 20, 30, 40} and we
use resize method to resize it to size 5. Then by default a fifth element with value 0 will be
inserted in the vector. We can specify the data to not be zero, by explicitly mentioning it as
the val while calling the resize method.
swap function
If we have two vectors v1 and v2 and we want to swap the elements inside them, you just
need to call v1.swap(v2), this will swap the values of the two vectors.
clear function
This method clears the whole vector, removes all the elements from the vector but do not
delete the vector.
SYNTAX: clear()
For a vector v, v.clear() will clear it, but not delete it.
size function
empty function
This method returns true if the vector is empty else returns false.
capacity function
This method returns the number of elements that can be inserted in the vector based on the
memory allocated to the vector.
at function
This method works same in case of vector as it works for array. vector_name.at(i) returns the
element at ith index in the vector vector_name.
vector_name.front() retuns the element at the front of the vector (i.e. leftmost element).
While vector_name.back() returns the element at the back of the vector (i.e. rightmost
element).
LIST Container in STL
Array and Vector are contiguous containers, i.e they store their dataon continuous memory,
thus the insert operation at the middle of vector/array is very costly (in terms of number of
operaton and process time) because we have to shift all the elements, linked list overcome
this problem. Linked list can be implemented by using the list container.
Syntax for creating a new linked list using list template is:
#include <iostream>
#include <list>
int main()
std::list<int> l;
#include <iostream>
#include <list>
std::list<int> l{1,2,3};
Here are some more ways by which we can initialize our list:
#include <iostream>
#include <list>
int main()
list<int> myList{1,2,3};
insert function
This method, as the name suggests, inserts an element at specificposition, in a list. There
are 3 variations of insert(), they are as follows :
#include <iostream>
#include <list>
using namespace std;
int main()
list<int> l = {1,2,3,4,5};
list<int>::iterator it = l.begin();
/*
/* now l is 10 10 10 10 10 1 100 2 3 4 5 */
return 0;
#include <list>
int main()
list<int> l{1,2,3,4,5};
l.push_back(6);
l.push_back(7);
l.push_front(8);
l.push_front(9);
/* now the list becomes 9,8,1,2,3,4,5,6,7 */
pop_front() removes first element from the start of the list. While pop_back()
removes first element from the end of the list.
#include <iostream>
#include <list>
int main()
list<int> l{1,2,3,4,5};
l.pop_back()();
l.pop_front()();
/* now the list becomes 2,3,4 */
empty function
This method returns true if the list is empty else returns false.
size function
This method can be used to find the number of elements present inthe list.
front() is used to get the first element of the list from the start
while back() is used to get the first element of the list from the back.
swap function
Swaps two list, if there is exception thrown while swapping anyelement, swap()
throws exception. Both lists which are to be swapped must be of the same type, i.e you
can‟t swap list of aninteger with list of strings.
reverse function
#include <iostream>
#include <list>
using namespace std;
int main()
list<int> l{1,2,3,4,5};
l.reverse();
sort function
sort() method sorts the given list. It does not create new sorted list but changes the position
of elements within an existing list to sortit. This method has two variations :
sort() : sorts the elements of the list in ascending order, theelement of the list
should by numeric for this function.
sort(compare_function) : This type of sort() is used when we have to alter the method
of sorting. Its very helpful for the elementsthat are not numeric. We can define how
we want to sort the list elements in compare_funtion. For example, list of strings can
be sorted by the length of the string, it can also be used for sorting in descending
order.
#include <iostream>
#include <list>
int main()
list1.sort();
/* list1 is now 1 2 3 4 5 6 */
list2.sort(compare_function);
}
splice function
splice() method transfers the elements from one list to another.There are three versions
of splice :
#include <iostream>
#include <list>
int main ()
list<int>::iterator it;
it = list1.begin();
list1.splice(it, list2);
return 0;
merge function
Merges two sorted list. It is mandatory that both the list should besorted first. merge()
merges the two list such that each element is placed at its proper position in the resulting
list. Syntax for merge is list1.merge(list2).
The list that is passed as parameter does not get deleted and thelist which calls the
merge() becomes the merged list
#include <iostream>
#include <list>
int main ()
list1.merge(list2);
/* list list1 is now 1,2,3,4,5,6,7,8,9,10 */
Since lists are collection of elements, thus they do not have a standard value of their own. Thus
in order to compare list or vectorswe compare their elements in their lexicographical order.
For example, let list1 = { 1 , 2 , 3} and list2 = { 1 , 3 , 2 }, now if we want to check if the
list1 is greater than list2 or not, we just check the element of each list in the order they
appear in the lists. Since 1in list1 is equal to 1 in list2, we proceed further, now 2 in list1 is
smaller then 3 in list2, thus list2 is lexicographically greater than list1.
For example: A map of students where roll number is the keyand name is the value
can be represented graphically as :
Notice that keys are arranged in ascending order, its because maps always arrange its keys in
sorted order. In case the keys are of stringtype, they are sorted lexicographically.
#include <iostream>
#include <map>
int main ()
map<string,int> map1;
at and [ ]
Both at and [ ] are used for accessing the elements in the map. Theonly difference between
them is that at throws an exception if the accessed key is not present in the map, on the
other hand operator [ ] inserts the key in the map if the key is not present already in the
map.
#include <iostream>
#include <map>
int main ()
map<int,string> m{ {1,”nikhilesh”} ,
{2,”shrikant”} , {3,”ashish”} };
m[4] = "doodrah";
m.at(5) = "umeshwa";
empty() returns boolean true if the map is empty, else it returns Boolean false. size() returns
number of entries in the map, an entryconsist of a key and a value. max_size() returns the
upper bound ofthe entries that a map can contain (maximum possible entries) based on the
memory allocated to the map.
insert() is used to insert entries in the map. Since keys are unique in a map, it first checks
that whether the given key is already present inthe map or not, if it is present the entry is not
inserted in the map and the iterator to the existing key is returned otherwise new entry is
inserted in the map.
insert(pair) : In this variation, a pair of key and value is insertedin the map. The
inserted pair is always inserted at the appropriate position as keys are arranged in
sorted order.
The insert_or_assing() works exactly as insert() except that if the givenkey is already present in
the map then its value is modified.
#include <iostream>
#include <map>
using namespace std;
int main ()
map::iterator i , j;
map<int,int> new_m;
new_m.insert(i,j);
m.insert( make_pair(3,6));
m.insert_or_assign( make_pair(3,6)); //
assign value = 6 to key =3
erase() removes the entry from the map pointed by the iterator (which is passed as
parameter), however if we want to remove all the elements from the map, we can use clear(),
it clears the map andsets its size to 0.
There are two variations of erase :
erase(iterator_itr) : This removes entry from the map pointed byiterator iterator_itr,
reducing the size of map by 1.
begin, end and find returns an iterator. begin() returns the iterator tothe starting entry of the
map, end() returns the iterator next to the last entry in the map and find() returns the iterator
to the entry having key equal to given key (passed as parameter).
STACK Container in C++ STL
The stack container is used to replicate stacks in c++, insertion anddeletion is always
performed at the top of the stack.
To know more about the Stack data Structure, visit: STACK DataStructure
stack<object_type> stack_name;
Following are some of the most commonly used functions of Stackcontainer in STL:
push function
push() is used to insert the element in the stack, the elements areinserted at the top of the
stack.
#include <iostream>
#include <stack>
int main ()
pop function
This method is used to removes single element from the stack. It reduces the size of the
stack by 1. The element removed is alwaysthe topmost element of the stack (most recently
added element) .The pop() method does not return anything.
top function
This method returns the topmost element of the stack. Note thatthis method returns the
element, not removes it, unlike pop().
SYNTAX: top()
size() returns the number of elements present in the stack, whereas empty() checks if the
stack is empty or not. empty returnstrue if the stack is empty else false is returned.
swap function
#include <iostream>
#include <stack>
int main ()
stack<int> s;
s.push(2);
s.push(3);
s.push(4);
push function
push() is used to insert the element in the queue. The element isinserted at the back or rear of
the queue.
#include <iostream>
#include <queue>
int main ()
pop function
This method removes single element from the front of the queue and therefore reduces its
size by 1. The element removed is the element that was entered first. the pop() does not
return anything.
#include <iostream>
#include <queue>
int main ()
front() returns the front element of the queue whereas back() returnsthe element at the back of
the queue. Note that both returns the element, not removes it, unlike pop().
size() returns the number of elements present in the queue, whereas empty() checks if the
queue is empty or not. empty returnstrue if the queue is empty else false is returned.
Swap function
priority_queue<int> pq;
push function
This method inserts an element in the priority_queue. The insertionof the elements have time
complexity of logarithmic time.
#include <iostream>>
#include <queue>
int main ()
{
priority_queue<int> pq1;
return 0;
pop function
This method removes the topmost element from the priority_queue(greatest element)
,reducing the size of the priority queue by 1.
#include <iostream>>
#include <queue>
priority_queue<int> pq1;
return 0;
}
top function
This method returns the element at the top of the priority_queuewhich is the greatest element
present in the queue.
size() returns the number of element present in the priority _queue, whereas empty() returns
Boolean true if the priority_queue is emptyelse Boolean false is returned.
swap function
insert(iterator i, iterator first, iterator last) : Inserts the element inthe range
[first,last] at the position pointed by iterator i in deque.
#include <iostream>
#include <deque>
#include <vector>
int main ()
{
int a[] = { 1,5,8,9,3 };
dq.push_back(10);
/* now dq is : 1,5,8,9,3,10 */
dq.push_front(20);
/* now dq is : 20,1,5,8,9,3,10 */
deque<int>::iterator i;
i=dq.begin()+2;
dq.insert(i,15);
/* now dq 20,1,15,5,8,9,3,10 */
int a[]={7,7,7,7};
d1.insert(dq.begin() , a , a+4 );
/* now dq is 7,7,7,7,20,1,15,5,8,9,3,10 */
pop_back() removes an element from the back of the deque whereas pop_front removes an
element from the front of the deque,both decreasing the size of the deque by one.
#include <iostream>
#include <deque>
#include <vector>
int main ()
dq.pop_back();
dq.pop_front();
/* now dq is : 1,5,8,9,3,5,6 */
empty() returns Boolean true if the deque is empty, else Boolean false is returned. size()
returns the number of elements present inthe deque and max_size() returns the number of
element the givendeque can hold.
swap function
Algorithms in STL don‟t work on containers, instead they work on iterators, they manipulate
the data pointed by the iterators. Thus it doesn‟'t matter what is the type of the container and
because of thisan algorithm will work for any type of element and we don't have todefine same
algorithm for different types of containers.
The above diagram shows to iterators i and j, pointing to thebeginning and the end
of a vector.
container_type <parameter_list>::iterator
iterator_name;
#include<iostream>
#include<vector>
int main()
vector<int>::iterator i;
vector<string>::iterator j;
list<int>::iterator k;
map<int, int>::iterator l;
}
Iterators can be used to traverse the container, and we can de- reference the iterator to get
the value of the element it is pointingto. Here is an example:
#include<iostream>
#include<vector>
int main()
vector<int> v(10);
vector<int>::iterator i;
pointed by it. */
return 0;
advance
distance
next
prev
begin
end
advance() Operation
It will increment the iterator i by the value of the distance. If thevalue of distance is
negative, then iterator will be decremented.
#include<iostream>
#include<vector>
int main()
{
i = v.begin();
advance(i,5);
advance(i,-1);
}
distance() Operation
It will return the number of elements or we can say distancebetween the first and
the last iterator.
#include<iostream>
#include<vector>
int main()
vector<int>::iterator i, j; // defines
iterators i,j to the vector of integers
i = v.begin();
j = v.end();
/* j now points to the end() of the vector v
*/
/* prints 10 , */
next() Operation
It will return the nth iterator to i, i.e iterator pointing to the nthelement from the
element pointed by i.
prev() Operation
It will return the nth predecessor to i, i.e iterator pointing to the nthpredecessor element from
the element pointed by i.
begin() Operation
This method returns an iterator to the start of the given container.SYNTAX: begin()
end() Operation
This method returns an iterator to the end of the given container.SYNTAX: end()