Skip to content

Pointers In C

Pointer is a derived data type in C, it is built from one fundamental data type available in C. Pointers contain memory addresses as their values. Since these memory addresses are the locations in the computer memory where program instructions and data are stored, pointers can be used to access and manipulate data stored in the memory.

Pointers are used frequently in C, as they offer a number of benefits to the programmers. They include:

  1. Pointers can be used to return multiple values from a function via function arguments.
  2. Pointers permit references to functions and thereby facilitate passing of functions as arguments to other functions.
  3. The use of pointer arrays to character string results in saving of data storage space in memory.
  4. Pointers allow C to support dynamic memory management.
  5. Pointers provide an efficient tool for manipulating dynamic data structures such as structures, linked lists, queues, stacks and trees.

Declaring a Pointer Variable

Pointer variables contain addresses that belong to a separate data type; they must be declared as pointers before we use them. The declaration of a pointer variable takes place in the following form:

data_type *pt_name

This tells the compiler three things about the variable pt_name.

  1. The asterisk(*) tells that the variable pt_name is a pointer variable.
  2. pt_name needs a memory location.
  3. pt_name pointer to a variable of data_type.

For example,

int *ptr; /* integer pointer */

Declares the variable p as a pointer variable that points to an integer data type.

Accessing the Address of a Variable

We can determine the address of a variable with the help of the operator & available in C. We have already seen the use of this address operator in the scanf function. The operator & immediately preceding a variable returns the address of the variable associated with it. For example, the statement

p = &quantity;

Would assign the address 5000( the location of quantity) to the variable p. The & operator can be remembered as “address of”.

The & operator can be used only with a simple variable or any array element.

Initialization of Pointer Variables

The process of assigning the address of a variable to a pointer variable is known as initialization. It contains the address of a variable of a similar data type. In C programming language, the address operator & is utilized to decide the location of a variable. The & (promptly going before a variable name) returns the location of the variable related to it.

Once a pointer variable has been declared we can use the assignment operator to initialize the variable.

Example:

int quantity;

int *ptr; /* declaration */

p = &quantity; /* initialization */

We can also combine the initialization with the declaration. That is,

int *p = &quantity;

is allowed. The only requirement here is that the variable quantity must be declared before the initialization takes place.

C Pointer to Pointer

A pointer to a pointer is a type of numerous indirection, or a chain of pointers. Ordinarily, a pointer contains the location of a variable. At the point when we characterize a pointer to a pointer, the main pointer contains the location of the subsequent pointer, which focuses on the area that contains the real worth as displayed below,

A variable which is a pointer to a pointer should be proclaimed accordingly. This is finished by setting an extra mark before its name. For instance, the following statement declares a pointer to a pointer of datatype int,

int **var;

data_type **ptr;

ptr=&pointer_variable;

Example of Pointer to Pointer

#include <stdio.h>

int main()

{

int i = 10;

int *ptr;

int **pptr;

int ***ppptr;

ptr = &i;

pptr = &ptr;

ppptr = &pptr;

printf(“\n %d %d %d %d”, i, *ptr, **pptr, ***ppptr);

}

Output:

10 10 10 10

For better understanding of the above program, please have a look at the following diagram.

C Pointer Arithmetic

We can perform arithmetic operations on the pointers like addition, deduction, and so on, as we realize that the pointer contains the location/address, the consequence of an arithmetic activity performed on the pointer will likewise be a pointer if the other operand is of type integer. In the pointer-from-pointer deduction, the outcome will be an integer. Following arithmetic tasks are attainable on the pointer in C language:

  1. Increment
  2. Decrement
  3. Addition
  4. Subtraction

Pointer Increment in C

In the event that we increase a pointer by 1, the pointer will begin highlighting the next location. This is fairly not quite the same as the overall arithmetic since the worth of the pointer will get expanded by the size of the data type to which the pointer is pointing.

The Rule to increment the pointer is given underneath:

new_address= current_address + i * size_of(data type)

For a 32-bit int variable, it will be incremented by 2 bytes.

For a 64-bit int variable, it will be incremented by 4 bytes.

Pointer Decrement in C

Like increment, we can decrement a pointer variable, if we decrement a pointer, it will begin highlighting the immediate previous location.

The rule of decrementing the pointer is given below:

new_address= current_address – i * size_of(data type)

For a 32-bit int variable, it will be decremented by 2 bytes.

For a 64-bit int variable, it will be decremented by 4 bytes.

Pointer Addition in C

At the point when a pointer is added with a value, the value is first multiplied by the size of the data type and afterward added to the pointer.

The formula of adding value to a pointer is given below:

new_address= current_address + (number * size_of(data type))

For 32-bit int variable, it will add 2 * number.

For 64-bit int variable, it will add 4 * number.

Pointer Subtraction in C

