0% found this document useful (0 votes)
5 views133 pages

c-language

The document provides an overview of the C programming language, its history, and its influence on other languages like C++ and Java. It discusses the use cases of C in operating systems, embedded systems, and compilers, as well as key concepts such as machine code, assembly code, and data types. Additionally, it covers basic programming constructs, memory management, and input/output operations in C.

Uploaded by

prakashv0841
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views133 pages

c-language

The document provides an overview of the C programming language, its history, and its influence on other languages like C++ and Java. It discusses the use cases of C in operating systems, embedded systems, and compilers, as well as key concepts such as machine code, assembly code, and data types. Additionally, it covers basic programming constructs, memory management, and input/output operations in C.

Uploaded by

prakashv0841
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 133

C/C++ - language

Jussi Pohjolainen
C: Mother of all Languages
• Many programming languages are directly derived from C or are heavily influenced by its
syntax and design
• C++:
• Built on C with object-oriented features.
• Objective-C:
• A C-based language with object-oriented extensions.
• Java and C#:
• Adopted C-like syntax and many concepts.
• JavaScript, Go, Rust, Swift, PHP, ...
• Designed in the 70s!
• 1978: Kernighan + Ritchie: "The C Programming Language"
• From 1989 -> 2018 ANSI C standard.
• 2018: C18 (ISO/IEC 9899:2018) language standard
• Free doc: https://en.cppreference.com/w/c
Use Cases?
• Operating Systems:
• C is frequently used to develop operating systems due to its low-level capabilities and
direct access to system hardware. Examples include UNIX, Linux, Windows, and macOS
kernels.
• Embedded Systems:
• C's ability to directly interact with hardware makes it ideal for programming
microcontrollers and embedded systems found in appliances, automotive systems, and
consumer electronics.
• Compilers and Interpreters:
• Many compilers and interpreters for other programming languages are themselves
written in C due to its performance and ability to manipulate system resources
effectively.
• Game Development, Networking, IoT Devices, Libraries...
Machine Code
• Definition: The lowest-level programming language, consisting of
binary code (0s and 1s) that the CPU directly executes.
• Human Readability: Not human-readable; it's difficult to interpret
and write directly.
• Portability: Not portable across different types of CPUs, as
different CPUs have different instruction sets.
• Usage: Used for critical performance-sensitive applications, but
typically generated automatically by compilers.
Assembly Code
• Definition: A low-level programming language that provides a
symbolic representation of machine code instructions.
• Human Readability: Slightly human-readable with mnemonics
for operations (e.g., MOV, ADD) and labels for memory addresses.
• Portability: Hardware-specific and not portable across different
CPU architectures.
• Usage: Used for system programming, device drivers, and
performance-critical code where hardware control is necessary.
• First C – compiler was written with assembly
Assembly:
x86
processor
Assembly:
ARM64
An instruction set
• An instruction set architecture (ISA), is a set of commands that a particular
processor (CPU) can execute
• These instructions are low-level commands that tell the CPU to perform
basic operations
• add, subtract, ..
• AND, OR, XOR
• Data movement
• Control Flow
• Input / Output
• Assembly code is basically using these instruction sets
• x86, ARM, MIPS, PowerPC
Compiling
• Assembly code is compiled into machine code using a tool called
assembler
• NASM (Linux + Windows)
• MASM (Microsoft Macro Assembler)
• FASM (Flast Assembler)
• Translates the assembly instructions into binary machine code
that CPU can execute
Problems with Assembly
• Productivity
• Portability
• Maintenance
• Development tools
C - language
• High – level language
• More focus on programming logic than detailed knowledge of
hardware
• Portability: same code can be compiled to different architectures
• Readability
• Maintainability
// Preprocessor directive to include the standard input-output header file.
// This file contains declarations for the I/O functions like printf and scanf.
#include <stdio.h>

// The main function where program execution begins.


