What is a Pointer in C
What is a Pointer in C
C pointer is the derived data type that is used to store the address of another variable and can
also be used to access and manipulate the variable's data stored at that location. The pointers
are considered as derived data types.
With pointers, you can access and modify the data located in the memory, pass the data
efficiently between the functions, and create dynamic data structures like linked lists, trees, and
graphs.
Pointer Declaration
To declare a pointer, use the dereferencing operator (*) followed by the data type.
Syntax
The general form of a pointer variable declaration is −
type *var-name;
Here, type is the pointer's base type; it must be a valid C data type and var-name is the name of
the pointer variable. The asterisk * used to declare a pointer is the same asterisk used for
multiplication. However, in this statement the asterisk is being used to designate a variable as a
pointer.
The actual data type of the value of all pointers, whether integer, float, character, or otherwise,
is the same, a long hexadecimal number that represents a memory address. The only difference
between pointers of different data types is the data type of the variable or constant that the
pointer points to.
Pointer Initialization
After declaring a pointer variable, you need to initialize it with the address of another variable
using the address of (&) operator. This process is known as referencing a pointer.
Syntax
The following is the syntax to initialize a pointer variable –
pointer_variable = &variable;
Example
Here is an example of pointer initialization –
int x = 10;
int *ptr = &x;
Referencing and Dereferencing Pointers
A pointer references a location in memory. Obtaining the value stored at that location is known
as dereferencing the pointer.
In C, it is important to understand the purpose of the following two operators in the context of
pointer mechanism −
The & Operator − It is also known as the "Address-of operator". It is used for
Referencing which means taking the address of an existing variable (using &) to set a
pointer variable.
The * Operator − It is also known as the "dereference operator". Dereferencing a
pointer is carried out using the * operator to get the value from the memory address
that is pointed by the pointer.
Pointers are used to pass parameters by reference. This is useful if a programmer wants a
function's modifications to a parameter to be visible to the function's caller. This is also useful
for returning multiple values from a function.
Access and Manipulate Values using Pointer
The value of the variable which is pointed by a pointer can be accessed and manipulated by
using the pointer variable. You need to use the asterisk (*) sign with the pointer variable to
access and manipulate the variable's value.
Example
In the below example, we are taking an integer variable with its initial value and changing it
with the new value.
#include <stdio.h>
int main() {
int x = 10;
// Pointer declaration and initialization
int * ptr = & x;
// Printing the current value
printf("Value of x = %d\n", * ptr);
// Changing the value
* ptr = 20;
// Printing the updated value
printf("Value of x = %d\n", * ptr);
return 0;
}
Output
Value of x = 10
Value of x = 20
//////////
Creating Pointers
You learned from the previous chapter, that we can get the memory address of a variable with
the reference operator &:
Example
int myAge = 43; // an int variable
Output:
43
0x7ffe5367e044
A pointer is a variable that stores the memory address of another variable as its value.
A pointer variable points to a data type (like int) of the same type, and is created with
the * operator.
The address of the variable you are working with is assigned to the pointer:
Example
#include <stdio.h>
int main() {
int myAge = 43; // An int variable
int* ptr = &myAge; // A pointer variable, with the name ptr, that stores the address of myAge
return 0;
}
Output:
43
0x7ffe5367e044
0x7ffe5367e044
Example explained
Create a pointer variable with the name ptr, that points to an int variable (myAge). Note that
the type of the pointer has to match the type of the variable you're working with (int in our
example).
Use the & operator to store the memory address of the myAge variable, and assign it to the
pointer.
Now, ptr holds the value of myAge's memory address.
Static Memory
Static memory is memory that is reserved for variables before the program runs. Allocation of
static memory is also known as compile time memory allocation.
C automatically allocates memory for every variable when the program is compiled.
For example, if you create an integer array of 20 students (e.g. for a summer semester), C will
reserve space for 20 elements which is typically 80 bytes of memory (20 * 4):
Example
int students[20];
printf("%lu", sizeof(students)); // 80 bytes
Output: 80
But when the semester starts, it turns out that only 12 students are attending. Then you have
wasted the space of 8 unused elements.
Since you are not able to change the size of the array, you are left with unnecessary reserved
memory.
Note that the program will still run, and it is not damaged in any way. But if your program
contains a lot of this kind of code, it may run slower than it optimally could.
If you want better control of allocated memory, take a look at Dynamic Memory below.
Dynamic Memory
Dynamic memory is memory that is allocated after the program starts running. Allocation of
dynamic memory can also be referred to as runtime memory allocation.
Unlike with static memory, you have full control over how much memory is being used at any
time. You can write code to determine how much memory you need and allocate it.
Dynamic memory does not belong to a variable, it can only be accessed with pointers.
To allocate dynamic memory, you can use the malloc() or calloc() functions. It is necessary to
include the <stdlib.h> header to use them. The malloc() and calloc() functions allocate some
memory and return a pointer to its address.
The malloc() function has one parameter, size, which specifies how much memory to allocate,
measured in bytes.
The calloc() function has two parameters:
amount - Specifies the amount of items to allocate
size - Specifies the size of each item measured in bytes
Note: The data in the memory allocated by malloc() is unpredictable. To avoid unexpected
values, make sure to write something into the memory before reading it.
Unlike malloc(), the calloc() function writes zeroes into all of the allocated memory. However,
this makes calloc() slightly less efficient.
The best way to allocate the right amount of memory for a data type is to use
the sizeof operator:
Be careful: sizeof(*ptr1) tells C to measure the size of the data at the address. If you forget
the * and write sizeof(ptr1) instead, it will measure the size of the pointer itself, which is the
(usually) 8 bytes that are needed to store a memory address.
Note: The sizeof operator cannot measure how much dynamic memory is allocated. When
measuring dynamic memory, it only tells you the size of the data type of the memory. For
example, if you reserve space for 5 float values, the sizeof operator will return 4, which is the
number of bytes needed for a single float value.
Example
int *students;
int numStudents = 12;
students = calloc(numStudents, sizeof(*students));
printf("%d", numStudents * sizeof(*students)); // 48 bytes
Output: 48
As can be seen, the length (size) of the array above is 9. But what if there is a requirement to
change this length (size)? For example,
If there is a situation where only 5 elements are needed to be entered in this array. In
this case, the remaining 4 indices are just wasting memory in this array. So there is a
requirement to lessen the length (size) of the array from 9 to 5.
Take another situation. In this, there is an array of 9 elements with all 9 indices filled.
But there is a need to enter 3 more elements in this array. In this case, 3 indices more
are required. So the length (size) of the array needs to be changed from 9 to 12.
Therefore, C 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.
Before learning above functions, let's understand the difference between static memory
allocation and dynamic memory allocation.
static memory allocation dynamic memory allocation
memory can't be increased while executing program. memory can be increased while executing program.
Now let's have a quick look at the methods used for dynamic memory allocation.
malloc() allocates single block of requested memory.
C calloc() method
1. “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:
2. It initializes each block with a default value ‘0’.
3. 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.
C 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);
C 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'.
Self Referential Structures
Self Referential structures are those structures that have one or more pointers which point to
the same type of structure, as their member.
In other words, structures pointing to the same type of structures are self-referential in nature
///
What are Self-referential Structures?
A self-referential structure is a struct data type in C, where one or more of its elements are
pointer to variables of its own type. Self-referential user-defined types are of immense use in C
programming. They are extensively used to build complex and dynamic data structures such
as linked lists and trees.
In C programming, an array is allocated the required memory at compile-time and the array size
cannot be modified during the runtime. Self-referential structures let you emulate the arrays by
handling the size dynamically.
File management systems in Operating Systems are built upon dynamically constructed tree
structures, which are manipulated by self-referential structures. Self-referential structures are
also employed in many complex algorithms.
p1 = &x;
p2 = &y;
p3 = &z;
The variables "x", "y" and "z" are unrelated as they will be located at random locations, unlike
the array where all its elements are in adjacent locations.
Explore our latest online courses and learn new skills at your own pace. Enroll and become a
certified expert to boost your career.
struct mystruct{
int a;
struct mystruct *b;
};
int main(){
p1 = &x;
p2 = &y;
p3 = &z;
x.b = p2;
y.b = p3;
return 0;
}
Output
Run the code and check its output −
Address of x: 659042000 a: 10 Address of next: 659042016
Address of y: 659042016 a: 20 Address of next: 659042032
Address of z: 659042032 a: 30 Address of next: 0
Self Referential Structure with Single Link: These structures can have only one self-pointer as
their member. The following example will show us how to connect the objects of a self-
referential structure with the single link and access the corresponding data members. The
connection formed is shown in the following figure.
Self Referential Structure with Multiple Links: Self referential structures with multiple links can
have more than one self-pointers. Many complicated data structures can be easily constructed
using these structures. Such structures can easily connect to more than one nodes at a time.
The following example shows one such structure with more than one links.
The connections made in the above example can be understood using the following figure.
In this article, we will learn about the linked list, its types, representation of the linked list in C, and
discuss what link list offers as compared to the similar data structures.
A linked list is a sequence of nodes where each node contains two parts:
Unlike arrays, linked lists do not store elements in contiguous memory locations. Instead, each node
points to the next, forming a chain-like structure and to access any element (node), we need to first
sequentially traverse all the nodes before it.
It is a recursive data structure in which any smaller part of it is also a linked list in itself.
In C, linked lists are represented as the pointer to the first node in the list. For that reason, the first node
is generally called head of the linked list. Each node of the linked list is represented by a structure that
contains a data field and a pointer of the same type as itself. Such structure is called self-referential
structures.
Linked list can be classified on the basis of the type of structure they form as a whole and the direction
of access. Based on this classification, there are five types of linked lists:
A linked list or singly linked list is a linear data structure that is made up of a group of nodes in which
each node has two parts: the data, and the pointer to the next node. The last node's (also known as tail)
pointers point to NULL to indicate the end of the linked list.
A linked list is represented as a pointer to the first node where each node contains:
A doubly linked list is a bit more complex than singly linked list. In it, each node contains three parts: the
data, a pointer to the next node, and one extra pointer which points to the previous node. This allows
for traversal in both directions, making it more versatile than a singly linked list.
A doubly linked list is represented as a pointer to the first node (head), where each node contains:
A circular linked list is a variation of a singly linked list where the last node points back to the first
node, forming a circle. This means there is no NULL at the end, and the list can be traversed in a
circular manner.
The structure of the circular linked list node is same as that of singly linked list.
A circular linked list is represented as a pointer to the first node, where each node contains:
Next: A pointer that links to the next node, with the last node pointing back to the first node.
o list size is limited to the memory size and doesn't need to be declared in advance.
o We can store values of primitive types or objects in the singly linked list.
The size of array must be known in advance before using it in the program.
Increasing size of the array is a time taking process. It is almost impossible to expand the size of
the array at run time.
All the elements in the array need to be contiguously stored in the memory. Inserting any
element in the array needs shifting of all its predecessors.
Linked list is the data structure which can overcome all the limitations of an array. Using linked list is
useful because,
1. It allocates the memory dynamically. All the nodes of linked list are non-contiguously stored in
the memory and linked together with the help of pointers.
2. Sizing is no longer a problem since we do not need to define its size at the time of declaration.
List grows as per the program's demand and limited to the available memory space.