A Complete Guide to Programming in C++ (Book)
Programming and Data Structures
Learn C++ Programming -Beginner to Advance - Deep Dive in C++
C++ Programming Course (freeCodeCamp)
Cherno's C++ (YouTube Series)
C++ is a high level object-oriented programing language.
Most C++ compilers require that C++ files end in an extension .cpp, .cxx, .cc, or .c.
C++ language is case sensitive.
A library is a collection of code that has been programmed and translated by someone else, ready for you to use in your program.
A compiler translates the written code into machine code.
A linker takes your machine code and the necessary parts from the C++ library and builds an executable file.
#include <iostream> //Preprocessor directive
using namespace std;
int main()
{
// Enter code here
return 0;
}| File Type | File extension | Description |
|---|---|---|
| Source code file | .cpp | Text file containing the c++ code. |
| Header file | .h | Text file containing information about other code files. |
| Object File | .obj | File containing object code. |
| Executable | .exe | Executable binary file. |
Object code is a portion of machine code that has not yet been linked into a complete program.
- This directs the compiler to include a source file before compiling the program.
- Generally used to include header files with extension .h. For example iostream.h.
| Symbol | Description |
|---|---|
| # | Preprocessor Directive |
| iostream | Header file provided by the C/C++ language for input/output processing |
| <> | Means that this file is available in a predefined directory |
Backslash ' \ ' is used to print special characters.
| Escape Sequence | Description |
|---|---|
| ' | single quote |
| " | double quote |
| ? | question mark |
| \\ | backslash |
| \a | audible bell |
| \b | backspace |
| \f | form feed - new page |
| \n | line feed - newline |
| \r | carriage return |
| \t | horizontal tab |
| \v | vertical tab |
Syntax errors occur when the compiler finds something wrong when it comes to the language rules i,e. syntax. When the compiler finds one or more errors, it will not translate the program to machine code. If the compiler finds an error, it will not simply stop and give up. It will try to report as many errors as it can find, so you can fix them all at once.
Run-Time error occurs when the program is syntactically correct but it doesn’t do what it is supposed to do. Because run-time errors are caused by logical flaws in the program, they are often called logic errors. Run-time errors are more troublesome as the compiler will not be able to find them.
Pseudocode is a plain language description of the steps in an algorithm. There are no strict requirements for pseudocode because it is read by human readers, not a computer program.
- For Hexadecimal use:
\x - For Octal use:
\0 - For decimal values use:
static_cast<char>()
A token is the smallest element of a C++ program that is meaningful to the compiler.
The C++ compiler recognizes these kinds of tokens:
- Identifiers
- Keywords
- Constants/Literals
- Operators
- Punctuators
- Other Separators
C++ Tokens | Keywords, Identifiers, Literals, Punctuators, Operators - cppforschool
Identifiers are used as the general terminology for naming of variables, functions and arrays. Identifier names must differ in spelling and case from any keywords. You cannot use keywords as identifiers; they are reserved for special use. Once declared, you can use the identifier in later program statements to refer to the associated value
- It must begin with a letter or underscore(_).
- It must consist of only letters, digits, or underscore. No other special character is allowed.
- It should not be a keyword.
- It must not contain white space.
- It must not start with a digit.
Keywords are pre-defined or reserved words in a programming language. Each keyword is meant to perform a specific function in a program.
Since keywords are referred names for a compiler, they can’t be used as variable names because by doing so, we are introducing ambiguity.
| alignas (since C++11) | explicit | signed |
| alignof (since C++11) | export(1) | sizeof |
| and | extern | static |
| and_eq | FALSE | static_assert (since C++11) |
| asm | float | static_cast |
| auto(1) | for | struct |
| bitand | friend | switch |
| bitor | goto | template |
| bool | if | this |
| break | inline | thread_local (since C++11) |
| case | int | throw |
| catch | long | TRUE |
| char | mutable | try |
| char16_t (since C++11) | namespace | typedef |
| char32_t (since C++11) | new | typeid |
| class | noexcept (since C++11) | typename |
| compl | not | union |
| concept (concepts TS) | not_eq | unsigned |
| const | nullptr (since C++11) | using(1) |
| constexpr (since C++11) | operator | virtual |
| const_cast | or | void |
| continue | or_eq | volatile |
| decltype (since C++11) | private | wchar_t |
| default(1) | protected | while |
| delete(1) | public | xor |
| do | register | xor_eq |
| double | reinterpret_cast | |
| dynamic_cast | requires (concepts TS) | |
| else | return | |
| enum | short |
- Integer constant (eg: 25, -64, 0)
- Floating point constant (eg: 2.34, -9.12, 1.2E10)
- Must begin with '0' (eg -12, 056)
- Must begin with '0x' (eg: 0x123)
- Must be written with single quotes (eg: 'A', '$')
- Must be written with double quotes (eg: "LUMS")
- Strings always end with a
\0delimiter
Literal is the raw value and identifier is the name of the variable or constant in which that raw value is stored.
Operators are symbols that triggers an action when applied to variables and other objects.
| Operator | Description |
|---|---|
| + | Addition |
| - | Subtraction |
| * | Multiplication |
| / | Division |
| % | Modulus |
| Operator | Description |
|---|---|
| ++ | Increment |
| −− | Decrement |
| Operator | Description |
|---|---|
| == | Is equal to |
| != | Is not equal to |
| > | Greater than |
| < | Less than |
| >= | Greater than or equal to |
| <= | Less than or equal to |
| Operator | Description |
|---|---|
| && | And operator. Performs logical conjunction of two expressions.(if both expressions evaluate to True, result is True. If either expression evaluates to False, the result is False) |
| || | Or operator. Performs a logical disjunction on two expressions.(if either or both expressions evaluate to True, the result is True) |
| ! | Not operator. Performs logical negation on an expression. |
Used on the bits of data.
| Operator | Description |
|---|---|
| << | Binary Left Shift Operator |
| != | Is not equal to |
| >> | Binary Right Shift Operator |
| ~ | Binary One's Complement Operator |
| & | Binary AND Operator |
| ^ | Binary XOR Operator |
| | | Binary OR Operator |
| Operator | Description |
|---|---|
| = | Assign |
| += | Increments, then assign |
| -= | Decrements, then assign |
| *= | Multiplies, then assign |
| /= | Divides, then assign |
| %= | Modulus, then assign |
| <<= | Left shift and assign |
| >>= | Right shift and assign |
| &= | Bitwise AND assign |
| ^= | Bitwise exclusive OR and assign |
| |= | Bitwise inclusive OR and assign |
| Operator | Description |
|---|---|
| , | Comma operator |
| sizeOf() | Returns the size of a memory location |
| & | Returns the address of a memory location |
| * | Pointer to a variable |
| ? : | Conditional Expression |
| Precedence | Operator | Description | Associativity |
|---|---|---|---|
| 1 | ::
|
Scope resolution | Left-to-right |
| 2 | a++ a--
|
Suffix/postfix increment and decrement | |
type() type{}
|
Functional cast | ||
a()
|
Function call | ||
a[]
|
Subscript | ||
. ->
|
Member access | ||
| 3 | ++a --a
|
Prefix increment and decrement | Right-to-left |
+a -a
|
Unary plus and minus | ||
! ~
|
Logical NOT and bitwise NOT | ||
(type)
|
C-style cast | ||
*a
|
Indirection (dereference) | ||
&a
|
Address-of | ||
sizeof
|
Size-of | ||
co_await
|
await-expression (C++20) | ||
new new[]
|
Dynamic memory allocation | ||
delete delete[]
|
Dynamic memory deallocation | ||
| 4 | .* ->*
|
Pointer-to-member | Left-to-right |
| 5 | a*b a/b a%b
|
Multiplication, division, and remainder | |
| 6 | a+b a-b
|
Addition and subtraction | |
| 7 | << >>
|
Bitwise left shift and right shift | |
| 8 | <=>
|
Three-way comparison operator (since C++20) | |
| 9 | < <= > >=
|
For relational operators < and ≤ and > and ≥ respectively | |
| 10 | == !=
|
For equality operators = and ≠ respectively | |
| 11 | &
|
Bitwise AND | |
| 12 | ^
|
Bitwise XOR (exclusive or) | |
| 13 | |
|
Bitwise OR (inclusive or) | |
| 14 | &&
|
Logical AND | |
| 15 | ||
|
Logical OR | |
| 16 | a?b:c
|
Ternary conditional | Right-to-left |
throw
|
throw operator | ||
co_yield
|
yield-expression (C++20) | ||
=
|
Direct assignment (provided by default for C++ classes) | ||
+= -=
|
Compound assignment by sum and difference | ||
*= /= %=
|
Compound assignment by product, quotient, and remainder | ||
<<= >>=
|
Compound assignment by bitwise left shift and right shift | ||
&= ^= |=
|
Compound assignment by bitwise AND, XOR, and OR | ||
| 17 | ,
|
Comma | Left-to-right |
| Punctuator | Symbol | Description |
|---|---|---|
| Brackets | [] |
Opening and closing brackets indicate single and multidimensional array subscript. |
| Parentheses | () |
Opening and closing parentheses indicate function calls; function parameters for grouping expressions. |
| Braces | {} |
Opening and closing braces indicate start and end of a compound statement. |
| Comma | , |
It is used as a separator is a function argument list. |
| Semicolon | ; |
It is used as a statement terminator. |
| Colon | : |
It indicates a labeled statement or conditional operator symbol. |
| Asterisk | * |
It is used in pointer declaration and dereferencing and as multiplication operator. |
| Equal sign | = |
It is used as an assignment operator. |
| Pound sign | # |
It is used as a preprocessor directive. |
Division ( / ) usually return the quotient value, or in other words if used with integers, will give answer in integers too i.e. 5 / 2 = 2.
If you want the result in decimal form you can do:
5 / 2.0(double)5 / 2i.e. type castingdouble a = 5, b = 2, c; c = a / bi.e. division on decimal defined values
Modulus ( % ) gives us the remainder i.e. 5 % 2 = 1
// Separate Last 2 Character
int a = 428;
a = a % 100;
cout << a << endl;
// Output: 28// Separate First 2 Character
int a = 938;
a = a / 10;
cout << a << endl;
// Output: 93++x; // increment first or pre increment
x++; // increment later ot post increment
// Example 1
x = 3;
y = ++x;
// x contains 4, y contains 4
// Example 2
x = 3;
y = x++;
// x contains 4, y contains 3
// Example 3
x = 1;
y = x++ + 1;
// x contains 2, y contains 2| Object | Convention |
|---|---|
| Constants | ALL_CAPS, ALLCAPS |
| Variables | all_small, allsmall |
| Functions | firstSmallRestCamelCase |
| Classes | CamelCase |
An identifier whose value can be modified or changed.
int number;
// Declaration statement
number = 8;
// Assignment statement
int another_number = 6;
// Variable definition (declaration + assignment)You must define a variable before you use it for the first time.
If you define a variable but leave it uninitialized, then your program can act unpredictably. If you use the variable without initializing it, then a default value will be used, yielding unpredictable results. For example, consider the program segment:
int bottles; // Forgot to initialize
int bottle_volume = bottles * 2; // Result is unpredictable- An identifier whose value cannot be modified or changed. They are treated just like regular variables except that their values cannot be modified after their definition.
- Its better to use UPPERCASE for names of constant.
- A constant can be declared using the keyword
constas:
const int CANS_PER_PACK = 6;
const float PI = 3.14159;
const char FIRST_CH = 'c';
const string PREFIX = "LUMS";const double CAN_VOLUME = 0.355; // Single line comment
/*
This is a
multiline comment
*/| Simple/Basic | Modifiers | Qualifiers | Derived (Structured) | Composite (Advanced) |
|---|---|---|---|---|
| char | signed | static | arrays | lists |
| int | unsigned | const | structures | queues |
| float | long | volatile | unions | stacks |
| double | - | void | classes | trees |
| - | - | - | - | graphs |
char is used to store a single character within single quotes ( ' ' ).
char x = 'x';
char z = '\n';Char is actually an integer in the backend and can be used to make a program more efficient.
Difference between signed / unsigned char
| Type | Range | Size |
|---|---|---|
| int | -2,147,483,648 ... 2,147,483,647 | 4 bytes |
| unsigned | 0 ... 4,294,967,295 | 4 bytes |
| short | -32,768 ... 32,767 | 2 bytes |
| unsigned short | 0 ... 65,535 | 2 bytes |
| long long | -9,223,372,036,854,775,808 ... 9,223,372,036,854,775,807 | 8 bytes |
| double | Double-precision floating-point | 8 bytes |
| float | Single-precision floating point | 4 bytes |
Double is a floating point data type while long is an integral data type. The difference is in the manner of encoding number information.
The 64 bit double format based on IEEE754 standard has the following breakup:
- Sign bit: 1 bit
- Exponent width: 11 bits
- Significant precision: 53 bits (52 explicitly stored)
The exponent gives double precision numbers a very large range - Negative numbers are in the range -1.79769e+308 to -2.22507e-308 and positive numbers are in the range 2.22507e-308 to 1.79769e+308.
The large range comes at the cost of decreased precision though.
64bit long in contrast has a simple encoding, it is represented as a string of bits in the binary numeral system. These can range from −2^63 to 2^63 − 1 in the signed case. Or from 0 to 2^64 -1 in the unsigned case.
Note that 'long' may imply either 32 bit or 64 bit depending on the context. Im assuming you mean 64bit long here.
Because numbers are represented in the computer with a limited number of digits, they cannot represent arbitrary integer or floating-point numbers. All data type have a limited range.
If a computation yields a value that is outside the int range, the variable will overflow.
If a variable is currently at the highest possible value it can store, and you add 1 to it, it will cycle back to the smallest possible value.
For floating-points, a computer can not store the exact value of a fraction and can only store a close approximation. This is called Roundoff Error. How precise that approximation, depends on the size of the data type.
0 is considered a positive number. Thus, 1 is subtracted from the total number of positive integers when calculating total range of positive numbers.
// int just ignores everything after the decimal - truncation
int x = 2.7523532425;
// x = 2
int x = 2.023532425;
// x = 2floating literal - cppreference
Floats are not usually used nowadays but if you want to explicitly use a float, declare it with a f suffix.
float = 2.45f;
// the f at the end is necessary, else the compiler will change the float to a doubleThe sizeof is a keyword, but it is a compile-time operator that determines the size, in bytes, of a variable or data type.
The sizeof operator can be used to get the size of classes, structures, unions and any other user defined data types.
It is mainly used to get size of arrays.
#include <iostream>
using namespace std;
int main() {
cout << "Size of char : " << sizeof(char) << endl;
cout << "Size of int : " << sizeof(int) << endl;
cout << "Size of short int : " << sizeof(short int) << endl;
cout << "Size of long int : " << sizeof(long int) << endl;
cout << "Size of float : " << sizeof(float) << endl;
cout << "Size of double : " << sizeof(double) << endl;
cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;
return 0;
}
/*
Size of char : 1
Size of int : 4
Size of short int : 2
Size of long int : 4
Size of float : 4
Size of double : 8
Size of wchar_t : 4
*/static_cast is used to convert data types.
// static_cast < new_type > ( expression )
int n = static_cast<int>(3.14);cout << "Enter number of bottles: "; //prompt
int bottles;
cin >> bottles; // input cin only reads one word.
Example if you try to input Double Word with cnn only Double will be loaded.
To take multiword inputs use getline().
string city;
getline(cin, city);
// read till the end of the line and store it in the variable citycin.fail() is used for Input Validation. Below is an example implementation:
int x = 0;
cin >> x;
if (cin.fail())
{
cout << "Error: Not an integer." << endl;
return 1; // used when the program closes due to an error
} else
{
cout << "Input was accepted" << endl;
return 0;
}When an input operation has failed, all further input operations also fail. If you want to read two number sequences and use a letter as a sentinel, you need to clear the failure state after reading the first sentinel. Call the cin.clear() function.
int values;
cout << "Enter values, Q to quit.\n";
while (cin >> values)
{
// Process input.
}
cin.clear(); // removes errror flag
// Suppose the user has entered 30 10 5 Q.
// The input of Q has caused the failure. Because
// only successfully processed characters are
// removed from the input, the Q character is
// still present. Read it into a dummy variable.
string sentinel;
getline(cin, sentinel); // inplace of this you can also use cin.ignore(1000, '\n');
// every input after this will work fineThe cin.clear() clears the error flag on cin so that future I/O operations will work correctly.
NOTE: cin.clear() and storing the cin's data in a dummy variable have separate purposes. Also see cin.ignore() and cin.flush().
istream::ignore - C++ Reference
fixed- write floating point values in fixed point notation.scientific- write floating point values in scientific notation.setprecision()- set floating point precision to n decimal places.setw()- set width to n columns.setfill()- use a specific character to fill a width (specified bysetw()).
use iomanip header to get access to setw() and setprecision()
| Statement | Output | Comment |
|---|---|---|
cout << 12.345678; |
12.3457 |
By default, a number is printed with 6 significant digits. |
cout << fixed << setprecision(2) << 12.3; |
12.30 |
Use the fixed and setprecision manipulators to control the number of digits after the decimal point. |
cout << ":" << setw(6) << 12; |
: 12 |
Four spaces are printed before the number, for a total width of 6 characters. |
cout << ":" << set(2) << 123; |
:123 |
If the width not sufficient, it is ignored. |
cout << setw(6) << ":" << 12; |
:12.3 |
The width only refers to the next item. Here, the : is preceded by five spaces. |
int main () {
double f =3.14159;
std::cout << std::setprecision(5) << f << endl;
std::cout << std::setprecision(9) << f << endl;
std::cout << std::fixed;
std::cout << std::setprecision(5) << f << endl;
std::cout << std::setprecision(9) << f << endl;
return 0;
}
/*
3.1416 // 5 digits
3.14159
// fixed specified here
3.14159 // fixed makes it so that 5 characters are printed after decimal
3.141590000 // here 9 digits are printed after the decimal
*/int main()
{
cout << setfill(' ') << setw(15) << "" << setfill ('*') << setw (3) << "" << setfill(' ') << setw(15) << "" << endl;
cout << setfill(' ') << setw(13) << "" << setfill ('*') << setw (7) << "" << setfill(' ') << setw(13) << "" << endl;
cout << setfill(' ') << setw(11) << "" << setfill ('*') << setw (11) << "" << setfill(' ') << setw(11) << "" << endl;
cout << setfill(' ') << setw(0) << "" << setfill ('*') << setw (33) << "" << setfill(' ') << setw(0) << "" << endl;
cout << setfill('*') << setw(8) << "" << setfill (' ') << setw (17) << "" << setfill('*') << setw(8) << "" << endl;
cout << " " << setfill('*') << setw(8) << "" << setfill (' ') << setw (13) << "" << setfill('*') << setw(8) << "" << " " << endl;
cout << setfill('*') << setw(8) << "" << setfill (' ') << setw (17) << "" << setfill('*') << setw(8) << "" << endl;
cout << setfill(' ') << setw(0) << "" << setfill ('*') << setw (33) << "" << setfill(' ') << setw(0) << "" << endl;
cout << setfill(' ') << setw(11) << "" << setfill ('*') << setw (11) << "" << setfill(' ') << setw(11) << "" << endl;
cout << setfill(' ') << setw(13) << "" << setfill ('*') << setw (7) << "" << setfill(' ') << setw(13) << "" << endl;
cout << setfill(' ') << setw(15) << "" << setfill ('*') << setw (3) << "" << setfill(' ') << setw(15) << "" << endl;
return 0;
}
/*
***
*******
***********
*********************************
******** ********
******** ********
******** ********
*********************************
***********
*******
***
*/int main()
{
cout << setfill(' ') << setw(4) << "" << setfill('*') << setw(1) << "" << setfill(' ') << setw(4) << "" << endl;
cout << setfill(' ') << setw(3) << "" << setfill('*') << setw(3) << "" << setfill(' ') << setw(3) << "" << endl;
cout << setfill(' ') << setw(2) << "" << setfill('*') << setw(5) << "" << setfill(' ') << setw(2) << "" << endl;
cout << setfill(' ') << setw(1) << "" << setfill('*') << setw(7) << "" << setfill(' ') << setw(1) << "" << endl;
cout << setfill(' ') << setw(0) << "" << setfill('*') << setw(9) << "" << setfill(' ') << setw(0) << "" << endl;
return 0;
}
/*
Output:
*
***
*****
*******
*********
*/- To use string include the header file string:
#include <string> - Given two strings, such as "Harry" and "Morgan", you can concatenate them to one long string.
string fname = "Harry";
string lname = "Morgan";
string name = fname + lname;
//"HarryMorgan"String literal is the raw string value like "hello".
Remember: Two string literals can not be concatenated. However, a string literal can be concatenated with a variable with a string\char data type.
if ( a < 20 )
{
// if condition is true then print the following
cout << "a is less than 20;" << endl;
}
else if ( a > 30)
{
cout << "a is more than 30;" << endl;
}
else
{
cout << "a is between 20 and 30;" << endl;
}
// if you have only one statement after if you can skip the {}
if ( 5 < 10 )
cout<<"Five is now less than ten, that's a big surprise";Dangling else can cause issues and can be quite difficult to debug.
if(x == 1)
if(x == 2)
if(x > 2)
else //this else belongs to if(x > 2)
{
//code
}if (int k = 5; k < 10)
{
// k will only be useable inside 'the if' code block
}//condition ? true value : false value
actual_floor = floor > 13 ? floor - 1 : floor;C++ optimizes the comparisons by only running half of the comparisons.
For example in x && b if x is false, the output of the comparison will be false no matter what the value of b is and so c++ will not even check the value of b. However, if x is true then c++ will check the value for b as now the output also depends on the value of b.
In case of x || b if x is true, the output of the comparison will true no matter what the value of b is and so c++ will not check the value of b. But if the value of x is false, now the output will depend on the value of b.
Analyze the following code:
bool yes()
{
cout << "yes";
return true;
}
bool no()
{
cout << "no";
return false;
}
int main()
{
yes() || no(); // output: yes
no() || yes(); // output: noyes
yes() || yes(); // output: yes
}Exact Comparison of Floating-Point Numbers Floating-point numbers have only a limited precision, and calculations can introduce roundoff errors.
Use the following equation to compare the Floating-Point Number:
double x = 2.0;
double y = sqrt(x);
// x = 2.00000000000000000000
// y*y = 2.00000000000000044409
// Wrong way to compare
if (x == y*y)
cout << "Comparison Working" << endl;
else
cout << "Comparison Not Working" << endl;
// Output:
// Comparison Not Working
// Right way to compare
double epsilon = 1E-14;
if ( fabs(x - y*y) < epsilon )
cout << "Comparison Working" << endl;
else
cout << "Comparison Not Working" << endl;
// Output:
// Comparison WorkingC++ uses Lexicographic Ordering of Strings. This ordering is very similar to the way in which words are sorted in a dictionary.
The easier way to look at it is to just use the ASCII table for comparisons. The character with the lower ASCII value will be less than the character with higher ASCII value.
int digit = 4;
string digit_name;
switch (digit)
{
case 1: digit_name = "one"; break; // if digit == 1
case 2: digit_name = "two"; break;
case 3: digit_name = "three"; break;
case 4: digit_name = "four"; break;
case 5: digit_name = "five"; break;
case 6: digit_name = "six"; break;
case 7: digit_name = "seven"; break;
case 8: digit_name = "eight"; break;
case 9: digit_name = "nine"; break;
default: digit_name = ""; break;
}
cout << digit_name << endl;
// fourenum Colors {RED , ORANGE, BLUE};
// RED = 0
// ORANGE = 1
// BLUE = 2
Colors mycolor = RED;
int x = 0;
if ((Colors)x == mycolor)
cout << "mycolor is RED" << endl;
else
cout << "mycolor is not RED" << endl;You can also force indexed:
enum Colors {RED=1 , ORANGE, BLUE};
// RED = 1
// ORANGE = 2
// BLUE = 3Used to create user-defined data types.
With typedef you can rename a primitive data types to improve code readability.
typedef int age;
// defining a new data type age, which is actually int at its core
age a1 = 16;
age a2 = 18;
// you can use the custom datatype just like any other primitive data typewhile (/* condition */) {
/* code */
}Do While Loop is a modification of the While Loop.
The do loop is appropriate when the loop body must be executed at least once.
do {
/* code */
} while(/* condition */);for (size_t i = 0; i < count; i++) {
/* code */
}/*
for (a, b ,c) { body }
a : initialization
b: condition
c: updating
1. a will run at the start
2. b will run
3. loop body will run
4. c will run
5. b will run
6. loop body will run
7. c will run
8. b will run
and so on..
*/// ***************
for (int i = 0; i < 5 ; i++)
{
cout << i;
}
// Output: 01234
// ***************
int i = 0;
for (; i < 5 ; i++)
{
cout << i;
}
// Output: 01234
// ***************
int i = 0;
for (; ; i++)
{
if ( i >= 5) { break; }
cout << i;
}
// Output: 01234
// ***************
int i = 0;
for (; ;)
{
if ( i >= 5) { break; }
cout << i;
i++;
}
// Output: 01234Foreach loop iterators over an array.
The number of times the loop runs, depends on the size of the array being iterated.
int arr[] = {1, 2, 3, 4, 5};
// arr: iterable
// x: iterating variable
for(int x: arr)
{
cout << x << endl;
}
cout << endl;
/*
12345
*/If you modify the values of an array using foreach. You must declare the iterating variable with a '&' sign.
int arr[] = {1, 2, 3, 4, 5};
for(int &x: arr)
{
x++;
}
//arr: {2, 3, 4, 5, 6}-
breakstatement breaks the loop -
continuestatement goes to the next iteration o the loop.
rand() is used to generate random numbers.
Use ctime for seed generation.
// Generating 10 random numbers between 0 and 6
srand(time(0)); // setting seed
int number = 0;
for (int i = 0; i < 10; i++)
{
number = rand() % 6 + 1;
cout << number << endl;
}// Generating 10 random decimals between 0 and 1
srand(time(0));
double number = 0;
for (int i = 0; i < 10; i++)
{
number = rand() * 1.0 / RAND_MAX; // multiply by 1.0 to convert
cout << number << endl; // the calculation to double.
}Functions are viewed as a black box. We put in value and we get some other value or in case of void functions we perform a task.
The whole idea of a function is to break down the program into smaller parts and to reuse those smaller parts if needed.
// Declaration of cube_volume
double cube_volume(double side_length); // function head
int main()
{
cube_volume(6); // function used
return 0;
}
// Definition of cube_volume
double cube_volume(double side_length) // function head
{
return side_length * side_length * side_length; // function body
}If you declare the define the function below the main() function, the compiler will not be able to find the function declaration and will not compile.
To fix this, put the function declaration above the main()function, and put the function definition after the main() function.
A drawback: Whenever you change the name of a function or one of the parameter types, you need to fix it in both places: in the declaration and in the definition.
return statement terminates the code body and returns a value, if provided.
void functions either do not return a value or return multiple values (with the use of struct).
You must use a return statement, without any value, at the end of a void function
void print(string sentence)
{
cout << sentence << endl;
return;
}
// return; important for terminationYou should describe your functions using comments.
/*
Computes the volume of a pyramid whose base is a square.
@param height the height of the pyramid
@param base_length the length of one side of the pyramid’s base
@return the volume of the pyramid
*/
double pyramidVolume(double height, double base_area)
{
return (height * base_area)/3;
}Function overloading is having multiple functions declarations with the same name but different parameters.
You cannot overload function declarations that differ only by return type (the parameters must also differ).
int add(int a, int b)
{
return a + b;
}
int add(int a, int b, int c)
{
return a + b + c;
}Generic functions (function with same body but different data types) can be turned into templates.
// T can be any name
template <class T>
T maxim(T x, T y)
{
return x>y ? x : y;
}
int main()
{
cout << maxim(2, 5) << endl;
cout << maxim(1.4, 2.6) << endl;
}
// Output:
// 5
// 2.6Function templates - cplusplus
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
return;
}
int main()
{
int a = 1;
int b = 9;
swap(a, b);
}
// Note: This function will not workFor the program above the machine code for main and swap live independently in the memory.
When main function reaches swap a new stack frame is created and the value of a and b is copied into the new stack frame. The swap function can only access the values in its stack frame. At the end of the swap function the stack frame is deleted.
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
return;
}
int main()
{
int a = 1;
int b = 9;
swap(&a, &b);
}For the program above the machine code for main and swap live independently in the memory.
When the swap function is called in main, instead of passing the value into the swap stack frame we pass the address of a and b. This gives swap the ability to manipulate the values these addresses point to.
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
return;
}
int main()
{
int a = 1;
int b = 9;
swap(a, b);
}For the program above, at the time of compilation the machine code for swap is copied into the machine code of main. In other words the body of swap is copied into main at the time of compilation.
In the case of call by reference, the activation frame of swap is the same as the activation frame of main.
For this reason, call by reference is only used for simple functions.
void (*func)() = myFunc; // myfunc is a function
//declared func as a function pointer
func(); // calling the function inline is a request to the compiler to copy the function body to the place where that specific function was called.
This is done to reduce the overhead when the execution time of the function is less than the time needed for control transfer.
Object Lifetime in C++ (Stack/Scope Lifetimes) - YouTube
- In a stack, different stack frames are present on top of each other. In order to access a stack frame at the bottom, you will have to remove (pop) the stack frames above it.
- Functions or Code Blocks are essentially stack frames.
- Variable scopes can be describes using stack frames
A variable that is defined within a function is visible from the point at which it is defined until the end of the block in which it was defined. This area is called the scope of the variable.
Object Lifetime in C++ (Stack/Scope Lifetimes) - YouTube
Global variable is visible to the whole file, while local variables are function specific.
double pi = 3.142; // Global Variable
double circumferenceOfCircle(int radius)
{
return 2 * pi * radius; // Global Variable Used
}
int main()
{
int r = 34; // Local Variable
cout << "Radius: " << r << endl;
cout << circumferenceOfCircle(r) << endl;
}Also check:
Scope resolution operator in C++ - GeeksforGeeks
DON'T USE GLOBAL VARIABLES
-
Block Scope (local within a block of code):
A variable whose scope is just a small block of code. E.g
iin for loops:for(int i = 0; i < 5; i++) { // i is only useable here }
-
Function scope (local within a block of function):
A variable which is only useable inside a function.
-
File scope:
A variable which is only useable inside a file.
-
Program scope:
A variable which is only useable inside a program.
Usually variables are destroyed after a code block finishes execution but if we define a variable, in that block, as static, it will not be destroyed.
Static elements are only created once and have a lifetime till the end of the program.
void counter()
{
static int count=0;
cout << count++;
}
int main()
{
for(int i=0;i<5;i++)
{
counter();
}
}
// Output:
// 01234& can also be used to get the address of a specific variable.
int x = 1;
cout << &x << endl;
// 0x7ffe6c03214cA reference of a variable is essentially that variable but different name
int i = 5;
int &integer = i;
cout << i << endl; // 5
cout << integer << endl; // 5
integer++;
cout << i << endl; // 6C++ References - tutorialspoint
Array is the collection of items of same type in contiguous memory (stack).
The array size must be constant.
Using sizeof() on arrays will return the total bytes needed to store that array.
int arr[5] = {1, 2, 3, 4, 5};
cout << sizeof(arr) << endl; // 20
cout << sizeof(arr[0]) << endl; // 4If you try to print an out of bound index of an array, the compiler will not complain.
The executable will be generated but the output will be unpredictable.
int arr[2] = {1, 2 };
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
/*
Output:
1
2
4196448
*/sizeof() can be used to calculate the size (number of objects in array) of an already refined array.
int arr[] = {1, 2, 3, 4};
int size = sizeof(arr)/sizeof(int);
// int size = sizeof(arr)/sizeof(arr[0]);
cout << size << endl;
// 4In order to work with arrays, you need to pass the size of the array also.
Or the size can be calculated using the sizeof() operator in certain circumstances.
double sum(double values[], int size) // passing in size is important
{
double total = 0;
for (int i = 0; i < size; i++)
{
total = total + values[i];
}
return total;
}By default, only the array pointer is passed to the function i.e. name_of_array[] is actually a pointer to the array.
The scope of the function treats the array as a pointer and thus you can not use things like foreach loop on the array.
C++ Passing Arrays to Functions - tutorialspoint
Passing an array by reference - StackOverflow
If a function doesn’t modify the values of an array parameter, it is considered a good idea to add the const reserved word:
double sum(const double values[], int size)
The const reserved word helps in the readability of the code, making it clear that the function keeps the elements of an array unchanged
If the implementation of the function tries to modify the array, the compiler issues a warning.
- A variable used to store the address of some data.
- References(
&) are managed by the compiler but pointers are directly managed by the programmer. - A program can not access the heap directly. To use heap, it needs to make use of pointers.
int x = 1000; // a variable x storing the value 1000
int* px = &x; // a pointer px storing the memory address of variable x- When you initialize a pointer, be sure that the pointer and the memory address have the same type.
- If you define a pointer variable without providing an initial variable, the pointer contains a random address. Using that random address is an error. To prevent this initialize a pointer with the value NULL :
int* px = NULL
The use of const with pointers is a little confusing so check the following examples:
int*- pointer to intint const *- pointer to const intint * const- const pointer to intint const * const- const pointer to const int
Now the first const can be on either side of the type so:
const int *==int const *const int * const==int const * const
If you want to go really crazy you can do things like this:
int **- pointer to pointer to intint ** const- a const pointer to a pointer to an intint * const *- a pointer to a const pointer to an intint const **- a pointer to a pointer to a const intint * const * const- a const pointer to a const pointer to an int
The name of the variable storing an array actually stores the starting address of that array.
int arr[5] = {};
cout << arr << endl; // Output: 0x7ffd9bcdc160 (i.e. address)Because array is continuous space in memory, you can access its content through pointers.
int arr[5] = {1, 2, 3, 4, 5};
int* p = arr;
cout << arr << endl;
cout << p << endl;
cout << *arr << endl;
cout << *p << endl;
/*Output:
0x7ffff9686530
0x7ffff9686530
1
1
*/Pointer arithmetic means adding an integer offset to an array pointer, yielding a pointer that skips past the given number of elements.
double a[10];
double* p = a;
// *(p + 3) == a[3]C language stores strings in char* which are quite similar to char[]. A string stored in a char* is called a 'c-string'. string.h is used to work with c-strings.
A c-string can be declared with the following command:
const char* string = "Harry";
//The `char*` must be a constant.C++ uses the string datatype to store strings.
If you are programming in c++, it is recommended to not use c-string (or any c function).
char* vs std:string vs char[] in C++ - GeeksForGeeks
Difference between char and char* in c - StackExchange
In the backend a char* is:
char[]in Cconst char[]in C++
A weird behavior of char*:
/* Will work */
const char backend_char_array[] = "abc";
const char *c = backend_char_array;
c = "Lorem ipsum dolor sit amet";
/* Will give error */
char char_arr[] = "abc";
char_arr = "Lorem";Why? Well because Arrays and pointer are not exactly the same. Arrays are more of wrapper around pointers.
Null terminator \0 is a character which tells the compiler the point where the string ends.
For example a "CS100" in its array form is ['C', 'S', '1', '0', '0', '\0']. As you can see, a 5 character long string requires an array of size 6.
Note: All char pointers declared using
newkeyword have their memory locations filled with'\0'.
// returns length of the string
int length(const char* string)
{
int i = 0;
// while(sting[i] != '\0')
while(*(string + i) != '\0')
{
i++;
}
return i;
}
int main()
{
const char* string = "CS100";
cout << length(string) << endl;
}
// 5C++ strings can be treated as arrays.
string word = "CS100";
cout << word << endl;
word[0] = 'S';
cout << word << endl; // SS100The new operator allocates memory from the heap. When you ask for a new double a storage location of type double is assigned on the heap, and a pointer to that location is returned.
You must reclaim dynamically allocated objects with the delete or delete[] operator or else you may face a memory leak.
After deleting the memory in heap, you need to delete the pointer by assigning it a value nullptr.
Using a pointer pointing to a deleted memory space can cause bugs.
int* value = new int;
delete value;
value = nullptr;How does delete[] "know" the size of the operand array?
- Uninitialized Pointers
- Memory Leak
- Dangling Pointers
The preprocessors are used to process the code before sending it to the compiler. The most common way is the file inclusion using #include <>. You can also use macro preprocessors by using #define NUMBER 1, these acts like a string substitution.
When you open a .h the contents of the file you often see looks something like this:
#ifndef main_h
#define main_h
void function_name();
#endif /* main_h */They are called as an "include guard" which checks for inclusion.
Another type of preprocessor is used by using #pragma that are used (or targeted) for specific compilers and architectures.
You can define a macro constant by using #define macro. For example:
#define NUMBER 1
int main(int argc, char const *argv[]) {
printf("%d\n", NUMBER);
return 0;
}When the above code is compiled the NUMBER is replaced by a literal value before the code reaches to the compiler. At this point you cannot get its address or use pointers.
To include a file in a C++ file you would have to use #include "file_name.h". This will place all the contents in the cpp before the code is sent to the compiler.
Preprocessor consists of different types of conditional compilation
| #if | Opening if condition |
|---|---|
| #else | else condition |
| #elif | else if condition |
| #ifdef | if defined condition |
| #ifndef | if not defined condition |
| #endif | end if condition |
Also, there are two alternatives for #ifdef and #ifndef, they are:
#if defined(macro)
#if !defined(macro)Macro's can also take parameters and replace them when called. For example:
#define ADD(a,b) (a+b)
int main(int argc, char const *argv[]) {
printf("%d\n", ADD(10,20));
return 0;
}If you want to use complex macros you can use line continuation by add \ at the end of the each line. For example:
#define LOOPER(i) do \
{ \
printf("%d\n",i++); \
} while (i < 3);There might be a situation where you might have to define a header file in another header file and when called in a C++ file you might include both header files. When you compile this you will have a Build fail, to over come this we have to include something called as Include guard. It looks something like this
#ifndef _HEADERNAME_H
#define _HEADERNAME_H
...
#endifUnderstanding lvalues and rvalues
Lvalues and Rvalues (C++) - Microsoft
CLASSES vs STRUCTS in C++ - YouTube
Structs are class like objects, whose records are public by default.
struct Student
{
string name;
int age;
};
int main()
{
Student s1;
s1.name = "Hamza";
s1.age = 19;
cout << s1.name << " is " << s1.age << " years old" << endl;
}C++ is a an Object Oriented Program, that's what makes it different from C programming language. A class is define by using class keyword followed by class name. For example:
class name_t {
int i; // Data members
public: // Function members
name_t (arguments); // Constructor
~name_t (); // Destructor
};Few points to remember:
- A class can have multiple constructor and only one destructor.
- A class when called and naming it is called an instance of that class. Example
name_t name;,nameis an instance of classname_t. - Using classes you can allocate memory properly.
class name_t {
public:
void some_name (arguments);
private:
int i;
};
void name_t::some_name (arguments){/* do something */};
int main(int argc, char const *argv[]) {
name_t obj1;
return 0;
}class name_t {
public:
void some_name (arguments);
private:
int i;
};
void name_t::some_name (arguments){/* do something */};
int main(int argc, char const *argv[]) {
name_t obj1;
return 0;
}- Interface: Usually kept in the header file.
class name_t {
private:
/* data */
public:
void some_name (arguments);
};-
Implementation: Usually kept in an implementation file
void name_t::some_name (arguments){/* do something */};
-
Usage: Usually kept in
cppfileint main(int argc, char const *argv[]) { name_t obj1; return 0; }
A virtual function is a member function in the base class that we expect to redefine in derived classes.
Basically, a virtual function is used in the base class in order to ensure that the function is overridden. This especially applies to cases where a pointer of base class points to an object of a derived class.
A virutal function can be declared using the virtual keyword.
class Base
{
public:
virtual void print()
{
// code
}
};A pure virtual function (or an abstract function) is a function that we have to overide in our derived class.
A pure virtual function can be declared using the following syntax:
virtual void show() = 0;If a class has a pure virtual function, it is considered abstract.
OPERATORS and OPERATOR OVERLOADING in C++
Operators - Overloading and Declarations
Always delete the = operator to ensure there is no accidental soft copy:
void operator=(const Classame &_) = delete;Self Assignment can result in unexpectdd errors.
// Guard self assignment
if (this == &other)
return *this;Make sure you add
#pragma onceinside your header file.
- Templates
- Lambda Functions
- Aggregate Initializiation
- Initializer Lists