// It returns an integer value to the operating system.
int main() {

// The printf function is used to print the string "Hello, World!" to the console.
// The \n is a newline character, which moves the cursor to the next line after printing the string.
printf("Hello, World!\n");

// The return statement ends the main function and returns the value 0 to the operating system.
// Returning 0 typically indicates that the program finished successfully.
return 0;
}
Compile and Run
gcc hello.c -o hello
./hello
GCC Compiler
• GCC (GNU Compiler Collection) is a compiler system developed
by the GNU Project
• C, C++, Objective-C, Fortran, Ada, and others
• Open source and free
Installing
• macOS
• Install Xcode command line tools
• Linux (Debian/Ubuntu)
• sudo apt update && sudo apt install gcc
• Windows
• https://winlibs.com/
WinLibs
• Win32 vs. Win64:
• Choose based on whether you need a 32-bit or 64-bit toolchain.
• 64-bit is generally preferred for modern development due to better performance and
the ability to handle larger memory.
• Posix vs MCF
• POSIX Threads
• Standard threading model used in Unix-like systems. Code is portable across systems. Widely
Supported. #include <pthread.h>
• MCF Threads
• Not standardized, less portable, designed for massive concurrency, efficiently handling very
large number of threads.
Variables
Basic Types
• int (32 bits, 4 bytes)*
• Stores integers (whole numbers), both positive and negative.
• float (32 bits, 4 bytes)*
• Stores single precision floating point numbers (numbers with a fractional part).
• double (64 bits, 8 bytes)*
• Stores double precision floating point numbers, providing more precision than float.
• char (8 bits, 1 byte)*
• Stores individual characters or small integers (usually 1 byte).
• * Usually, can vary depending on OS and compiler
Bits, Byte?
bit: 0 or 1
byte (8 bits): 01011010

// Example, character 'a'


byte (8 bits): 01100001 => integer 97 => 'a'
32 bits, 4 bytes
32 bits / 4 bytes: 00000000 0000000 0000000 01100001
Basic Types
int age = 30; // An integer variable
int temperature = -5; // Can store negative values

float weight = 65.5; // A floating-point number


float height = 175.0f; // Suffix 'f' denotes a float literal

double distance = 123.456; // A double precision floating point number

char initial = 'A'; // Stores a single character


char escape = '\n'; // Escape character for new line
Modifier types
• signed
• Allows storage of both positive and negative numbers.
• unsigned
• Only allows positive values and zero, effectively doubling the maximum
value of a data type.
• short
• Used with int to specify a shorter integer.
• long
• Used with int to specify a longer integer.
Derived types
• Arrays
• A fixed-size sequence of elements of a single type, e.g., int arr[10];.
• Pointers
• Variables that store memory addresses of another variable, e.g., int *ptr;.
• Structures
• A user-defined data type that allows the combination of data items of different kinds,
e.g., struct { int age; char *name; } person;.
• Union
• Similar to structures, but the members that share the same memory location, allowing
different types of data in the same location at different times.
• Function Pointers
• Variables that point to functions.
Modifier Types
unsigned int followers = 5000; // Only positive numbers

short int distance = 32000; // Short integer, typically 2 bytes


long int population = 1000000; // Long integer, typically 4 or 8 bytes
unsigned long int stars = 4294967295; // Large range positive numbers

signed short temperature = -32768; // Allows for negative numbers in a small range
Modifier Types
#include <stdio.h>
#include <math.h>

int main() {
unsigned long x = 18446744073709551615UL;
printf("%lu", x);
return 0;
}
Casting
• Casting in C is a way to convert a variable from one data type to
another.
• This can be done explicitly using casting operators or implicitly by
the compiler
Explicit Casting
• Casting in C is a way to convert a variable from one data type to
another.
• This can be done explicitly using casting operators or implicitly by
the compiler
• Example
int i = 10;
float f = (float) i;
double d = 9.5;
int x = (int) d;
float temp = 65.99;
char ch = (char) temp;
Implicit Casting
• Implicit casting is automatically performed by the compiler when
passing values between different types without explicit cast
• However, care must be taken as implicit casting can sometimes
lead to unexpected results or data loss:
• Example
int i = 42;
float f = i; // We do not lose information
Output and Input
Output
• The printf function in C is a standard output function that is used
extensively for formatting and printing data to the console
• int printf(const char *format, ...);
• format: A format string that includes text to be printed,
placeholders for variables (format specifiers), and formatting
instructions.
• ...: Represents a variable number of arguments that replace the
format specifiers in the format string.
Format Specifiers
Format Specifier Description Example Value Printed Output
%d or %i Integer in decimal base 42 42
%u Unsigned decimal integer 150 150
%f Floating-point number 3.14159 3.141590
Double precision floating
%lf point (used interchangeably 3.1415926535 3.141593
with %f in printf)
Scientific notation
%e or %E 123456.789 1.234568e+05
(lowercase or uppercase)
Shortest representation of
%g or %G %f or %e (lowercase or 0.00012345 1.2345e-04
uppercase)
Unsigned hexadecimal
%x or %X integer (lowercase or 255 ff or FF
uppercase)
%o Unsigned octal integer 10 12
%c Character 65 A
%s String "Hello" Hello
%p Pointer address Address of x 0x7ffeefbff8d8
%% Percent sign N/A %
Escape Sequences
• \n: New line
• \t: Horizontal tab
• \a: Alert (bell) character
• \\: Backslash
• \": Double quote
Examples
printf("Hello, world!\n");
printf("Temperature: %.2f degrees\n", 23.456);
printf("Character: %c\n", 'A');
printf("Hexadecimal: %#x\n", 255);
Input
• The scanf function in C is used to read formatted input from the standard
input, typically the keyboard.
• It is one of the most common input functions in C and serves as a
counterpart to printf, which is used for formatted output.
• int scanf(const char *format, ...);
• format: A format string that contains one or more format specifiers, which
specify the type and format of the data to be read. This string also can
contain literals and whitespace characters, which are used to match the
input.
• ...: The additional arguments must be pointers to variables where the read
values are stored.
Format specifiers
• %d - Reads an integer.
• %f - Reads a float.
• %lf - Reads a double.
• %c - Reads a single character.
• %s - Reads a string until a whitespace is encountered.
• %[...] - Reads a string that matches a set of characters specified
within the brackets.
Examples
int number;
printf("Enter an integer: ");
scanf("%d", &number);
printf("You entered: %d\n", number);
Examples
float pi;
printf("Enter a floating point number: ");
scanf("%f", &pi);
printf("You entered: %f\n", pi);
Examples
char ch;
printf("Enter a character: ");
scanf("%c", &ch);
printf("You entered: %c\n", ch);
Examples
int day, month, year;
printf("Enter day, month, and year: ");
scanf("%d %d %d", &day, &month, &year);
printf("Entered date is: %02d/%02d/%d\n", day, month, year);
Control Flow
If else
int number = 10;
if (number > 0) {
printf("The number is positive.\n");
} else if (number < 0) {
printf("The number is negative.\n");
} else {
printf("The number is zero.\n");
}
switch
char grade = 'B';