At the point when a pointer is deducted with a value, the value is first multiplied by the size of the data type and afterward deducted from the pointer.

The formula of subtracting value from the pointer variable is given below:

new_address= current_address – (number * size_of(data type)

For 32-bit int variable, it will subtract 2 * number.

For 64-bit int variable, it will subtract 4 * number.

Dangling Pointers in C

While programming, we use pointers that contain memory locations of data objects. A dangling pointer is a pointer that focuses on the memory area even after its deallocation. Or then again we can say that pointer doesn’t highlight a valid data object of the suitable kind. The memory area pointed by the dangling pointer is known as a dangling reference.

Example of Dangling Pointers in C

#include <stdio.h>

#include <conio.h>

int *myvalue()

{

int a = 676;

return &a;

}

int main()

{

int *ptr = myvalue();

printf(“%d”, *ptr);

return 0;

}

Output:

trisl.c: In function ‘myvalue’:

trisl.c:6:12: warning: function returns address of local variable [-Wreturn-local-addr]

return &a;

^~

Explanation:

  1. Once the main() function is created where the pointer ‘ptr’ has been declared. It consists of the return value of the ‘myvalue()’.
  2. Once the ‘myvalue()’ is called, then the control moves from one context to another which is an integer *myvalue(), the ‘myvalue()’ then returns to the address of the ‘a’ variable.
  3. Once the control comes back to the main function, the variable will no longer be available. It causes a segmentation fault, that is, the code will be dumped.

sizeof( ) operator in C

Sizeof() administrator in C is machine-subordinate usefulness which shifts from one compiler to another. One might say that it is a byte explicit usefulness. It helps in giving the byte and size of the factors and the number it possesses for the assignment of the variable to the memory. Sizeof() work is exclusively used to discover the specific size of a variable utilized for programming in C.

Sizeof() operator has a return type which returns absolute bytes in memory to address the bytes. It is extremely valuable in the execution and improvement of convenient applications as it is truly adaptable and simple to take on for its adaptability.

Syntax of sizeof() operator with parameters:

  1. sizeof( type )
  2. sizeof( expression )
  3. sizeof( variable name )

Why do we need sizeof()

  1. To find out the number of elements in an array.
  2. To allocate a block of memory dynamically.

Example:

#include <stdio.h>

int main()

{

int p = 15;

float f = 18.20;

int q = 32;

double r = 10.34;

printf(“Size of Regular expression becomes %lu”, sizeof(p + (f – q) * r));

return 0;

}

Output:

Size of Regular expression becomes 8

Const Pointers in C

Let’s first get what a constant pointer is. A constant pointer is a pointer that can’t change the location of its holding. All in all, we can say that once a constant pointer focuses on a variable then it can’t highlight some other variable.

Below is the syntax for the constant pointers in C:

<type of pointer> *const <name of pointer>;

Let’s understand the constant pointer through an example.

#include <stdio.h>

#include <stdlib.h>

int main()

{

char variable1 = ‘A’, variable2 = ‘B’;

const char *pointer = &variable1;

//*pointer = variable2; This is not the correct way to change the pointer value , it will throw an error.

// Still we can change the pointer by changing the pointer itself

printf(“Current value of the pointer is : %c\n”, *pointer);

pointer = &variable2;

printf(“The value of the pointer after change is : %c\n”, *pointer);

}

Output:

Current value of the pointer is : A

The value of the pointer after change is : B

Pointer to Const

As apparent from the name, a pointer through which one can’t change the value of the variable it focuses on is known as a pointer to constant. These kinds of pointers can change the location they highlight yet can’t change the value kept at that location.

Below is the syntax of Pointers to Constant:

const <type of pointer>* <name of pointer>;

Let’s take a small code to illustrate a pointer to a constant :

#include <stdio.h>

int main()

{

int a = 50;

int b = 75;

const int *ptr;

ptr = &a;

ptr = &b;

printf(“Value of ptr is : %u”, ptr);

return 0;

}

Output:

Value of ptr is : 6422292

Constant Pointer to a Constant

In the event that you have perceived the over two kinds, this one is exceptionally straightforward as it’s a combination of the over two sorts of pointers you have seen above. A constant pointer to constant is a pointer that can neither change the location it’s highlighting to and nor it can change the value kept at that location.

Below is the syntax of Constant Pointer to a Constant:

const <type of pointer>* const <name of pointer>;

Let’s check out a piece of code to get this:

#include <stdio.h>

int main(void)

{

int var1 = 0, var2 = 0;

const int *const ptr = &var1;

*ptr = 17;

ptr = &var2;

printf(“%d\n”, *ptr);

return 0;

}

Output:

Void Pointers in C

The void pointer is a pointer that isn’t related to any information types. It focuses on certain information areas in the capacity that implies pointing to the address of variables. It is likewise called a general-purpose pointer.

Syntax of Void Pointer:

void *pointer name;

  • void indicates that the pointer is a void pointer
  • * indicates that the variable is a pointer variable
  • pointerName is the name of the pointer

Let us look at an example of declaring and initializing void pointer in C:

void *ptr;

char ch = ‘N’;

int num = 10;

ptr = &ch;

ptr = #

In the above code, we notice that since ptr is a void pointer, we can make it point to a variable of char type as well as a variable of int type. It can point to any type of variables.

Size of the void pointers in C

Size of the void pointer in C is as old as the size of the pointer of character type. As per C discernment, the portrayal of a pointer to void is as old as a pointer of character type. The size of the pointer will differ contingent upon the stage that you are utilizing.

Example:

#include <stdio.h>

int main()

{

void *ptr = NULL; //void pointer

int *p = NULL; // integer pointer

char *cp = NULL; //character pointer

float *fp = NULL; //float pointer

//size of void pointer

printf(“Size of void pointer = %d\n\n”, sizeof(ptr));

//size of integer pointer

printf(“Size of integer pointer = %d\n\n”, sizeof(p));

//size of character pointer

printf(“Size of character pointer = %d\n\n”, sizeof(cp));

//size of float pointer

printf(“Size of float pointer = %d\n\n”, sizeof(fp));

return 0;

}

Output:

Size of void pointer = 4

Size of integer pointer = 4

Size of character pointer = 4

Size of float pointer = 4

Dereferencing a void Pointer

We can’t just dereference a void pointer using indirection (*) operator. Let’s see the below example:

#include <stdio.h>

int main()

{

int a = 10;

void *ptr;

ptr = &a;

printf(“Value which is pointed by ptr pointer : %d”, *ptr);

return 0;

}

Output:

trisl.c: In function ‘main’:

trisl.c:7:58: warning: dereferencing ‘void *’ pointer

printf(“Value which is pointed by ptr pointer : %d”, *ptr);

^~~~

trisl.c:7:5: error: invalid use of void expression

printf(“Value which is pointed by ptr pointer : %d”, *ptr);

^~~~~~

*Note: In the above code, *ptr is a void pointer which is highlighting the integer variable ‘a’. As we definitely realize that the void pointer can’t be dereferenced, so the above code will give the compile time mistake since we are printing the value of the variable pointed by the pointer ‘ptr’ straightforwardly.

Now, we rewrite the above code to remove the error.

#include <stdio.h>

int main()

{

int a = 10;

void *ptr;

ptr = &a;

printf(“Value which is pointed by ptr pointer : %d”, *(int *)ptr);

return 0;

}

Output:

Value which is pointed by ptr pointer : 10

Pointer Arithmetic in Void Pointers

Another significant point I need to specify is about pointer arithmetic with the void pointer. Before you apply pointer arithmetic in void pointers try to give a legitimate typecast first any other way you might get unexpected results.

Example:

#include <stdio.h>

int main()

{

float a[4] = {5.7, 2.9, 8.8, 7.0};

void *ptr;

ptr = a;

for (int i = 0; i < 4; i++)

{

printf(“%f,”, *ptr);

ptr = ptr + 1; // Incorrect.

}

}

Output:

trisl.c: In function ‘main’:

trisl.c:10:23: warning: dereferencing ‘void *’ pointer

printf(“%f,”, *ptr);

^~~~

trisl.c:10:9: error: invalid use of void expression

printf(“%f,”, *ptr);

^~~~~~

*Note: The above code shows the compile-time error, as we cannot apply the arithmetic operations on void pointer directly, i.e., ptr=ptr+1.

Let’s rewrite the above code to remove the error,

#include <stdio.h>

int main()

{

float a[4] = {5.7, 2.9, 8.8, 7.0};

void *ptr;

ptr = a;

for (int i = 0; i < 4; i++)

{

printf(“%f,”, *((float *)ptr + i));

}

}

Output:

5.700000,2.900000,8.800000,7.000000,

*Note: The above code runs successfully as we applied the proper casting to the void pointer, i.e., (float*)ptr and then we apply the arithmetic operation, i.e., *((float*)ptr+i).

C Dereference Pointer

Dereferencing is a technique used to control or access information contained in a memory area that is highlighted by a pointer. Asterisk (*) is utilized alongside a pointer variable to dereference a pointer variable; it alludes to a variable that is being pointed. Henceforth it is called dereferencing of a pointer.

Steps on the best way to dereference a pointer:

  1. Declare the integer variable to which a pointer points:

int a = 3;

  1. Declare the integer pointer variable required:

int *ptr;

  1. After declaring an integer pointer variable, we can store the address of variable ‘a’ to a pointer variable ‘ptr’:

ptr = &a;

  1. Later the value of ‘a’ can be changed by dereferencing a pointer ‘ptr.’

*ptr = 5;

On the off chance that you follow the previously mentioned steps, it very well may be seen that the value of the variable ‘a’ will be changed to 5. This is on the grounds that the pointer ‘ptr’ focuses to the variable ‘a’ area, and dereferencing the pointer ‘ptr,’ that is, *ptr = 5, will refresh the value of x.

Example:

#include <stdio.h>

#include <conio.h>

int main()

{

int a = 3;

int *ptr;

ptr = &a;

*ptr = 21;

printf(“The value of the variable a is: %d”, a);

return 0;

}

Output:

The value of the variable a is: 21

Null Pointers in C

A Null Pointer is a pointer that doesn’t highlight any memory area. It stores the base location of the fragment. The invalid pointer fundamentally stores the Null value while void is the type of pointer.

If we do not have any address which is to be assigned to the pointer, then it is known as a null pointer. When a NULL value is assigned to the pointer, then it is considered as a Null pointer.

You can use null pointers in the following cases:

  1. To initialize a pointer variable when that pointer variable isn’t alloted any substantial memory address yet.
  2. To pass an invalid pointer to a function argument when we would prefer not to pass any legitimate memory address.
  3. To check for an invalid pointer prior to getting to any pointer variable. So, we can perform blunders when dealing with pointer-related code, for example dereference a pointer variable provided that it’s not NULL.

Examples of Null Pointer

int *ptr=(int *)0;

float *ptr=(float *)0;

char *ptr=(char *)0;

double *ptr=(double *)0;

int *ptr=NULL;

Example of Null Pointer

#include <stdio.h>

int main()

{

int *ptr = NULL; // ptr is a NULL pointer

printf(“The value of ptr is: %x “, ptr);

return 0;

}

Output:

The value of ptr is: 0

C Function Pointer

As we realize that we can make a pointer of any data type, for example, int, char, float, we can likewise make a pointer highlighting a function. The code of a function consistently lives in memory, which implies that the function has some location. We can get the location of memory by utilizing the function pointer.

Syntax:

function_return_type(*Pointer_name)(function argument list)

Example:

#include <stdio.h>

int main()

{

printf(“Address of main() function is %p”, main);

return 0;

}

Output:

Address of main() function is 00401460

Calling a function through a function pointer

We definitely realize how to call a function in the standard manner. Presently, we will perceive how to call a function using a function pointer.

Calling the above function in the usual way:

result = func(a , b); // Calling a function using the usual way.

Calling a function using a function pointer:

result = (*fp)( a , b); // Calling a function using function pointer.

Passing a function’s address as an argument to other function

We can pass the function’s address as an argument to different functions similarly we send different arguments to the function.

Let’s understand through an example:

#include <stdio.h>

void func1(void (*ptr)());

void func2();

int main()

{

func1(func2);

return 0;

}

void func1(void (*ptr)())

{

printf(“Function1 is called”);

(*ptr)();

}

void func2()

{

printf(“\nFunction2 is called”);

}

Output:

Function1 is called

Function2 is called

*Note: In the above code, we have made two functions, i.e., func1() and func2(). The func1() function contains the function pointer as an argument. In the main() technique, the func1() strategy is brought up in which we pass the address of func2. When the func1() function is called, ‘ptr’ contains the location of ‘func2’. Inside the func1() function, we call the func2() function by dereferencing the pointer ‘ptr’ as it contains the location of func2.

Function pointer as argument in C

We can pass the reference of a function as a boundary by utilizing a function pointer. This cycle is referred to as a call by reference as the function parameter is passed as a pointer that holds the address of arguments. If any change is made by the function using pointers, it will likewise mirror the progressions at the address of the passed variable.

Syntax:

(type) (*pointer_name)(parameter);

Example:

#include <stdio.h>

void display(void (*p)())

{

for (int i = 1; i <= 5; i++)

{

p(i);

}

}

void print_numbers(int num)

{

printf(“%d”, num);

}

int main()

{

void (*p)(int); // void function pointer declaration

printf(“The values are :”);

display(print_numbers);

return 0;

}

Output:

The values are :12345

In the above code,

  • We have defined two functions named ‘display()’ and print_numbers().
  • Inside the main() method, we have declared a function pointer named as (*p), and we call the display() function in which we pass the print_numbers() function.
  • In the definition of display() function, we have defined a ‘for’ loop, and inside the for loop, we call the print_numbers() function using statement p(i). Here, p(i) means that the print_numbers() function will be called on each iteration of i, and the value of ‘i’ gets printed.
nv-author-image

Vaibhav Kapoor

A professional web entrepreneur, WordPress developer and digital marketing strategist with more than 4 years of experience in building a business from scratch. Knowledgeable about SEO, blogging, internet marketing, social media and website development.

Leave a Reply

Your email address will not be published. Required fields are marked *

[wpfepp_submission_form form="1"]