C++: Complete Developers Guide -Part 2
C++ Programmers guide- In depth
Before starting to read this please go through, C++ complete Developers Guide part-1 link.
C++ preprocessors:
It is a program that processes your source code before the compiler sees it, it strips comments from the source file and replaces them with single space then it looks for preprocessors directives and executes them.
Preprocessor directives are lines which starts with ‘#’ (hash or pound) symbol, most commonly used directive is the ‘#include’ directive, when the compiler sees this line it replaces that line with the file it is referring to, and it processes that file as well, so when the compiler sees the source code, all comments are removed and all preprocessors line has been replaced with the respective file, Preprocessors are commonly used to compile conditional code.
For eg. if you want to compile a small portion of code only if you are on windows and/or include windows specific libraries.
Important: Preprocessors does not understand C++ code.
The main function:
The main function is the one which gets executed in while we run our program, it is the entry point, all code inside main gets executed.
Main function with no arguments needs no extra information in order to run, while main function with arguments needs extra information in order to run.
#include <iostream>
using namespace std;
int main() {
cout << "Hello world";
return 0;
}
Execute: program.exe
This above program doesn’t need any extra information in order to execute, while there is another version of main which accepts arguments as below
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
cout << "Hello world" << argc;
return 0;
}
Execute: program.exe argument1 argument2
This program needs some extra information in order to be executed from the command line, here, argc stands for argument count, meaning the number of arguments or extra information that we will pass through command line, second argument that we pass is argv which stands for argument vector, that holds values or strings which we want to pass in main function, we will discuss it later on.
The main function should always return 0,
Namespaces:
Namespaces comes in handy when we use two different library and we have a name conflict between both libraries, for example, company x names cout and company y also named cout function which we want to use in our program so program doesn’t knows which cout to use, so namespace creates a containers and group the code entities as namespace scope, company x can create a name space x and within that namespace define cout function, and company y do the same thing, so if the developer needs to use company x’s cout the developer can use x::cout to access x’s cout function and y::cout to use y’s cout function. Hence, it is used to reduce name conflicts.
The ‘::’ is called a scope resolution operator.
Previously we have used namespace to remove std::cin, std::cout std::endl, as below
#include <iostream>
using namespace std;
int main() {
cout << "Hello world";
return 0;
}
However it is still not optimized to use namespace ‘std’ for this reason, using namespace ‘std’; brings all bunch of other names that are defined in that namespace, a better version is to only include those which we use.
#include <iostream>
using std::cout;
int main() {
cout << "Hello world";
return 0;
}
Note — Operator and Operand: Operator is simply what action is to perform for eg, add, subtract, divide, multiply all are operators, whereas operands are those on which an operator is applied. for eg. 2 + 3, so, 2 and 3 are operands and + is operator, combination of operator and operands are called expressions.
Basic Input Output (I/O):
cin, cout, cerr, clog, are most common basic input and output functions
1. cout and <<:
<< is insertion operator it inserts the value of operand to its left, for eg, cout << data; so here data is operand and ‘<<’ is used to insert the value of data on left hand side, to add line breaks we need to specify line break by using endl or ‘\n’ (end line character)
Note — ‘\n’ in programming language is used for line breaks.
If we use endl manipulator the input buffer stream gets flushed,
When user input multiple values the program reads it as a stream of input and assigns it to variables, if endl is used these input stream gets flushed. We will see in the file handling section later.
We can chain multiple data with << as for eg below,
cout << “the value of radius and area is: ” << radius << area;
Here, radius and area are variables declared in the program.
2. cin and >>:
>> is called extraction operator, it extracts input from the cin input stream which are added by user through keyboard, and stores in variable to the right, the extraction operator reads integer if variable to the right is of type integer, it will read float for float type, sequence of character for string type variable.
It can also be chained like cout and <<, characters are read only when the user has finished entering value and enter is pressed, when two values have been extracted using chaining as in below
cin >> data1 >> data2;
The white space, tabs new line, are considered as termination of value which have been extracted, so if user inputs.
2 3
The space here terminates, reading the value of data1, so 2 is stored in data1 and data2 will hold value as 3, the above is called input stream.
cin reading fails, when data type of variable and type of user input is different, hence data will have un-determined value.
Lets say, we want to read two values one is an integer and one double (decimal value),
cin >> intValue >> doubleValue;
So if user enters 10.5 from terminal:
10.5
‘intValue’ will hold 10 as an integer value and 0.5 will be stored in the ‘doubleValue’ variable.
Local vs global variables:
Variables declared inside any function are local to that function which cannot be accessed or used outside of that function, global variables are variables which can be accessed anywhere or inside any function.
#include <iostream>
int global_age = 10; // global variable
int main () { // main function starts here
int age {18}; // local variable to main function
cout << age << " years old";
return 0;
} // main function ends here
age = 10; // since it is local to main function it cannot be
// accessed here and it will give compile time error
Note- The control first checks the function if age is present or not, if it is present then it uses that, but if it is not present it will look into global level and check whether age is present, if it is present then it will use that and if not then it will throw an error.
Variables and its types:
Previously we saw some intro regarding types of variables, this section covers some deep detail on why data types are important.
Primitive data types are types which are directly implemented by C++, some of the commonly used primitive data types are int long float double bool char etc. We will see char, int, floating points and boolean types, it is important for a c++ developer to know how much size of memory needs to be given for a variable to hold a certain value, the size and precision is compiler dependent hence we use #include <climits> which contains all necessary stuffs.
As, we know computers store data in 0’s and 1’s, hence, the sizes are expressed in bits, the more bits we allocate, the more unique values can be represented, and more storage to represent that memory.
Formula, to get how many distinct values can be represented is 2 power of n, where n is number of bits, So, 8 bits can represent 2⁸ = 256 distinct values.
Character data type:
It is used to represent character such as ‘A’, ‘a’, ‘B’, ‘b’ etc, char data type is implemented in 8 bit which means it can represent 256 characters, enough to represent all alphabets however many language are mixture of multiple single character and symbols, unicode is the common standard to represent multiple character sets of any language.
Example:
#include <iostream>
int main () {
char initial {'K'};
cout << "My initial is: " << initial;
return 0;
}
Output: My initial is: K
Note- here we have used {} after initial which is used for value initialisation. so the variable ‘initial’ will hold value as character ‘K’.
Integer Data types:
It has signed and unsigned integer data types, the following are the types and the memory size used.
If we need to declare signed integer we don’t need to write the ‘signed’ keyword as integers are by default signed values, A long signed integer is falls in range [-2147483648 to 2147483647], whereas long unsigned integer falls in range 0 to 4294967295, that means, value greater than 2147483647 cannot be stored in long int variable we would be needing long long int to handle it, similarly, values greater to 4294967295 will not be stored in unsigned long int variables we would be needing unsigned long long int.
Example 1:
#include <iostream>
int main () {
unsigned short int exam_score {22};
cout << "My exam marks are: " << exam_score;
return 0;
}
Output: My exam marks are: 22
Example 2:
#include <iostream>
int main () {
int countries_count {65};
cout << "Countries count is: " << countries_count;
return 0;
}
Output: Countries count is: 65.
Example 3:
#include <iostream>
int main () {
long int people_in_india {13800000};
cout << "People in India is: " << people_in_india;
return 0;
}
Output: People in India is: 13800000
Example 4:
#include <iostream>
int main () {
long int people_on_earth {7'60'000'000};
cout << "People in earth is: " << people_on_earth;
return 0;
}
This will give error as narrowing conversion and it is because we are trying to fit big numbers in long int which doesn’t have space to store.
Note — This error will only be shown when we use list initialisation, if we use regular initialisation like long int people_on_earth = 7'60'000'000; then, the variable people_on_earth will get some rubbish random value.
Note — Here, in this example, we have used ticks as 7'60'000'000 so, C++ 14 standard allows us to use ticks for reading purpose, if it doesn’t compiles your compiler is not C++ 14
Fixed code:
#include <iostream>
int main () {
long long int people_on_earth {7'60'000'000}; // added long long
cout << "People on Earth: " << people_on_earth;
return 0;
}
Output: People on Earth: 760000000.
Floating Data type:
These data type are used to represent non integer values such as real numbers for eg, 0.1 ,2.4, 5.5 or pi, some numbers have infinite number of digits after decimal point and computers have finite storage, pi is perfect example of this, in such cases computer stores approximate values of such numbers, floating point numbers are stored internally as signed numbers.
Above table shows type and corresponding range with decimal digits that are supported for respective data types.
Example 1:
#include <iostream>
int main () {
float car_payment {204.1};
cout << "Your car payment is: " << car_payment;
return 0;
}
Output: Your car payment is: 204.1.
Example 2:
#include <iostream>
int main () {
double pi {3.14159};
cout << "Pi is: " << pi;
return 0;
}
Output: Pi is: 3.14159
Example 3:
#include <iostream>
int main () {
long double very_large_no {2.7e120};
cout << "very large number is: " << very_large_no;
return 0;
}
Output: very large number is: 2.7e120.
Boolean Data type:
Boolean data type is used to represent true or false value, it takes up size of 8 bit, in C++ 0 value is considered false value, and any non zero value is considered true value, boolean also holds true and false keywords as values, boolean values are much important in programming for eg, isActive, ‘gameOver’.
#include <iostream>
int main () {
bool game_over {false};
cout << "Is Game Over? : " << game_over;
return 0;
}
Output: Is Game Over ? : 0.
Here, the output should be false but in c++ the value 0 means false.
Some overflow example:
#include <iostream>
int main () {
short int value1 {30000};
short int value2 {1000};
short product {value1 * value2}; // must use long int product
cout << "Product of value1 and value 2 is: " << product;
return 0;
}
Output: Product of ‘value1' and value 2 is: -2763.
This value is wrong as the product of value1 and value2 yields a number which cannot be fit in short range hence, we must use long int product.
‘sizeof’ operator:
Simple way to determine size of data type by using ‘sizeof’ operator. For eg, ‘sizeof(int)’, ‘sizeof(double)’, ‘sizeof(some_variable)’ etc, ‘sizeof’ operator gets information from two header files ‘climits’ and ‘cfloats’, these files also provides bunch of handy constants, which can be used to determine the precision of our data types, for eg, INT_MAX tells us the maximum integer value we can store in on an int data type in specific machine.
#include <iostream>
#include <climits>
#include <cfloat>
using std::cout;
int main () {
cout << "sizeof information" << endl << "================"<< endl;
cout << "char: "<< sizeof(char) << endl;
cout << "int: "<< sizeof(int) << endl;
cout << "unsigned int: "<< sizeof(unsigned int) << endl;
cout << "short: "<< sizeof(short) << endl;
cout << "long: "<< sizeof(long) << endl;
cout << "long long: "<< sizeof(long long) << endl;
cout << "float: "<< sizeof(float) << endl;
cout << "double: "<< sizeof(double) << endl;
cout << "long double: "<< sizeof(long double) << endl;
cout << "======================="<< endl<<"Minimum values:"<<endl;
cout << "char: "<<CHAR_MIN<< endl;
cout << "int: " << INT_MIN << endl;
cout << "short: " << SHRT_MIN << endl;
cout << "long: " << LONG_MIN << endl;
cout << "long long: " << LLONG_MIN << endl;
cout << "======================"<< endl <<"Maximum values:"<<endl;
cout << "char: "<<CHAR_MAX << endl;
cout << "int: " << INT_MAX << endl;
cout << "short: " << SHRT_MAX << endl;
cout << "long: " << LONG_MAX << endl;
cout << "long long: " << LLONG_MAX << endl;
int age {21};
double wage {22.54};
cout << "Size of age is: " << sizeof age << endl;
cout << "Wage is: "<< sizeof(wage) << endl; //both are same
return 0;
}
Output:: the output may be different in different machine
sizeof information
==================
char: 1
int: 4
unsigned int: 4
short: 2
long: 4
long long: 8
float: 4
double: 8
long double: 12
==================
Minimum values
char: -128
int: -2147483648
short: -32768
long: -2147483648
long long: -9223372036854775808
==================
Maximum values
char: 128
int: 2147483648
short: 32768
long: 2147483648
long long: 9223372036854775808
Age is: 4
wage is: 8
Every value above unit is byte, ‘sizeof’ age and ‘sizeof(age)’ both can be used.
Constants in C++:
Constants are variables which when assigned a value cannot be changed, There are many types of constants:
Note — Constants expressions (constexpr keyword), Enumerated constants (enum keyword) will be seen in later chapters.
1. Literal constants:
Literal constants are simple constants for eg. pi = 3.14, days _in_week = 7 etc, etc.
We can explicit with the type of literal constants as in case of integer literal constants, we add suffixes to integer literal to specify different type, for eg U and L represent, unsigned and long, respectively, which can be lower case or uppercase, for eg 12U, 12L , 12LL etc.
For floating point suffixes we can use F and L for float and long double, respectively, for eg, 12.1, 12.1F 12.2L.
We also have character literal constants,
\n for new line,
\t for new tab,
\r for return,
\b for backspace,
\’ single quote,
\” double quote,
\\ backslash.
These are used in string literals, for eg
cout << “Hello \t there \n my friend \n”;
This will output:
Hello there
my friend
2. Declared constants (const keyword):
The most used constants declaration is declared constants, by using const keyword, for eg, const float pi {3.145926}; we always need to initialise declared constants with its initial value or else compiler will give you error.
3. Defined constants (#define keyword):
Never use defined constants in modern c++ development, in old c++ program development defined constants were used, The compiler doesn’t understand defined constants and never throws error, as it is preprocessed.
Syntax:
#define pi 3.145926
Let's use this,
Problem statement: Consider, you have a bike repair service, you charge $30 for one bike + 6% tax, estimates are valid for 30 days,
Prompt number of bike that user will repair, and provide your estimation such as:
Bike repair service:
Number of Bikes: 2
Price per Bike: $30
cost: $60
tax: $3.6
Code without constants:
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main () {
cout << "Welcome to Bike repair garage" << endl;
cout << "\nHow many bikes would you like to repair?" << endl;
int bike_count {0};
cin >> bike_count;
cout << "\nEstimate for Bike repairing:" << endl;
cout << "\n Number of Bikes: " << bike_count;
cout << "\n Price per Bike: $<< 30 << endl;
cout << "Cost: $" << 30 * bike_count << endl;
cout << "Tax: $" << 30 * bike_count * 0.06 << endl;
// 0.06
// because of 6% i.e. 6/100 ~ 0.06
cout << "====================================" << endl;
cout << "Total estimate:"<<(30* bike_count)+(30*bike_count *0.06)<<endl;
cout << "This estimate is valid for "<< 30<<"days"<<endl;
cout << endl;
}
Code with using constants:
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main () {
cout << "Welcome to Bike repair garage" << endl;
cout << "\nHow many bikes would you like to repair?" << endl;
int bike_count {0};
cin >> bike_count;
const double price_per_bike {30.0};
const double sales_tax {0.06};
const int expiry_duration {30}; // days
cout << "\nEstimate for Bike repairing:" << endl;
cout << "\n Number of Bikes: " << bike_count;
cout << "\n Price per Bike: $<< price_per_bike << endl;
cout << "Cost: $" << price_per_bike * bike_count << endl;
cout << "Tax: $" << price_per_bike * bike_count * sales_tax <<
endl;
cout << "===============================" << endl;
cout << "Total estimate:"<<(price_per_bike* bike_count)+
(price_per_bike*bike_count *sales_tax)<<endl;
cout << "This estimate is valid for "<< expiry_duration<<"days"
<<endl;
cout << endl;
}
This is called refactoring meaning changing the code without affecting the behavior of the code.
The third part of this series can be found by clicking here.
Pls, do share this with as many people as you can.
TLDR;
For more tech related blogs please visit:
khizaruddins.medium.com
Follow me on twitter and instagram
Buy me a Coffee.