switch (grade) {

case 'A':
printf("Excellent!\n");

break;

case 'B':

case 'C':

printf("Well done\n");

break;

case 'D':

printf("You passed\n");

break;

case 'F':

printf("Better try again\n");

break;

default:
printf("Invalid grade\n");

}
while
int count = 5;
while (count > 0) {
printf("Count = %d\n", count);
count--;
}
for
for (int i = 0; i < 5; i++) {
printf("i = %d\n", i);
}
do while
int a = 5;
do {
printf("a = %d\n", a);
a--;
} while (a > 0);
Conditions
• Conditions within if statements are evaluated as Boolean
expressions where the integer zero (0) represents FALSE
• Any non-zero value is treated as TRUE.
• if(1) { .. }
Quick Start to Memory
Storage Typical Use
Type Location Initialization Lifetime Scope Cases
Limited to the Temporary data
Duration of
Local Stack Not automatic block where within
function call
declared functions
Data needed
Automatic Accessible from
Data Segment Entire program across multiple
Global (zero if any part of the
(.data or .bss) duration functions or
uninitialized) program
modules

RAM Static (within Data Segment


Automatic
(zero if
Entire program
Limited to the
function/block
Preserving
state between
functions) (.data or .bss) duration
uninitialized) declared function calls
Automatic Limited to the
Data Segment Entire program Module-wide
Static (global) (zero if file where
(.data or .bss) duration private data
uninitialized) declared
Flexible size
data or when
Controlled by Controlled by
Dynamic Heap Not automatic amount is
programmer pointers
unknown at
compile time
Stack
• Stack allocation is faster than heap allocation
• Memory on the stack is automatically created when a function
starts and cleaned up when the function exits
• Best used for small data that will not need to be resized and for
data whose lifetime is well-known and coincides with the scope of
the block in which it is declared
Heap
• The heap is a more loosely managed pool of memory where
blocks of memory are dynamically allocated and freed, often in an
arbitrary order.
• The heap can grow dynamically and is generally limited by the size
of the virtual memory in the operating system.
• Heap allocation involves more complex management, which can
include searching for a block of free memory of adequate size,
which makes it slower compared to stack allocation
• The lifetime of heap variables is controlled by the programmer
Stack
#include <stdio.h>

void function() {
int stackVar = 10; // Local variable allocated on the stack
printf("Stack variable value: %d\n", stackVar);
}

int main() {
function();
return 0;
}
Pointers and references
#include <stdio.h>

#include <stdlib.h>

int main() {

int a = 5;

printf("Address of a is %p\n", &a);

int *memoryAddressOfA = &a;

printf("Address is a is %p\n", memoryAddressOfA);

// let's change a

*memoryAddressOfA = 6;

printf("Value of a is %d\n", a);

return 0;

}
Heap
#include <stdio.h>

#include <stdlib.h>

int main() {

int *heapVar = malloc(sizeof(int)); // Allocate memory on the heap

printf("Address is %p\n", heapVar);

printf("Value is %d\n", *heapVar);

*heapVar = 20; // Assign value to allocated memory

printf("Heap variable value: %d\n", *heapVar);

free(heapVar); // Free the allocated memory

heapVar = NULL; // Good practice to set pointer to NULL after freeing

return 0;

}
Memory Leak
#include <stdio.h>

