c++ text book
c++ text book
In C++, variables
must be declared with a specific data type, which determines the kind of data they can
store.
Declaration:
Int x; → This tells the compiler to reserve memory for an integer variable x, but it does not
assign any value. The content of x is undefined until explicitly assigned.
Initialization:
X = 10; → This assigns the value 10 to x. If x was previously uninitialized, it now holds a
definite value.
Int x = 10; → This both declares x and initializes it with 10 in a single step.
This is the most common way to define variables when an initial value is available.
Data Types
In C++, data types specify the kind of data a variable can store. Understanding them is
crucial for efficient memory management and program correctness.
Integer types store whole numbers and can be signed (default) or unsigned.
Int is the most commonly used integer type and typically occupies 4 bytes of memory.
Short int (or simply short) is a smaller integer type, usually 2 bytes.
Long long int (or long long) is an extended integer type that usually takes 8 bytes, allowing
for very large numbers.
Unsigned versions (e.g., unsigned int, unsigned long) store only non-negative values,
effectively doubling the maximum positive range.
Floating-Point Types
Float is a single-precision floating-point type that typically takes 4 bytes and provides
around 6-7 decimal digits of precision.
Double is a double-precision floating-point type that usually takes 8 bytes and provides
around 15-16 decimal digits of precision.
Long double offers even higher precision and may take 8 to 16 bytes, depending on the
system.
Character Type:
The char data type stores a single character and typically takes 1 byte.
Wchar_t (wide character) is used for Unicode characters and may take 2 or 4 bytes.
Char16_t and char32_t are specialized types used for UTF-16 and UTF-32 encoding,
respectively.
Boolean Type
The bool data type represents true or false values and typically takes 1 byte
Derived data types are built using primitive data types. They help manage complex data
structures efficiently and improve code organization. The primary derived data types in
C++ are:
1. Arrays
2. Pointers
3. References
4. Function Pointers
1. Arrays
An array is a collection of elements of the same data type, stored in contiguous memory
locations. Arrays allow multiple values to be stored under a single variable name, making
data management easier.
Int arr[5] = {10, 20, 30, 40, 50}; // Declaration and Initialization
2. Pointers
A pointer is a variable that stores the memory address of another variable. They allow
direct memory access and manipulation, making them crucial for dynamic memory
allocation, arrays, and function calls.
Int x = 10;
The dereference operator (*) allows accessing the value stored at a pointer’s address.
A void pointer is a generic pointer that can store the address of any data type.
Void* ptr;
Int x = 10;
Int x = 10;
Int main() {
Int a = 5;
Update(a);
4. Function Pointers
A function pointer is a pointer that stores the address of a function, allowing dynamic
function calls.
Void greet() {
Int main() {
#include <iostream>
Cout << a + b;
Int main() {
Conclusion
Derived data types extend the capabilities of primitive types, enabling more complex and
efficient programs.
#include <iostream>
Using namespace std;
Struct Student {
Int id;
Char name[50];
Float marks;
};
Int main() {
Student s1 = {101, “John”, 85.5};
Cout << “ID: “ << s1.id << “, Name: “ << s1.name << “, Marks: “ << s1.marks;
}
A class (class) is an advanced structure that supports data encapsulation and object-
oriented programming (OOP). A class contains data members (variables) and member
functions (methods).
#include <iostream>
Using namespace std;
Class Car {
Public:
String brand;
Int year;
Void display() {
Cout << “Brand: “ << brand << “, Year: “ << year;
}
};
Int main() {
Car myCar;
myCar.brand = “Tesla”;
myCar.year = 2022;
myCar.display();
}
A union (union) is similar to a structure, but all members share the same memory
location, meaning only one member can hold a value at a time. This makes unions
memory-efficient but limits simultaneous data storage.
#include <iostream>
Using namespace std;
Union Data {
Int i;
Float f;
};
Int main() {
Data d;
d.i = 10;
cout << “Integer: “ << d.i << endl;
d.f = 3.14; // Overwrites previous value
cout << “Float: “ << d.f << endl;
}
#include <iostream>
Using namespace std;
Enum Status { SUCCESS = 1, FAILURE = -1, PENDING = 0 };
Int main() {
Status currentStatus = SUCCESS;
Cout << currentStatus; // Outputs 1
}
The typedef keyword and using alias allow renaming data types for better readability.
Typedef unsigned int uint;
Uint age = 25;
Cout << age; // Outputs 25
Alternatively, using can be used for type aliasing.
Using uint = unsigned int;
Uint salary = 50000;
Cout << salary;
User-defined data types enhance C++ by providing structured, reusable, and efficient
code. Structures and classes improve data organization, unions optimize memory usage,
enumerations make constants meaningful, and type aliases improve code readability.
Formula to Calculate the Range of Data Types
The range of a data type depends on the number of bits used for storage and whether it is
signed (can store negative values) or unsigned (only positive values).
Since all bits are used for magnitude, the range is:
0 to (2ⁿ - 1)
Example: For a 32-bit (4-byte) unsigned int,
0 to (2³² - 1) = 0 to 4,294,967,295
To check the range dynamically, you can use the limits library:
#include <iostream>
#include <limits>
Using namespace std;
Int main() {
Cout << “Range of int: “ << numeric_limits<int>::min() << “ to “ <<
numeric_limits<int>::max() << endl;
Cout << “Range of float: “ << numeric_limits<float>::min() << “ to “ <<
numeric_limits<float>::max() << endl;
Cout << “Range of double: “ << numeric_limits<double>::min() << “ to “ <<
numeric_limits<double>::max() << endl;
}
String in C++ vs. String Class (std::string)
int main() {
char str[] = "Hello"; // Null-terminated string
cout << str; // Outputs: Hello
}
String functions from <cstring> are used for operations like copying and concatenation.
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char str1[20] = "Hello";
char str2[] = "World";
The std::string class (from <string>) provides a more flexible and safer way to work with
strings.
Declaring and Using a std::string
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Hello, World!";
cout << str; // Outputs: Hello, World!
}
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1 = "Hello";
string s2 = "World";
Scope in C++ defines where a variable or function can be accessed and how long it
remains in memory. Scope determines the lifetime and visibility of variables, ensuring
proper memory management and avoiding conflicts.
1. Local Scope
A local variable is declared inside a function or block ({}) and only exists within that
function or block. It is destroyed when the function/block exits.
Example: Local Variable in a Function
#include <iostream>
Using namespace std;
Void display() {
Int x = 10; // Local variable
Cout << x; // Accessible here
}
Int main() {
Display();
// cout << x; // Error: x is not accessible outside display()
}
Key Points:
X is created when display() is called.
X is destroyed after display() ends.
Cannot be accessed outside display().
2. Global Scope
A global variable is declared outside all functions and can be accessed anywhere in the
program. It exists throughout program execution.
Void display() {
Cout << globalVar; // Accessible inside any function
}
Int main() {
Display();
Cout << globalVar; // Also accessible here
}
Key Points:
globalVar is accessible in both display() and main().
Global variables persist throughout the program.
Disadvantage: Can cause naming conflicts and hard-to-debug errors.
3. Block Scope
A block-scoped variable is declared inside {} and exists only within that block. It cannot
be accessed outside the block.
#include <iostream>
Using namespace std;
Int main() {
{
Int num = 42;
Cout << num; // Accessible here
}
// cout << num; // Error: num is not accessible outside the block
}
Key Points:
4. Function Scope
A function has its own scope, meaning its code cannot be accessed outside its definition.
However, functions can be called from anywhere in the program.
#include <iostream>
Using namespace std;
Void greet() {
Cout << “Hello, World!”;
}
Int main() {
Greet(); // Valid: Calling the function
// cout << greet; // Error: Cannot access function body directly
}
Key Points:
The function greet() can be called anywhere, but its contents are not directly accessible.
A function must be declared before it is used.
5. Class Scope
Class members (variables and functions) belong to a class and can only be accessed
using an object of that class.
Private members can be accessed only inside the class.
Public members can be accessed outside the class.
Example: Class Scope
#include <iostream>
Using namespace std;
Class Car {
Private:
Int speed; // Private (only accessible inside class)
Public:
Void setSpeed(int s) { speed = s; }
Void showSpeed() { cout << speed; }
};
Int main() {
Car myCar;
myCar.setSpeed(100);
myCar.showSpeed(); // Valid
// cout << myCar.speed; // Error: speed is private
}
Key Points:
6. Namespace Scope
Namespaces group related variables, functions, and classes to avoid naming conflicts.
The std namespace contains standard functions like cout and cin.
Example: Using a Namespace
#include <iostream>
Using namespace std; // Uses standard namespace
Namespace MyNamespace {
Int x = 10;
}
Int main() {
Cout << MyNamespace::x; // Accessing namespace variable
}
Key Points:
Avoids naming conflicts by grouping identifiers.
Must use namespace_name::variable_name to access variables.
A static global variable is accessible only within the file where it is declared.
Example: File Scope
#include <iostream>
Using namespace std;
Void display() {
Cout << fileVar;
}
Int main() {
Display();
}
Key Points:
Static restricts global variable access to the same file.
Useful for modular programming.
Scope Resolution Operator ::
Used to access global variables, class members, and namespace members when there
is a naming conflict.
Example: Accessing a Global Variable with ::
#include <iostream>
Using namespace std;
Int main() {
Int x = 10; // Local variable
Cout << x; // Outputs local x (10)
Cout << ::x; // Outputs global x (50)
}
Key Points:
Local and global variables with the same name exist separately.
::x accesses the global variable.
Key Takeaways
1. Local variables exist only inside a function/block and are destroyed after
execution.
2. Global variables exist throughout the program but can lead to conflicts.
3. Class members are private by default, requiring public methods for access.
5. Static global variables have file scope, limiting access to the same file.
Type casting is the process of converting one data type into another. In C++, there are two
types of type casting:
1. Implicit Type Casting (Automatic Conversion)
2. Explicit Type Casting (Manual Conversion)
#include <iostream>
Using namespace std;
Int main() {
Int num = 10;
Double result = num; // Implicit conversion (int → double)
Cout << result; // Outputs: 10.0
}
Key Points:
Explicit type casting is done manually when converting data types that might lead to data
loss.
1. C-Style Casting
2. Function-Based Casting (static_cast, dynamic_cast, reinterpret_cast,
const_cast)
2.1 C-Style Casting (Using Parentheses or type before a value)
This is the traditional method of type conversion.
Example: C-Style Casting
#include <iostream>
Using namespace std;
Int main() {
Double pi = 3.14159;
Int num = (int)pi; // C-style type casting
Cout << num; // Outputs: 3 (decimal part is removed)
}
Key Points:
The static_cast is the preferred method for type conversion in modern C++. It performs
safe conversions and is more readable.
#include <iostream>
Using namespace std;
Int main() {
Double pi = 3.14159;
Int num = static_cast<int>(pi); // Explicit conversion
Cout << num; // Outputs: 3
}
Key Points:
Safer than C-style casting.
Only allows compatible conversions (e.g., float to int, int to double).
#include <iostream>
Using namespace std;
Class Base {
Public:
Virtual void show() { cout << “Base class”; }
};
Int main() {
Base* basePtr = new Derived();
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // Safe downcasting
If (derivedPtr) {
derivedPtr->show(); // Outputs: Derived class
} else {
Cout << “Type conversion failed!”;
}
}
Key Points:
Used for safe downcasting in inheritance.
Works only with polymorphic classes (must have at least one virtual function).
Used for low-level conversions (e.g., converting a pointer of one type to another).
Unsafe and should be used cautiously.
Example: Using reinterpret_cast
#include <iostream>
Using namespace std;
Int main() {
Int num = 65;
Char* ptr = reinterpret_cast<char*>(&num); // Interpret int as char pointer
Cout << *ptr; // May output: ‘A’ (ASCII 65)
}
Key Points:
Converts an integer pointer to a character pointer.
Useful in low-level programming but risky.
Int main() {
Int num = 10;
changeValue(&num);
cout << num; // Outputs: 20
}
Key Points:
Const_cast removes const, allowing modification.
Use cautiously, as modifying const data can cause undefined behavior.
Summary
7. Const_cast removes or adds const to variables and should be used only when
necessary.
The const keyword makes a variable read-only, meaning its value cannot be
modified after initialization.
#include <iostream>
Using namespace std;
Int main() {
Const int x = 10;
Cout << x << endl;
Key Points:
Used for fixed values like PI, configuration settings, and function parameters.
The volatile keyword tells the compiler not to optimize a variable because its value
may change unexpectedly (e.g., due to hardware events, multithreading, or
system processes).
#include <iostream>
Using namespace std;
Volatile int flag = 0; // Value can change due to external factors
Int main() {
While (flag == 0) {
// Code keeps running until flag is changed
}
Cout << “Flag changed!”;
}
Key Points:
Prevents compiler optimization, ensuring every read operation fetches the latest
value.
The auto keyword allows the compiler to automatically infer the variable type.
#include <iostream>
Using namespace std;
Int main() {
Auto x = 10; // Compiler infers int
Auto y = 3.14; // Compiler infers double
Auto text = “Hello”; // Compiler infers const char*
Key Points:
A variable in C++ is a named storage location in memory that holds a value. Its
value can be changed during the execution of a program.
Int x; // Declaration
X = 10; // Initialization
Int y = 20; // Declaration and Initialization
Declaration: Tells the compiler about the variable’s name and type.
Unsigned: Can hold only non-negative values, doubling the positive range.
Float: 4 bytes
Double: 8 bytes
Int x = 10;
Int *ptr = &x;
Int x = 10;
Int &ref = x;
Cannot be reassigned.
Struct Person {
String name;
Int age;
};
Person p;
p.name = “John”;
p.age = 30;
Class Car {
Public:
String brand;
};
Car myCar;
A memory-efficient data type where all members share the same memory space.
(Continuing with Scope, Type Casting, and String Handling in next sections...)
1. Addition (+)
Used to add two numbers.
Works with integers, floating-point numbers, and characters (ASCII values).
Example:
Int a = 10, b = 5;
Cout << (a + b); // Output: 15
2. Subtraction (-)
Used to subtract one number from another.
Works with integers and floating-point numbers.
Example:
Int a = 10, b = 5;
Cout << (a – b); // Output: 5
3. Multiplication (*)
Used to multiply two numbers.
Example:
Int a = 10, b = 5;
Cout << (a * b); // Output: 50
4. Division (/)
Used to divide one number by another.
If both numbers are integers, the result is an integer (decimal part is ignored).
Example:
Int a = 10, b = 3;
Cout << (a / b); // Output: 3 (not 3.33)
If at least one number is a floating-point type (float or double), the result includes
decimals:
Double x = 10, y = 3;
Cout << (x / y); // Output: 3.33333
5. Modulus (%)
Returns the remainder of integer division.
Works only with integer values.
Example:
Int a = 10, b = 3;
Cout << (a % b); // Output: 1 (remainder of 10/3)