- C Programming Tutorial
- C - Home
- C - Overview
- C - Features
- C - History
- C - Environment Setup
- C - Program Structure
- C - Hello World
- C - Compilation Process
- C - Comments
- C - Tokens
- C - Keywords
- C - Identifiers
- C - User Input
- C - Basic Syntax
- C - Data Types
- C - Variables
- C - Integer Promotions
- C - Constants
- C - Literals
- C - Escape sequences
- C - Storage Classes
- C - Operators
- C - Decision Making
- C - if statement
- C - if...else statement
- C - nested if statements
- C - switch statement
- C - nested switch statements
- C - Loops
- C - While loop
- C - For loop
- C - Do...while loop
- C - Nested loop
- C - Infinite loop
- C - Break Statement
- C - Continue Statement
- C - goto Statement
- C - Functions
- C - Main Functions
- C - Return Statement
- C - Recursion
- C - Scope Rules
- C - Arrays
- C - Properties of Array
- C - Multi-Dimensional Arrays
- C - Passing Arrays to Function
- C - Return Array from Function
- C - Variable Length Arrays
- C - Pointers
- C - Pointer Arithmetics
- C - Passing Pointers to Functions
- C - Strings
- C - Array of Strings
- C - Structures
- C - Structures and Functions
- C - Arrays of Structures
- C - Pointers to Structures
- C - Self-Referential Structures
- C - Nested Structures
- C - Unions
- C - Bit Fields
- C - Typedef
- C - Input & Output
- C - File I/O
- C - Preprocessors
- C - Header Files
- C - Type Casting
- C - Error Handling
- C - Variable Arguments
- C - Memory Management
- C - Command Line Arguments
- C Programming Resources
- C - Questions & Answers
- C - Quick Guide
- C - Useful Resources
- C - Discussion
C - Self-referential Structures
As the name suggests, 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 etc. In C, an array is allocated the required memory at the compile−time, and the array size cannot be modified during the runtime. Self−referential structures let you emulates the arrays by handling the size dynamically.
The file management systems in OS software are built upon dynamically constructed tree structures, which are manipulated by self−referential structures. Self−referential structures are also employed in many complex algorithms.
A general syntax of defining a self−referential structure is as follows −
strut typename{ type var1; type var2; . . struct typename *var3; }
Let us understand how self−referential structure is used, with the help of the following example −
We define a struct type called mystruct. It has an int element a, and b is the pointer to mystruct type itself.
We declare three variables of mystruct type −
struct mystruct x = {10, NULL}, y = {20, NULL}, z = {30, NULL};
Next, we declare three mystruct pointers and assign references to x,y and z to them.
struct mystruct * p1, *p2, *p3; 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. To explicitly establish link between them, we can store address of y in x, and address of z in y.
Let us implement this in the following program −
Example
#include <stdio.h> struct mystruct{ int a; struct mystruct *b; }; int main(){ struct mystruct x = {10, NULL}, y = {20, NULL}, z = {30, NULL}; struct mystruct * p1, *p2, *p3; p1=&x; p2=&y; p3=&z; x.b = p2; y.b = p3; printf("Add of x: %d a: %d add of next: %d\n", p1, x.a, x.b); printf("add of y: %d a: %d add of next: %d\n", p2, y.a, y.b); printf("add of z: %d a: %d add of next: %d\n", p3, z.a, z.b); return 0; }
Output
Add of x: 6422000 a: 10 add of next: 6421984 add of y: 6421984 a: 20 add of next: 6421968 add of z: 6421968 a: 30 add of next: 0
Let us refine the above program further. Instead of declaring variables and then storing their address in pointers, we shall use malloc() function to dynamically allocate memory whose address is stored in pointer variables. We then establish links between the three nodes as shown below −
Example
#include <stdio.h> #include <stdlib.h> struct mystruct{ int a; struct mystruct *b; }; int main(){ struct mystruct *p1, *p2, *p3; p1=(struct mystruct *)malloc(sizeof(struct mystruct)); p2=(struct mystruct *)malloc(sizeof(struct mystruct)); p3=(struct mystruct *)malloc(sizeof(struct mystruct)); p1->a=10; p1->b=NULL; p2->a=20; p2->b=NULL; p3->a=30; p3->b=NULL; p1->b = p2; p2->b = p3; printf("Add of x: %d a: %d add of next: %d\n", p1, p1->a, p1->b); printf("add of y: %d a: %d add of next: %d\n", p2, p2->a, p2->b); printf("add of z: %d a: %d add of next: %d\n", p3, p3->a, p3->b); return 0; }
Output
Add of x: 10032160 a: 10 add of next: 10032192 add of y: 10032192 a: 20 add of next: 10032224 add of z: 10032224 a: 30 add of next: 0
We can reach the next element in the link from its address stored in the earlier element, as p1−>b points to the address of p2. This while loop displays the linked list −
Example
#include <stdio.h> #include <stdlib.h> struct mystruct{ int a; struct mystruct *b; }; int main(){ struct mystruct *p1, *p2, *p3; p1=(struct mystruct *)malloc(sizeof(struct mystruct)); p2=(struct mystruct *)malloc(sizeof(struct mystruct)); p3=(struct mystruct *)malloc(sizeof(struct mystruct)); p1->a=10; p1->b=NULL; p2->a=20; p2->b=NULL; p3->a=30; p3->b=NULL; p1->b = p2; p2->b = p3; while (p1!=NULL){ printf("Add of current: %d a: %d add of next: %d\n", p1, p1->a, p1->b); p1=p1->b; } return 0; }
Output
Add of current: 10032160 a: 10 add of next: 10032192 Add of current: 10032192 a: 20 add of next: 10032224 Add of current: 10032224 a: 30 add of next: 0
Linked List
In the above examples, the dynamically constructed list has three discrete elements linked with pointers. We can use a for loop to set up required number of elements by allocating memory dynamically, and store the address of next element in the previous node. The following example is a more generalized solution of creating a linked list with self−referential structure.
Example
#include <stdio.h> #include <stdlib.h> struct mystruct{ int a; struct mystruct *b; }; int main(){ struct mystruct *p1, *p2, *start; int i; p1=(struct mystruct *)malloc(sizeof(struct mystruct)); p1->a=10; p1->b=NULL; start=p1; for (i=1; i<=5; i++){ p2=(struct mystruct *)malloc(sizeof(struct mystruct)); p2->a=i*2; p2->b=NULL; p1->b=p2; p1=p2; } p1=start; while (p1!=NULL){ printf("Add of current: %d a: %d add of next: %d\n", p1, p1->a, p1->b); p1=p1->b; } return 0; }
Output
Add of current: 11408416 a: 10 add of next: 11408448 Add of current: 11408448 a: 2 add of next: 11408480 Add of current: 11408480 a: 4 add of next: 11408512 Add of current: 11408512 a: 6 add of next: 11408544 Add of current: 11408544 a: 8 add of next: 11408576 Add of current: 11408576 a: 10 add of next: 0
Doubly linked list
This is linked list is traversed from beginning till it reaches NULL. You can also construct a doubly linked list, where the structure has two pointers, each referring to the address of previous and next element.
The struct definition for this purpose should be as below:
struct node { int data; int key; struct node *next; struct node *prev; };
Tree
Self−referential structures are also used to construct non−linear data structures as trees. A binary search tree is logically represented by the following figure −
The struct definition for the implementing a tree is as follows −
struct node { int data; struct node *leftChild; struct node *rightChild; };
To learn these complex data structure in detail, you can visit the DSA tutorial − https://www.tutorialspoint.com/data_structures_algorithms/index.htm