#include <stdlib.h>

int main() {

if(1) {

int *heapVar = malloc(sizeof(int)); // Allocate memory on the heap

printf("Address is %p\n", heapVar);

printf("Value is %d\n", *heapVar);

*heapVar = 20; // Assign value to allocated memory

printf("Heap variable value: %d\n", *heapVar);

// free(heapVar); // Free the allocated memory

// heapVar = NULL; // Good practice to set pointer to NULL after freeing

return 0;

}
Fix
#include <stdio.h>
#include <stdlib.h>

int main() {
int *heapVar = NULL; // Declare heapVar outside the if block

if(1) {
heapVar = malloc(sizeof(int)); // Allocate memory on the heap
printf("Address is %p\n", heapVar);
*heapVar = 20; // Assign value to allocated memory
printf("Value is %d\n", *heapVar);
printf("Heap variable value: %d\n", *heapVar);
}

// Free the allocated memory outside the if block


if (heapVar != NULL) {
free(heapVar);
heapVar = NULL; // Good practice to set pointer to NULL after freeing
}

return 0;
}
Arrays
Arrays
• Arrays in C are fundamental data structures that consist of
elements of the same data type placed contiguously in memory
Array in Stack
#include <stdio.h>

int main() {
int arr[5] = {1, 2, 3, 4, 5}; // Array declared on the stack
int i; // Loop variable also on the stack

printf("Array elements are: ");


for (i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
Array in Heap
#include <stdio.h>
#include <stdlib.h> // Include for malloc and free functions

int main() {
int size = 5;
int *arr = malloc(size * sizeof(int)); // Dynamically allocate memory for the array on the
heap

// Initialize array elements


for (int i = 0; i < size; i++) {
arr[i] = i + 1; // Assign values to the array
}

printf("Array elements are: ");


for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");

free(arr); // Free the allocated memory


arr = NULL; // Set pointer to NULL to avoid dangling pointer

return 0;
}
Dynamic array in heap
#include <stdio.h>
#include <stdlib.h> // Include for malloc and free functions

int main() {
int size;

// Ask user for the size of the array


printf("Enter the size of the array: ");
scanf("%d", &size);

int *arr = malloc(size * sizeof(int)); // Dynamically allocate memory for the array on the heap

// Initialize array elements


for (int i = 0; i < size; i++) {
arr[i] = i + 1; // Assign values to the array
}

printf("Array elements are: ");


for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");

free(arr); // Free the allocated memory


arr = NULL; // Set pointer to NULL to avoid dangling pointer

return 0;
}
Pointers with Arrays
#include <stdio.h>
#include <stdlib.h>

int main() {
// Allocate memory for three integers
int *numbers = malloc(3 * sizeof(int));

// Initialize the integers using pointer arithmetic


*numbers = 1; // Equivalent to numbers[0] = 1
*(numbers + 1) = 2; // Equivalent to numbers[1] = 2
*(numbers + 2) = 3; // Equivalent to numbers[2] = 3

// Print the integers using pointer arithmetic


printf("First integer: %d\n", *numbers); // Outputs 1
printf("Second integer: %d\n", *(numbers + 1)); // Outputs 2
printf("Third integer: %d\n", *(numbers + 2)); // Outputs 3

// Free the allocated memory


free(numbers);
numbers = NULL; // Good practice to set pointer to NULL after freeing

return 0;
}
Char Array
Char arrays
• String: char array that ends with '\0'
• Declaration
• char str1[6] = "hello"; // Array size is 6, including the null terminator
• Accessing
• char firstChar = str1[0];
• Output
• printf("%s\n", str1); // Output the string
• Input
• scanf("%s", str2); // Read a string into str2 (unsafe, prefer fgets)
Avoid scanf
• Using scanf to read strings into character arrays can be
problematic due to its potential to cause buffer overflow
• Buffer overflow occurs when the data written to a buffer exceeds
its storage capacity, which can lead to undefined behavior,
program crashes, or security vulnerabilities.
• Example
• char name[10];
• printf("Enter your name: ");
• scanf("%s", name); // Unsafe: does not limit input size
fgets
#include <stdio.h>

int main() {
char name[10];
printf("Enter your name: ");
fgets(name, sizeof(name), stdin); // Safe: input size is limited
// Remove potential newline character
name[strcspn(name, "\n")] = 0;
printf("Hello, %s!\n", name);
return 0;
}
strcspn, strlen, strcat
#include <stdio.h>
#include <string.h>

int main() {
char str[20];

printf("Enter a string: ");


fgets(str, sizeof(str), stdin); // Read string with space handling

// Replace \n with \0. \0 marks the end of the string


int index = strcspn(str, "\n");
str[index] = '\0';

printf("You entered: %s\n", str);

// String manipulation
int len = strlen(str);
printf("String length: %d\n", len);

strcat(str, " World");


printf("String after concatenation: %s\n", str);

return 0;
}
Dynamic Char Array
#include <stdio.h>
#include <stdlib.h>

int main() {
int size = 256; // Define the maximum size of the input
char *str = malloc(size); // Dynamically allocate memory for the string

printf("Enter a string: ");


fgets(str, size, stdin)

// Remove the newline character if present


str[strcspn(str, "\n")] = '\0';

printf("You entered: %s\n", str);

free(str); // Free the allocated memory


return 0;
}
Functions
Functions
• Functions are blocks of code that perform a specific task
• Help you organize your programs by dividing them into smaller,
manageable, and reusable parts
• Using functions can make your code more modular, easier to
maintain, and more readable.
Basic Structure
• Return Type:
• Specifies what type of data the function will return. It can be any data type such as int, char, void, etc. A void
return type means the function does not return a value.
• Function Name:
• The identifier by which the function can be called in other parts of the program.
• Parameters (Optional):
• Variables that accept values passed into the function. These parameters act as local variables within the
function.
• Function Body:
• The block of code that defines what the function does. It includes a series of statements enclosed in curly
braces {}.
• Return Statement (Conditional):
• This statement is used to return a value from the function. It is required if the function declares a return type
other than void.
Example
#include <stdio.h>

// Function declaration
int multiply(int x, int y);

int main() {
int result = multiply(10, 5);
printf("Result: %d\n", result);
return 0;
}

// Function definition
int multiply(int x, int y) {
return x * y; // Return the product of x and y

}
#include <stdio.h>
#include <string.h>

void output(char character, int amount) {


for(int i=0; i<amount; i++) {
printf("%c", character);
}
}

int main() {
int height;

printf("Enter height: ");


scanf("%d", &height);

for(int row = 0; row < height; row++) {


if(row == 0 || row == height - 1) {
output('x', height);
} else {
output('x', 1);
output(' ', height - 2);
output('x', 1);
}
printf("%c", '\n');
}
return 0;
}
#include <stdio.h>
#include <string.h>
Preprocessor
#define WALL_CHAR 'x'
#define SPACE_CHAR ' ' commands for creating
void output(char character, int amount) { constant values
for (int i = 0; i < amount; i++) {
putchar(character);
}
}

void printRow(int width, int isBorder) {


if (isBorder) {
output(WALL_CHAR, width);
} else {
output(WALL_CHAR, 1);
output(SPACE_CHAR, width - 2);
output(WALL_CHAR, 1);
}
putchar('\n'); putchar is easier
} function for outputting
int main() {
int height;
only one char
printf("Enter height: ");
if (scanf("%d", &height) != 1 || height <= 0) {
printf("Invalid input. Please enter a positive integer.\n");
return 1;
}

for (int row = 0; row < height; row++) {


printRow(height, row == 0 || row == height - 1);
}

return 0;
}
Structs
Structs
• Structs in C programming are composite data types that allow you
to encapsulate multiple data items of potentially different types
into a single cohesive unit.
• Composite Type:
• A struct (short for "structure") is a user-defined data type in C that groups
together different data items (called members) under a single name.
• Encapsulation:
• Structs help in encapsulating related data items, making it easier to
manage and organize data in complex programs.
Example
struct Person {
char name[50];
int age;
float height;
};

struct Person person1 = {"John Doe", 30, 5.75};


Example
struct Person person1;
strcpy(person1.name, "Alice");
person1.age = 28;

struct Person *ptr = &person1;


printf("Name: %s, Age: %d", ptr->name, ptr-
>age);
Example
struct Person {
char name[50];
int age;
float height;
};

struct Person person1 = {"John Doe", 30, 5.75};


Example
struct Person *p = malloc(sizeof(struct Person));
if (p != NULL) {
strcpy(p->name, "Bob");
p->age = 40;
}
C++
Origin and History
• Developed by Bjarne Stroustrup in 1979
• Extension of C with object-oriented features
• Standardized by ISO in 1998 (C++98) with several updates (C++03,
C++11, C++14, C++17, C++20)
Key Features
• Object-oriented programming
• Standard Template Library (STL)
• Function overloading and templates
Syntax and Structure
• Similarities with C
• Basic syntax: statements, expressions, control structures (if, for, while)
• Primitive data types: int, char, float, double
• Functions and pointers
• Differences from C
• Classes and objects
• Access specifiers: public, private, protected
• Constructors and destructors
• Inline functions
Hello World: hello.cpp
#include <iostream>

int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
Compile and Run

use g++
instead of gcc
Datatypes
Fundamental Data Types
• int: Integer type
• char: Character type
• float: Single precision floating-point type
• double: Double precision floating-point type
• bool: Boolean type (true/false)
Derived Datatypes
• Arrays
• Pointers
• References
User-defined Datatypes
• Structures (struct)
• Enumerations (enum)
• Classes (class)
Namespaces
Namespaces
• Avoid name collisions
• Organize code into logical groups
Header files
• Declarations:
• Header files are used to declare the interfaces to your code, including
functions, classes, constants, and macros.
• Inclusions:
• They are included in other files using the #include directive to share
declarations across multiple source files without redefining them.
mymath.h
#ifndef MYMATH_H
rPevents multiple
#define MYMATH_H inclusions of the same
header file using

namespace mymath {
int max(int a, int b);
}

#endif
Source files: .cpp
• Provides the body of the functions declared in the header files.
• Class Method Definitions: Implements the methods of the classes
declared in the header files.
• Local Functions: Defines any additional functions that are not
exposed to other parts of the program.
mymath.cpp
#include "mymath.h"
Ensure that header
file is consistant with
namespace mymath { cpp file

int max(int a, int b) {


return a > b ? a : b;
}
}
main.cpp
#include <iostream>
#include "mymath.h"

int main() {
std::cout << "Hello, World!" << std::endl;
std::cout << mymath::max(5, 5) << std::endl;
return 0;
}
Namespaces
#include <iostream> Possible to have max –
method in two different
#include "mymath1.h" namespaces, no name
collisions
#include "mymath2.h"

int main() {
std::cout << mymath1::max(5, 5) << std::endl;
std::cout << mymath2::max(5, 5) << std::endl;
return 0;
}
Basic Input and Output
IOStream
• Including the iostream Library
• Output with cout
• std::cout << "Hello, World!" << std::endl;
• Input with cin
• int age;
• std::cout << "Enter your age: ";
• std::cin >> age;
Functions in C++
Function in C++
• A function is a block of code that performs a specific task.
• Functions help in code reusability and modularity.
• Function
• int add(int a, int b) {
• return a + b;
• }
Function Overloading
• Function overloading allows multiple functions to have the same
name with different parameters.
• It helps improve code readability and usability.
• Functions must differ in the type or number of parameters.
• Return type alone is not sufficient to overload a function.
Example
int add(int a, int b) {
return a + b;
}

double add(double a, double b) {


return a + b;
}
Default parameters
void display(int a, int b = 10) {
std::cout << "a: " << a << ", b: " << b << std::endl;
}

display(5); // Output: a: 5, b: 10
display(5, 20); // Output: a: 5, b: 20
Example
void greet(std::string name = "Guest") {
std::cout << "Hello, " << name << "!" << std::endl;
}

void greet(std::string name, std::string title) {


std::cout << "Hello, " << title << " " << name << "!" << std::endl;
}

greet(); // Output: Hello, Guest!


greet("Alice"); // Output: Hello, Alice!
greet("Alice", "Dr."); // Output: Hello, Dr. Alice!
C++ OO
Key Concepts of OOP
• Classes and Objects
• Encapsulation
• Inheritance
• Polymorphism
Classes and Objects
// Class definition
class Animal {
public:
void eat() {
std::cout << "I can eat!" << std::endl;
}
};

// Creating an object
int main() {
Animal animal1;
animal1.eat(); // Output: I can eat!
return 0;
}
class Student { int main() {
private:
std::string name; Student student1;
int age;
student1.setName("Alice");
public:
// Setter for name student1.setAge(20);
void setName(std::string n) {
name = n; std::cout << "Name: " <<
} student1.getName() << std::endl;

// Getter for name std::cout << "Age: " << student1.getAge()


std::string getName() { << std::endl;
return name;
} return 0;

// Setter for age }


void setAge(int a) {
age = a;
}

// Getter for age


int getAge() {
return age;
}
};
Inheritance
// Base class
class Animal {
public:
void eat() {
std::cout << "I can eat!" << std::endl;
}
};

// Derived class
class Dog : public Animal {
public:
void bark() {
std::cout << "I can bark!" << std::endl;
}
};

int main() {
Dog dog1;
dog1.eat(); // Output: I can eat!
dog1.bark(); // Output: I can bark!
return 0;
}
Polymorphism
// Base class
class Shape {
public:
virtual void draw() {
std::cout << "Drawing Shape" << std::endl;
}
};

// Derived class
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing Circle" << std::endl;
}
};

int main() {
Shape* shape1 = new Shape();
Shape* shape2 = new Circle();

shape1->draw(); // Output: Drawing Shape


shape2->draw(); // Output: Drawing Circle

delete shape1;
delete shape2;

return 0;
}
Abstract class
// Base class
class Shape {
public:
virtual void draw() = 0;
};

// Derived class
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing Circle" << std::endl;
}
};

