This article is the continuation of the Series on the C programming tutorial and carries the discussion on C language programming and its implementation. It aims to provide easy and practical examples for understanding the C program. In our last article, we saw the pointer’s advanced topics in C programming. In this tutorial, we are going to see Different types of pointers in c.
You can also read, embedded interview topics, compilation steps, and memory layout in C.
Table of Contents
Prerequisites
Before starting our topic, I would recommend you to read these pointer topics.
Different Types of Pointers in C
Pointers are the variables that are used to store the address of another variable. We can use this pointer to point to the address of another variable or function or another pointer. That we know already. If you don’t know, please read Prerequisites.
Now we will talk about types of the pointers in C. There are many different types of Pointers in C.
- NULL Pointer
- Void pointers or Generic Pointers
- Dangling Pointer
- Wild Pointer or Bad Pointer
- Near Pointer (old method, Not useful for nowadays)
- Far Pointer (old method, Not useful for nowadays)
- Huge Pointers (old method, Not useful for nowadays)
NULL Pointer
- A NULL pointer is a pointer that is pointing to nothing, i.e. it is assigned a null value.
- In case, if you don’t have an address to be assigned to a pointer then you can simply use
NULL
. (It is considered a good practice to set it to null.) - The pointer which is initialized with
NULL
value is considered as a NULL pointer. - NULL is a macro constant defined in the following header files
stdio.h
alloc.h
mem.h
stddef.h
stdlib.h
- Every pointer type i.e
int *
,char *
each has a null pointer value.
Syntax
<data type> *<variable name> = NULL;
Example
int *ptr = NULL; char *ptr = '\0'; float *ptr = (float *)0; double *ptr = NULL;
You can check the pointer is NULL
or not by using the below snippet.
if(ptr != NULL) { /*Pointer is not NULL*/ } else { /*Pointer is NULL*/ }
Note:
A null pointer is conceptually different from an uninitialized pointer. A null pointer is known not to point to any object or function; an uninitialized pointer might point anywhere. An uninitialized pointer stores an undefined value.
Void Pointer or Generic Pointers
- A void pointer is one that does not have any data type associated with it, i.e. it can be assigned a value of any type.
- It is a C convention for a raw address. It is capable of storing addresses of any data type.
- This is very useful when you want a pointer to point to data of different types at different times.
- We cannot dereference the generic pointer.
- The generic pointer can hold any type of pointer like a char pointer, struct pointer, an array of the pointer, etc. without any typecasting.
- Any type of pointer can hold a generic pointer without any typecasting.
- Generic pointers are used when we want to return such a pointer which is applicable to all types of pointers. For example return type of the malloc function is a generic pointer because it can dynamically allocate the memory space to store an integer, float, structure, etc. hence we can typecast its return type to the appropriate pointer type.
Syntax
void *<data type>;
Example
void *ptr; //void pointer int a; char c; ptr = &a; //ptr changes to integer pointer as address of integer is assigned to it ptr = &c; //ptr changes to character pointer as address of character is assigned to it
Dangling Pointer
- Dangling pointers are pointers that point to a memory location that has been deleted (or freed).
- Dangling pointers arise during object destruction, when an object that has an incoming reference is deleted or deallocated, without modifying the value of the pointer, so that the pointer still points to the memory location of the deallocated memory.
Causes of dangling pointers
-
Return Local Variable in Function Call
-
Variable goes Out of Scope
-
Accessing the De-allocating or free variable memory
Example
Return Local Variable in Function Call
char* func() { char str[10]; strcpy(str,"Hello!"); return(str); } //returned pointer points to str which has gone out of scope.
Variable goes Out of Scope
#include<stdio.h> int main() { char **strPtr; { char *str = "Hello!"; strPtr = &str; } // str falls out of scope // strPtr is now a dangling pointer printf("%s", *strPtr); }
Accessing the De-allocating or free variable memory
int *c = malloc(sizeof(int)); free(c); *c = 3; //writing to freed location!
Avoiding dangling pointer errors
- We can avoid dangling pointer errors by initializing the pointer to
NULL
after de-allocating memory, so that the pointer will be no longer dangling. - Assigning
NULL
value means the pointer is not pointing to any memory location. See the below snippet to avoid dangling pointers.
Note:
In some compilers, you may get a warning message returning the address of a local variable or temporary.
int *c = malloc(sizeof(int)); free(c); c = NULL;
Wild Pointer or Bad Pointer
- A pointer that has not been initialized to anything till its first use (not even
NULL
) is known as a wild pointer. The pointer may be initialized to a non-NULL garbage value that may not be a valid address. - A wild pointer is also called a Bad pointer because without assigning any variable address, it points to the memory location.
int main() { int *ptr; /* wild pointer */ int x = 10; // ptr is not a wild pointer now ptr = &x; return 0; }
Note:
We can initialize a pointer at the point of a declaration by the address of some object/variable or by NULL;
Old method Pointers
In TURBO C there are three types of pointers. TURBO C works under the DOS operating system which is based on an 8085 microprocessor. These are some old concepts used in 16-bit intel architectures in the days of MS-DOS, not very useful anymore.
Near Pointers
- Near pointer is used to store 16-bit addresses means within the current segment on a 16-bit machine. The limitation is that we can only access 64kb of data at a time.
- That is near pointer cannot access beyond the data segment like graphics video memory, text video memory, etc.
- The size of the near pointer is two bytes.
- With help of keyword near, we can make any pointer a near pointer.
Example
#include<stdio.h> int main() { int x=25; int near* ptr; ptr=&x; printf(“%d”,sizeof ptr); return 0; }
Output: 2
Far Pointers
- The pointer that can point or access whole the residence memory of RAM, i.e., which can access all 16 segments is known as the far pointer.
- The size of the far pointer is 4 bytes or 32-bit.
Example
#include<stdio.h> int main() { int x=10; int far *ptr; ptr=&x; printf("%d",sizeof ptr); return 0; }
Output: 4
In that 4bytes,
- First 16-bit stores: Segment number
- Next 16-bit stores: Offset address
#include<stdio.h> int main() { int x=100; int far *ptr; ptr=&x; printf("%Fp",ptr); //%Fp is used for print offset and segment address of pointer in printf function in hexadecimal number format return 0; }
Output: 8FD8:FFF4
Here 8FD8 is the segment address and FFF4 is the offset address in hexadecimal number format.
Note:
We cannot guess what will be offset address, segment address, and far address of any far pointer. These addresses are decided by the operating system.
Limitation of far pointer
We cannot change or modify the segment address of the given far address by applying any arithmetic operation on it. That is by using the arithmetic operator we cannot jump from one segment to another segment. If you will increment the far address beyond the maximum value of its offset address instead of incrementing the segment address it will repeat its offset address in cyclic order.
Huge Pointers
- The pointer that can point or access whole the residence memory of RAM i.e. which can access all 16 segments is known as a huge pointer.
- The size of a huge pointer is 4 bytes or 32-bit
Example
#include<stdio.h> int main() { char huge * far *p; printf("%d %d %d",sizeof(p),sizeof(*p),sizeof(**p)); return 0; }
Output: 4 4 1
Normalization of huge pointer
Turbo C compiler is based on an 8085 microprocessor in which the physical address of memory is represented in 20 bits. Conversion of 4 bytes or 32-bit huge addresses into 20-bit actual physical addresses is known as normalization.
Note: If you will increment a huge pointer it will increment both offset and segment address unlike to far pointer which only increments offset address. So, if you have little knowledge about huge pointer and you are using huge pointer then you can easily access and modify the IVT, device driver memory, video memory, etc. This might be dangerous for your computer.
Why there are three types of pointers in the Turbo C compiler?
Turbo c compiler is based on Dos operating system which is based on 8085 microprocessors. In the 8085 microprocessor, the actual physical address is represented in 20 bits. But there are not any pointers that can point 20-bit address. Considering the simplicity of calculations, access to an actual physical address, security, etc. c has introduced three types of pointers i.e. near, far, and huge pointer.
You can also see the Important interview topics in the C Program.
In our next article, we will see callback functions in C programming.
You can also read the below tutorials.
Embedded Software | Firmware | Linux Devic Deriver | RTOS
Hi, I am a tech blogger and an Embedded Engineer. I am always eager to learn and explore tech-related concepts. And also, I wanted to share my knowledge with everyone in a more straightforward way with easy practical examples. I strongly believe that learning by doing is more powerful than just learning by reading. I love to do experiments. If you want to help or support me on my journey, consider sharing my articles, or Buy me a Coffee! Thank you for reading my blog! Happy learning!