UNIT-4 PART-1: POINTERS
What does a variable declaration mean?
int a = 9;
this declaration tells the C compiler to:
a) reserve space in the memory to hold the integer value.
b) associate the name a with this memory location.
c) store the value 9 at this location.
a Location Name
9 Value At Location
65524 Location Number
Memory Address
• When a variable is created in C, a memory address is assigned to the
variable.
• The memory address is the location of where the variable is stored on the
computer.
• When we assign a value to the variable, it is stored in this memory
address.
• To access it, use the reference operator (&), and the result represents
where the variable is stored:
The (&) operator / address of operator (&)/
reference operator(&)
Also Known As
• address of operator (&)
• reference operator(&)
• The reference operator (&) is used to obtain the memory address of a
variable. It is also referred to as the "address-of operator." When you
use & with a variable, it gives you the address in memory where the
variable is stored.
(&) also known as pointer
int a = 9;
printf(“Address of a = %p”,&a);
&a is often called a "pointer". A pointer basically stores the memory
address of a variable as its value. To print pointer values, we use the %p
format specifier. %p prints the address in hexadecimal format.
The (*) operator / Dereferencing operator(*)/ Indirection
operator(*) / Value At Address operator(*)
• we have been using the ‘&’ operator all the time in the scanf() function.
the other pointer operator available in C is ‘*’, called “value at address”
operator. (in the previous example) it gives the value stored at the address
65524,which is 9. the value at address operator is also known as the
indirection operator or the Dereferencing operator.
*(&a) : value at the address ‘ a ‘
int a = 9;
printf(“ Value of a = %d”,a); // generally
printf(“ Value of a = %d”, * (&a) ); // using indirection operator.
output:
Value of a = 9
Value of a = 9
NOTE: printing the value of * (&a) is same as printing the value of a
• the expression &a gives the address of the variable a. this address can
be collected in another variable, by saying,
• b=&a;
a b
9 65524
65524 65522
• As you can see a’s value is 9 and b’s value is a’s address. since b is a
variable that contains the address of a, it is declared as.
int *b; // value at address stored in b is an integer
This declaration tells the compiler that b will be used to store
the address of an integer value. In other words b points to an
integer.
POINTER DEFINITION
• A pointer is defined as a derived data type that can store the memory
address of other variables, functions, or even other pointers.
POINTER DECLARATION
Syntax of Pointer Declaration:
The syntax of pointers depends on the type they are pointing to. In general, for
a variable, a pointer can be declared as:
type* ptr; or type * ptr; or type *ptr;
where,
ptr is the name of the pointer.
type is the type of data it is pointing to.
The ( * ) dereferencing operator is used to denote that the declared variable
stores the address of another variable.
Pointer Types And Their sizes
• Example: declarations
• int *a; // a is a pointer of type integer
• float *b; // b is a pointer to a float
• char *c; // c is a pointer to a character
Here, a,b,c are declared as pointer variables,i.e., variables that hold addresses. the
declaration float *b; means that b is going to contain the address of a floating-point
[Link] char *c means that c is going to contain the address of a character
value .
• Even though a,b,c are different types of pointers, they all hold addresses(location
number) . Since addresses are always whole numbers, they contain whole numbers.
So their sizes would be same . these sizes can be obtained using the sizeof
operator .
• printf("%p %p %p",sizeof(a),sizeof(b),sizeof(c));
• this printf would report the size of each pointer as 2 bytes,4 bytes,8 bytes based on
whether it is executed on 16-bit,32-bit or 64-bit machine respectively.
• To declare a pointer, we use the (*) dereference operator before its
name. In pointer declaration, we only declare the pointer but do not
initialize it.
• Note: We can also declare and initialize the pointer in a single step.
This is called pointer definition.
Pointer Dereferencing
• Dereferencing a pointer is the process of accessing the value stored in the memory
address specified in the pointer. We use the same (*) dereferencing operator that
we used in the pointer declaration.
• Note: It is recommended that the pointers should always be initialized to some
value before starting using it. Other wise, it may lead to number of errors.
revisit function calls/parameter passing technique
types of function calls:
1. call by value
2. call by reference
3. mixed function call: we know that the return statement can return
only one value. but with mixed functions we can return with
multiple values.
Compatibility of Pointers
• Pointer compatibility refers to whether pointers of different types can
be assigned to each other or compared.
• A pointer to type int can only point to an int variable, unless explicitly
cast.
• int x = 10;
• int *p = &x; // Compatible
• float *fp = &x; // Incompatible without a cast
• CONSTANT POINTER
• A const int *p points to a constant integer and cannot modify the
value it points to
• const int x = 10;
• const int *p = &x; // Valid
• // *p = 20; // Error: cannot modify constant value
• Different Sizes:
• Pointers of different sizes (e.g., int * and char *) are incompatible
without casting.
POINTER TO VOID
• A pointer to void is a special type of pointer that can point to any data type. The type of
the data it points to is not known at compile time, making it a generic pointer.
• Declaration of a Void Pointer
• void *ptr; // A void pointer declaration
• A void * pointer can store the address of any data type (e.g., int, float, char, or even
user-defined types).
• Since it doesn't know the type of data it points to, you cannot dereference a void
pointer directly. Instead, you must cast it to a specific type first.
• int x = 10;
• void *vp = &x; // Compatible
• printf("%d", *(int *)vp); // Must cast to int * before dereferencing
L-Value and R-Value of Pointers
• L-Value:
• The terms L-value (left value) and R-value (right value) refer to the
behavior of pointers in expressions.
• An L-value is a pointer itself, meaning the memory address it holds
can be changed. For example:
• int x = 10, y = 20;
• int *p = &x; // p holds the address of x
• p = &y; // L-value of p is updated to hold the address of y
• R-Value:
• An R-value is the value at the address the pointer is pointing to
(dereferencing). For example:
• int x = 10;
• int *p = &x; // Pointer p holds the address of x
• printf("%d", *p); // Dereferencing gives the R-value: 10
REFER TO THE PROGRAMS
• Explaination with the programs is given in the program pdf for the Topics
Below:
types of memory allocation
1. Static Memory Allocation
2. Dynamic Memory Allocation
Static Memory Allocation
Static Memory Allocation
• Definition: Memory is allocated at compile time, and the lifetime of the allocated
memory is fixed (until the program terminates).
• The size of the memory is known during [Link] are allocated
memory on the stack or in the global data [Link] and simple.
• Memory cannot be resized during program execution.
• Managed automatically (no need for malloc/free).
MEMORY ALLOCATION FUNCTIONS
Dynamic Memory Allocation:
• Dynamic Memory Allocation can be defined as a procedure in which the size of a
data structure (like Array) is changed during the runtime.C provides some
functions to achieve these tasks. There are 4 library functions provided by C
defined under <stdlib.h> header file to facilitate dynamic memory allocation in C
programming.
They are: malloc() calloc() free() realloc()
malloc() method
• The “malloc” or “memory allocation” method in C is used to dynamically allocate
a single large block of memory with the specified size. It returns a pointer of type
void which can be cast into a pointer of any form. It doesn’t Initialize memory at
execution time so that it has initialized each block with the default garbage value
initially.
ptr = (cast-type*) malloc(byte-size)
For Example:
ptr = (int*) malloc(100 * sizeof(int));
Since the size of int is 4 bytes, this statement will allocate 400 bytes of
memory. And, the pointer ptr holds the address of the first byte in the
allocated memory.
If space is insufficient, allocation fails and returns a NULL pointer.
calloc() method
“calloc” or “contiguous allocation” method in C is used to dynamically allocate the
specified number of blocks of memory of the specified type. it is very much similar
to malloc() but has two different points and these are:
It initializes each block with a default value ‘0’.
It has two parameters or arguments as compare to malloc().
Syntax of calloc() in C
ptr = (cast-type*)calloc(n, element-size);
here, n is the no. of elements and element-size is the size of each element.
For Example:
ptr = (float*) calloc(25, sizeof(float));
This statement allocates contiguous space in memory for 25 elements each with the
size of the float.
If space is insufficient, allocation fails and returns a NULL pointer.
free() method
“free” method in C is used to dynamically de-allocate the memory. The memory
allocated using functions malloc() and calloc() is not de-allocated on their own.
Hence the free() method is used, whenever the dynamic memory allocation
takes place. It helps to reduce wastage of memory by freeing it.
Syntax of free() in C
free(ptr);
realloc() method
• “realloc” or “re-allocation” method in C is used to dynamically change the
memory allocation of a previously allocated memory. In other words, if the
memory previously allocated with the help of malloc or calloc is insufficient,
realloc can be used to dynamically re-allocate memory. re-allocation of memory
maintains the already present value and new blocks will be initialized with the
default garbage value.
Syntax of realloc() in C
ptr = realloc(ptr, newSize);
where ptr is reallocated with new size 'newSize'.
If space is insufficient, allocation fails and returns a NULL pointer.
Actual syntax of memory allocation functions
• void* malloc(size_t size);
• void* calloc(size_t num, size_t size);
• void free(void* ptr);
• void* realloc(void* ptr, size_t size);
Memory Leak
memory leak in programming refers to a situation where a program allocates
memory (typically dynamically using functions like malloc(), calloc()), but fails to
release it using free() . As a result, the memory is no longer accessible to the
program, but the system still holds onto it, causing a gradual increase in the
memory usage of the program.
Solution:
Always ensure you free dynamically allocated memory using free()
Dangling Pointer
• a pointer that refers to a memory location that has been freed or is
no longer valid. Accessing or dereferencing a dangling pointer leads to
undefined behavior, which can cause crashes, data corruption, or
unpredictable results.
• Deallocating Memory (Using free): When dynamically allocated
memory is freed, the pointer still contains the address of the now-
freed memory.
How to Avoid Dangling Pointers
Set the Pointer to NULL After Freeing:
• After freeing memory, assign the pointer to NULL to prevent
accidental access.
applications of pointers:
Dynamic Memory Allocation
• "A pointer in C can be used to dynamically allocate memory for an array at
runtime, such as creating an array for user-defined data size."
Arrays and Strings
• "Pointers help traverse arrays or manipulate strings by accessing their elements
directly through memory addresses."
Passing by Reference
• "Using pointers, a function can modify the value of a variable in the calling function,
which is crucial for in-place changes."
Efficiency
• "Pointers enhance performance by directly accessing memory, avoiding the
overhead of copying data."
Pointer Arithmetic
• "With pointer arithmetic, you can access sequential elements in an array without
using array indices."