int main() {
Shape* shape1 = new Shape();
Shape* shape2 = new Circle();

shape1->draw(); // Output: Drawing Shape


shape2->draw(); // Output: Drawing Circle

delete shape1;
delete shape2;

return 0;
}
Dynamic Memory Handling
Using heap with int
#include <iostream>

int main() {
// Step 1: Allocate memory on the heap
int* ptr = new int;

// Step 2: Assign a value to the allocated memory


*ptr = 42;

// Step 3: Use the allocated memory


std::cout << "Value: " << *ptr << std::endl;

// Step 4: Deallocate the memory


delete ptr;
ptr = nullptr; // Avoid dangling pointer

return 0;
}
Memory leak
#include <iostream>

int main() {
// Step 1: Allocate memory on the heap
int* ptr = nullptr;

if (true) { // The condition is always true, but it could be any condition


ptr = new int;

// Step 2: Assign a value to the allocated memory


*ptr = 42;

// Step 3: Use the allocated memory


std::cout << "Value: " << *ptr << std::endl;

// Memory leak here: No delete statement to deallocate the memory


// The allocated memory is never freed
}

// Outside the if block, there is no delete statement


// ptr still points to the allocated memory but it's not deallocated

return 0;
}
Templates
Templates
• Templates in C++ are a powerful feature that allows for generic
programming.
• Enable functions and classes to operate with any data type
without being rewritten for each type
• There are two basic main types of templates
• function templates
• class templates
Function Template
#include <iostream>

// Function template
template <typename T>
T add(T a, T b) {
return a + b;
}

int main() {
int intResult = add(3, 4); // T is int
double doubleResult = add(2.5, 3.1); // T is double

std::cout << "intResult: " << intResult << std::endl; // Outputs: intResult: 7
std::cout << "doubleResult: " << doubleResult << std::endl; // Outputs: doubleResult: 5.6

return 0;
}
Class Template
#include <iostream>

// Class template
template <typename T>
class Container {
private:
T value;
public:
Container(T val) : value(val) {}
void setValue(T val) { value = val; }
T getValue() { return value; }
};

int main() {
Container<int> intContainer(42); // T is int
Container<double> doubleContainer(3.14); // T is double

std::cout << "intContainer: " << intContainer.getValue() << std::endl; // Outputs: intContainer: 42
std::cout << "doubleContainer: " << doubleContainer.getValue() << std::endl; // Outputs: doubleContainer: 3.14

return 0;
}
#include <iostream> // Print the list elements again
std::cout << "List elements after push_front: ";
#include <list> for (int value : *myList) {
std::cout << value << " ";
}
int main() {
std::cout << std::endl;
// Create a list of integers on the heap
std::list<int>* myList = new std::list<int>; // Delete an element by value
myList->remove(20); // Remove 20 from the list

// Insert elements into the list // Print the list elements again
std::cout << "List elements after removal: ";
myList->push_back(10); // Add 10 to the end for (int value : *myList) {
myList->push_back(20); // Add 20 to the end std::cout << value << " ";
}
myList->push_back(30); // Add 30 to the end std::cout << std::endl;

// Access the first and last elements


// Print the list elements std::cout << "First element: " << myList->front() <<
std::cout << "List elements: "; std::endl;
std::cout << "Last element: " << myList->back() << std::endl;
for (int value : *myList) {
std::cout << value << " "; // Free the memory allocated for the list
delete myList;
}
std::cout << std::endl; return 0;
}

// Insert at the front // g++ -std=c++11 *.cpp -o myapp


myList->push_front(5); // Add 5 to the front
Modern Features
auto type
#include <iostream>
#include <vector>

int main() {
auto x = 5; // int
auto y = 3.14; // double
auto str = "Hello"; // const char*

std::vector<int> vec = {1, 2, 3, 4, 5};


for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;

return 0;
}
range
#include <iostream>
#include <vector>

int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};

for (int value : vec) {


std::cout << value << " ";
}
std::cout << std::endl;

return 0;
}
Smart Pointers
• unique_ptr represents unique ownership of a resource.
• Only one unique_ptr can own a resource at a time
• When the unique_ptr goes out of scope, it automatically deletes the
resource.
• shared_ptr allows multiple pointers to share ownership of a resource.
• The resource is deleted when the last shared_ptr owning it is destroyed.
Problem
#include <iostream>

int main() {
if (true) {
int* ptr = new int(10); // Allocate memory on the heap
std::cout << "Value: " << *ptr << std::endl;
// Forgetting to delete the allocated memory
}
// Memory allocated inside the if block is not freed, causing a memory leak
return 0;
}
Fix: g++ -std=c++14 *.cpp -o myapp
#include <iostream>
#include <memory>

int main() {
if (true) {
std::unique_ptr<int> ptr = std::make_unique<int>(10); // Allocate memory on the heap using unique_ptr
std::cout << "Value: " << *ptr << std::endl;
// No need to manually delete, unique_ptr automatically deletes the memory when it goes out of scope
}
// Memory allocated inside the if block is automatically freed when the unique_ptr goes out of scope
return 0;
}
shared_ptr
#include <iostream>
#include <memory> // For shared_ptr

class MyClass {
public:
MyClass(int value) : value(value) {
std::cout << "MyClass constructor called with value: " << value << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor called for value: " << value << std::endl;
}
int getValue() const {
return value;
}
private:
int value;
};

int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(42);

if(true) {
std::shared_ptr<MyClass> ptr2 = ptr1;
std::cout << "Value through ptr2: " << ptr2->getValue() << std::endl;
std::cout << "Reference count: " << ptr1.use_count() << std::endl;
}
std::cout << "Value through ptr1: " << ptr1->getValue() << std::endl;
std::cout << "Reference count: " << ptr1.use_count() << std::endl;

return 0;
}
Lambdas
• An anonymous function that can capture variables from its
surrounding scope.
• Basic Syntax:
• [ capture ] ( params ) -> ret { body }
• Capture Clause ([]): Specifies which variables from the surrounding scope
are captured and how.
• Parameter List (( params )): Defines the parameters the lambda takes.
• Return Type (-> ret) (optional): Specifies the return type. If omitted, the
compiler deduces it.
• Body ({ body }): Contains the code to be executed when the lambda is
called.
Example
#include <iostream>
#include <functional>

int main() {
// Define the lambda function with std::function
std::function<int(int, int)> add = [](int a, int b) -> int {
return a + b;
};

// Use the lambda function to add two numbers


int sum = add(5, 3);

// Print the result


std::cout << "The sum of 5 and 3 is: " << sum << std::endl;

return 0;
}
Using auto
#include <iostream>

int main() {
// Define the lambda function
auto add = [](int a, int b) -> int {
return a + b;
};

// Use the lambda function to add two numbers


int sum = add(5, 3);

// Print the result


std::cout << "The sum of 5 and 3 is: " << sum << std::endl;

return 0;
}
Using callbacks
#include <iostream>
#include <functional>

// Function that takes two integers and a callback function


void performOperation(int a, int b, const std::function<int(int, int)>& callback) {
// Call the callback function with the provided integers
int result = callback(a, b);
// Print the result
std::cout << "The result of the operation is: " << result << std::endl;
}

int main() {
// Define the lambda function for summing two numbers
auto sum = [](int a, int b) -> int {
return a + b;
};

// Define the lambda function for subtracting two numbers


auto extract = [](int a, int b) -> int {
return a - b;
};

// Use the lambda function for summing as a callback


performOperation(5, 3, sum); // Should print "The result of the operation is: 8"

// Use the lambda function for extracting as a callback


performOperation(5, 3, extract); // Should print "The result of the operation is: 2"

return 0;
}
Using callbacks with anonymous lambdas
#include <iostream>
#include <functional>

// Function that takes two integers and a callback function


void performOperation(int a, int b, const std::function<int(int, int)>& callback) {
// Call the callback function with the provided integers
int result = callback(a, b);
// Print the result
std::cout << "The result of the operation is: " << result << std::endl;
}

int main() {
// Use an anonymous lambda function for summing as a callback
performOperation(5, 3, [](int a, int b) -> int {
return a + b;
}); // Should print "The result of the operation is: 8"

// Use an anonymous lambda function for subtracting as a callback


performOperation(5, 3, [](int a, int b) -> int {
return a - b;
}); // Should print "The result of the operation is: 2"

return 0;
}
#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <functional>

// Function that reads a file in a different thread and invokes the callback with the file content
void fileRead(const std::string& filePath, std::function<void(const std::string&)> callback) {
// Create a thread to read the file
std::thread([filePath, callback]() {
std::ifstream inputFile(filePath);
if (!inputFile) {
std::cerr << "Unable to open file: " << filePath << std::endl;
return;
}

std::string content;
std::string line;
while (std::getline(inputFile, line)) {
content += line + '\n';
}
allows the thread to run independently
inputFile.close(); from the std::thread object that originally
// Invoke the callback with the file content
callback(content);
represented it. After calling detach, the
}
}).detach(); thread becomes a daemon thread
int main() {
// Example usage of fileRead function
fileRead("path/to/foo.txt", [](const std::string& content) {
std::cout << "File content:\n" << content << std::endl;
});

// Prevent main from exiting immediately


std::this_thread::sleep_for(std::chrono::seconds(2)); // Adjust time as needed for file reading to complete

return 0;
}

You might also like