0% found this document useful (0 votes)
4 views

PSC-unit 4

This document provides an overview of structures and pointers in C programming, detailing how to define and access structures, use arrays within structures, and pass structures as function arguments. It also covers nested structures, typedef for simplifying structure declarations, and introduces unions as a user-defined data type. Examples are provided to illustrate the concepts and their applications in managing complex data types effectively.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

PSC-unit 4

This document provides an overview of structures and pointers in C programming, detailing how to define and access structures, use arrays within structures, and pass structures as function arguments. It also covers nested structures, typedef for simplifying structure declarations, and introduces unions as a user-defined data type. Examples are provided to illustrate the concepts and their applications in managing complex data types effectively.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 56

UNIT 4 STRUCTURES AND POINTERS

Structures and unions - accessing structure members arrays within structures, arrays of
structures, structures within structures,passing structures as function arguments. Type defining
structures,Pointers: Pointer variables. Declaring and dereferencing pointer variables. Pointer
Arithmetic. Examples. Accessing arrays through pointers. Pointers and strings. Pointers to
Functions (call by value and call by reference -Pointers to Arrays, Pointers to Structures,
Dynamic memory allocation.

4.1 Structures

Why do we use Structure?

In C, there are cases where we need to store multiple attributes of an entity. It is not necessary
that an entity has all the information of one type only. It can have different attributes of different
data types.

For example, an entity Student may have its name (string), roll number (int), marks (float). To
store such type of information, we use a special data structure called “Structure”.

What is Structure?

Structure in C is a user-defined data type that enables us to store the collection of different data
types. Each element of a structure is called a member.

Syntax to define Structure

The keyword, struct is used to define the structure.

struct structure_name

{
data_type member1;
data_type member2;
..
..
data_type memberN;
};

Example to define a Structure for an entity employee in C.

struct employee
{ int id;
char name[20] ;
char company[100] ;
};

The following image shows the memory allocation of the structure employee that is defined in
the above example.

Here, struct is the keyword.

employee is the name of the structure.

id, name, and salary are the members or fields of the structure.

Let's understand it by the diagram given below:

Declaring structure variable

We can declare a variable for the structure so that we can access the member of the structure
easily. There are two ways to declare structure variable:

1. By declaring the structure variable keyword within the main() function.


2. By declaring the variable at the time of defining the structure.
1st way:

Let's see the example to declare the structure variable by struct keyword. It should be declared
within the main function.

struct employee
{ int id;
char name[50] ;
char company[100] ;
};

Now write the given code inside the main() function.

struct employee e1, e2;

The variables e1 and e2 can be used to access the values stored in the structure. Here, e1 and
e2 can be treated in the same way as the objects in C++ and Java.

2nd way:

Another way to declare structure variable is at the time of defining the structure.

struct employee
{ int id;
char name[50];
char company[100] ;
} e1, e2;

Which approach is good

If the number of variables is not fixed, the first approach can be used. It provides the flexibility
to declare the structure variable many times.

If number of variables are fixed, second approach can be used.

4.2 Accessing members of the structure

There are two ways to access structure members:

1. By using . operator (member or dot operator)


2. By using -> operator (structure pointer operator)

The following statement is used to access the structure member “id” of variable p1, using .
(member) operator.

p1.id
C Structure Example

Let's see a simple example of structure in C language.

#include<stdio.h>
#include <string.h>
struct employee
{ int id;
char name[50];
} e1; //declaring structure variable, e1

int main()
{
//store first employee information
e1.id=101;
strcpy (e1.name, "Ganesh");//copying string into char array
//printing first employee information
printf( "Employee 1 id : %d", e1.id);
printf( "Employee 1 name : %s", e1.name);
return 0;
}

Output:

Employee 1 id: 101


Employee 1 name: Ganesh

Let's see another example of the structure in C language to store many employees information.

#include<stdio.h>
#include <string.h>
struct employee
{ int id;
char name [50];
float salary;
} e1, e2; // declaring structure variables, e1 and e2

int main ()
{
//store first employee information
e1.id=101;
strcpy(e1.name, "Harishva");//copying string into char array
e1.salary=150000;

//store second employee information


e2.id=102;
strcpy(e2.name, "Krithik");
e2.salary=140000;

//printing first employee information


printf( "Employee 1 Id: %d", e1.id);
printf( "Employee 1 Name : %s", e1.name);
printf( "Employee 1 salary : %f", e1.salary);

//printing second employee information


printf( "Employee 2 Id : %d", e2.id);
printf( "Employee 2 Name : %s", e2.name);
printf( "Employee 2 salary : %f", e2.salary);
return 0;
}

Output:

employee 1 id : 101
employee 1 name : Harishva
employee 1 salary : 150000
employee 2 id : 102
employee 2 name : Krithik
employee 2 salary : 140000

ARRAYS WITHIN A STRUCTURE

An array can be declared inside a structure as a member when we need to store multiple
members of the same type.
For example, suppose we have an employee and we need to store the data of his/her weekly
attendance. So for that, we need to define a structure of type Employee and store the data
within that.
struct Employee
{
int day1, day2, day3, day4, day5, day6, day7;
};

Syntax to Declare Array Within Structure


The below syntax is to declare array within structure in C.

struct StructureName {
// Other members
dataType arrayName[arraySize];
};

Accessing Elements of an Array within a Structure


We can access the elements of the array within the structure using the dot (.) operator along
with the array index inside array subscript operator.

structureName.arrayName[index]

Example of Array within Structure in C

// C program to demonstrate the array within structures

#include <string.h>
#include <stdio.h>
// Defining array within structure
struct Employee
{
// character array to store name of the employee
char Name[20];
int employeeID;
// integer array to maintain the record of attendanc eof
// the employee
int WeekAttendence[7];
};
int main()
{
// defining structure of type Employee
struct Employee emp;

// Adding data
emp.employeeID = 1;
strcpy(emp.Name, "Rohit");
int week;
for (week = 0; week < 7; week++) {
int attendence;
emp.WeekAttendence[week] = week;
}
printf("\n");
// printing the data
printf("Emplyee ID: %d - Employee Name: %s\n",
emp.employeeID, emp.Name);
printf("Attendence\n");
for (week = 0; week < 7; week++) {
printf("%d ", emp.WeekAttendence[week]);
}
printf("\n");
return 0;
}

Output
Emplyee ID: 1 - Employee Name: Rohit
Attendence
0123456
4.3 ARRAYS OF STRUCTURES
An array of structures in C can be defined as the collection of multiple structures variables
where each variable contains information about different entities. The array of structures in
C are used to store information about multiple entities of different data types.
The array of structures is also known as collection of structures.

Need for Array of Structures


Suppose we have 100 employees and we need to store the data of 100 employees. So for that,
we need to define 100 variables of struct Employee type and store the data within that.
For that, we can define an array whose data type will be struct Employee so that it will be
easily manageable.
For Example:
Instead of using the below statement:
struct Employee emp1, emp2, emp3, emp4.......emp100;
We will use the statement shown below in our program
struct Employee emp [100];
// Then we can easily access different employee details by emp [0], emp [1], etc.

Declaration of Array of Structures


struct structure_name array_name [number_of_elements];
Example of Array of Structure in C
#include<stdio.h>
struct student
{
int rollno;
char name[10];
int marks;
};
int main ()
{
struct student st[5];
printf("Enter the Records of 5 students");
for(int i=0;i<5;i++)
{
printf("Enter Rollno:");
scanf("%d",&st[i].rollno);
printf("Enter Student Name:");
scanf("%s",st[i].name);
printf("Enter the marks:");
scanf("%d",&st[i].marks);
}
printf("Student Information List:");
for(i=0;i<5;i++)
{
printf("Rollno: %d", st[i].rollno);
printf("Student Name : %s", st[i].name);
printf("Marks: %d " , st[i].marks);
}
return 0;
}

Output:

Enter Records of 5 students


Enter Rollno:1
Enter Name:Hari
Enter Rollno:2
Enter Name:Shiva
Enter Rollno:3
Enter Name:Krithik
Enter Rollno:4
Enter Name: Brahma
Enter Rollno:5
Enter Name:Gautham

Student Information List:


Rollno:1
Student Name:Hari
Marks: 100
Rollno:2
Student Name:Shiva
Marks:100
Rollno:3
Student Name:Krithik
Marks:100
Rollno:4
Student Name:Brahma
Marks:100
Rollno:5
Student Name: Gautham
Marks:98

4.4 STRUCTURES WITHIN STRUCTURES (NESTED STRUCTURE)


A Nested structure in C is a Structure within Structure. One structure can be declared inside
another structure in the same way structure members are declared inside a structure.
Syntax:
struct name_1
{
member1;
member2;
.
.
membern;
struct name_2
{
member_1;
member_2;
.
.
member_n;
} var1;
} var2;

Define the Inner Structure


First, define a basic structure that will be used within another structure.
struct Date
{
int day;
int month;
int year;
};

Define the Outer Structure


Next, define the outer structure, including the inner structure as a member.
struct Employee
{
char name[50];
int id;
struct Date birthday; // Nested structure
};

The member of a nested structure can be accessed using the following syntax:
Variable name of Outer_Structure.Variable name of Nested_Structure.data member to
access

Structures within Structures - Example


#include <stdio.h>
#include <string.h>
struct Employee
{
int id;
char name[20];
struct Date
{
int dd;
int mm;
int yyyy;
} doj;
} e1;
int main ()
{
//storing employee information
e1.id = 101;
strcpy (e1.name, "Krish"); //copying string into char array
e1.doj.dd = 10;
e1.doj.mm = 11;
e1.doj.yyyy = 2014;
//printing first employee information
printf ("employee id : %d", e1.id);
printf ("employee name : %s", e1.name);
printf ("employee date of joining (dd/mm/yyyy) : %d/%d/%d", e1.doj.dd, e1.doj.mm,
e1.doj.yyyy);
return 0;
}
Output:

4.5 PASSING STRUCTURE AS FUNCTION ARGUMENTS

Passing an entire structure as an argument to function

• Name of the structure variable is given as argument in function call.


• It is collected in another structure variable in function header.
• The disadvantage is that a copy of an entire structure is created again by wasting the
memory.

Example 1:

The following program shows how to pass an entire structure as an argument to function.

#include<stdio.h>
struct date
{
int day;
char month[10];
int year;
};
int main()
{
struct date d;
printf("enter the day,month and year:");
scanf("%d%s%d", &d.day, d.month, &d.year);
display(d);//passing entire structure as an argument to function
return 0;
}
void display (struct date d)
{
printf("day=%d", ,d.day);
printf("month=%s", d.month);
printf("year=%d", d.year);
}
ADVERTISEMENT

Output

When the above program is executed, it produces the following result −


enter the day, month and year:18 JAN 2021
day=18
month=JAN
year=2021

Example 2

Consider another example that demonstrate the passing of an entire structure as an argument
to function.

#include<stdio.h>
struct add{
int var1;
int var2;
}a;
//Declaring and returning Function //
void show(struct add a)
{
//Declaring sum variable//
int sum;
//Arithmetic Operation//
sum=a.var1+a.var2;
//Printing O/p //
printf("Added value is %d",sum);
}
void main()
{
//Declaring structure//
struct add a;
//Reading User I/p
printf("Enter variable 1 = ");
scanf("%d”, &a.var1);
printf("Enter variable 2 = ");
scanf("%d", &a.var2);
//Calling function //
show(a);
}

Output

When the above program is executed, it produces the following result

Enter variable 1 = 20
Enter variable 2 = 50
Added value is 70
4.6 TYPE DEFINING STRUCTURES
Using the typedef keyword:
There is no longer a need to type struct again and again with every declaration of the variable
of this type.
Method 1:
In the code below, the structure Point is defined separately using struct Point, and then
a typedef is applied to create an alias Point for this structure. This allows us to declare variables
of this structure type using just Point.
4
15
#include<stdio.h>
struct Point
{
int x;
int y;
};
typedef struct Point Point;
int main()
{
Point p1;
p1.x = 1;
p1.y = 3;
printf("%d ", p1.x);
printf("%d ", p1.y);
return 0;
}
Run
Declaration of variable without mentioning struct again
1 3

Method 2:
The typedef is applied directly to the structure definition itself. This combines the definition of
the structure and the creation of the alias Point in a single statement.
#include<stdio.h>
// Define a structure named Point with two integer members: x and y
typedef struct Point{
int x;
int y;
} Point;
int main()
{
// Declare a variable named p1 of type Point
Point p1;
p1.x = 1;
p1.y = 3;
printf("%d \n", p1.x);
printf("%d \n", p1.y);
return 0;
C program to implement typedef with structures

#include <stdio.h>
#include <string.h>

// using typedef to define an alias for structure


typedef struct students
{
char name[50];
char branch[50];
int ID_no;
} stu;

// Driver code
int main()
{
stu st;
strcpy(st.name, "HariShiva");
strcpy(st.branch, "Computer Science and Engineering");
st.ID_no = 108;

printf("Name: %s\n", st.name);


printf("Branch: %s\n", st.branch);
printf("ID_no: %d\n", st.ID_no);
return 0;
}

Output
Name: HariShva
Branch: Computer Science and Engineering
ID_no: 108
4.7 Union
The Union is a user-defined data type in C language that can contain elements of the different
data types just like structure. But unlike structures, all the members in the C union are stored
in the same memory location. Due to this, only one member can store data at the given
instance.
Syntax of Union in C
union union_name
{
datatype member1;
datatype member2;
...
};

Different Ways to Define a Union Variable

There are two methods using which we can define a union variable.
1. With Union Declaration
2. After Union Declaration
1. Defining Union Variable with Declaration
union union_name
{
datatype member1;
datatype member2;
...
} var1, var2, ...;

2. Defining Union Variable after Declaration

union union_name var1, var2, var3...;


where union_name is the name of an already declared union.

Access Union Members

We can access the members of a union by using the ( . ) dot operator just like structures.

var1.member1;
where var1 is the union variable and member1 is the member of the union.

Example of Union

// C Program to demonstrate how to use union


#include <stdio.h>
union un
{
int member1;
char member2;
float member3;
};

// driver code
int main()
{
// defining a union variable
union un var1;

// initializing the union member


var1.member1 = 15;

printf("The value stored in member1 = %d", var1.member1);


return 0;
}

Output
The value stored in member1 = 15
Differences between Structure and Union

Differences between Array and Structure


S.No. Array Structure

An array is a collection that consists of A Structure is a collection that consists of


1. elements of homogenous, (i.e.) of same elements of heterogeneous or dissimilar data
data type types.

Array uses subscripts or '[ ]' (square Structure uses the '.' (dot operator) to access
2.
brackets) to access the elements the elements.

3. The size of an array is fixed The size of a structure is not fixed

Traversing through and searching for Traversing through and searching for
4.
elements in an array is quick and easy. elements in a structure is slow and complex.

An array is always stored in contiguous A structure may or may not be stored in


5.
memory locations. contiguous memory locations.

POINTER
4.8 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.

4.9 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.
Example:
int *a;
int b=10;
a=&b;

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
int x = 10;
int *ptr = &x;
Here, x is an integer variable, ptr is an integer pointer. The pointer ptr is being initialized with
x.

4.10 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

& 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.
* 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

4.11Pointer Arithmetic

C pointers arithmetic operations are different from the general arithmetic operations. The
following are some of the important pointer arithmetic operations in C:

Increment and Decrement of a Pointer


Addition and Subtraction of Integer to Pointer
Subtraction of Pointers
Comparison of Pointers

Increment and Decrement of a Pointer

"++" and "--" are used as the increment and decrement operators in C. They are unary operators,
used in prefix or postfix manner with numeric variable operands, and they increment or
decrement the value of the variable by one.

Assume that an integer variable "x" is created at address 1000 in the memory, with 10 as its
value. Then, "x++" makes the value of "x" as 11.

int x = 10; // created at address 1000

x++; // x becomes 11
What happens if we declare "y" as pointer to "x" and increment "y" by 1 (with "y++")? Assume
that the address of "y" itself is 2000.

int x = 10; // created at address 1000

// "y" is created at address 2000


// it holds 1000 (address of "x")
int *y = &x ;

y++; // y becomes 1004


Since the variable "y" stores 1000 (the address of "x"), we expect it to become 1001 because
of the "++" operator, but it increments by 4, which is the size of "int" variable.
The is why because, if the address of "x" is 1000, then it occupies 4 bytes: 1000, 1001, 1002
and 1003. Hence, the next integer can be put only in 1004 and not before it. Hence "y" (the
pointer to "x") becomes 1004 when incremented.

4.12 Example of Incrementing a Pointer


The following example shows how you can increment a pointer −

#include <stdio.h>

int main(){

int x = 10;
int *y = &x;

printf("Value of y before increment: %p\n", y);

y++;

printf("Value of y after increment: %p", y);


}
Output
Run the code and check its output −

Value of y before increment: 6422036


Value of y after increment: 6422040
You can see that the value has increased by 4. Similarly, the "--" operator decrements the value
by the size of the data type.

Example of Decrementing a Pointer


Let us change the types of "x" and "y" to "double" and "float" and see the effect of decrement
operator.

#include <stdio.h>

int main(){

double x = 10;
double *y = &x;

printf("value of y before decrement: %ld\n", y);

y--;

printf("value of y after decrement: %ld", y);


}
Output
Value of y before decrement: 6422032
Value of y after decrement: 6422028
When an array is declared, the elements are stored in adjacent memory locations. In case of
"int" array, each array subscript is placed apart by 4 bytes, as the following figure shows
Hence, if a variable stores the address of 0th element of the array, then the "increment" takes it
to the 1st element.

Example of Traversing an Array by Incrementing Pointer


The following example shows how you can traverse an array by incrementing a pointer
successively

#include <stdio.h>

int main(){

int a[]= {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
int len = sizeof(a)/sizeof(int);
int *x = a;
int i = 0;

for(i = 0; i < len; i++){


printf("Address of subscript %d = %d Value = %d\n", i, x, *x);
x++;
}

return 0;
}

Output:

Address of subscript 0 = 6421984 Value = 10


Address of subscript 1 = 6421988 Value = 20
Address of subscript 2 = 6421992 Value = 30
Address of subscript 3 = 6421996 Value = 40
Address of subscript 4 = 6422000 Value = 50
Address of subscript 5 = 6422004 Value = 60
Address of subscript 6 = 6422008 Value = 70
Address of subscript 7 = 6422012 Value = 80
Address of subscript 8 = 6422016 Value = 90
Address of subscript 9 = 6422020 Value = 100
Addition and Subtraction of Integer to Pointer
An integer value can be added and subtracted to a pointer. When an integer is added to a pointer,
the pointer points to the next memory address. Similarly, when an integer is subtracted from a
pointer, the pointer points to the previous memory location.

Addition and subtraction of an integer to a pointer does not add and subtract that value to the
pointer, multiplication with the size of the data type is added or subtracted to the pointer.

For example, there is an integer pointer variable ptr and it is pointing to an address 123400, if
you add 1 to the ptr (ptr+1), it will point to the address 123404 (size of an integer is 4).

Let's evaluate it,


ptr = 123400
ptr = ptr + 1
ptr = ptr + sizeof(int)*1
ptr = 123400 + 4
ptr = 123404
Example of Adding Value to a Pointer
In the following example, we are declaring an array and pointer to an array. Initializing the
pointer with the first element of the array and then adding an integer value (2) to the pointer to
get the third element of the array.

#include <stdio.h>

int main() {
int int_arr[] = {12, 23, 45, 67, 89};
int *ptrArr = int_arr;

printf("Value at ptrArr: %d\n", *ptrArr);

// Adding 2 in ptrArr
ptrArr = ptrArr + 2;

printf("Value at ptrArr after adding 2: %d\n", *ptrArr);

return 0;
}

Output
Value at ptrArr: 12
Value at ptrArr after adding 2: 45

Example of Subtracting Value to a Pointer

In the following example, we are declaring an array and pointer to an array. Initializing the
pointer with the last element of the array and then subtracting an integer value (2) from the
pointer to get the third element of the array.

#include <stdio.h>

int main() {
int int_arr[] = {12, 23, 45, 67, 89};
int *ptrArr = &int_arr[4]; // points to last element

printf("Value at ptrArr: %d\n", *ptrArr);

// Subtracting 2 in ptrArr
ptrArr = ptrArr - 2;

printf("Value at ptrArr after adding 2: %d\n", *ptrArr);

return 0;
}
Output
Value at ptrArr: 89
Value at ptrArr after adding 2: 45
Subtraction of Pointers

We are familiar with the "+" and "−" operators when they are used with regular numeric
operands. However, when you use these operators with pointers, they behave in a little different
way.

Since pointers are fairly large integers (especially in modern 64-bit systems), addition of two
pointers is meaningless. When we add a 1 to a pointer, it points to the next location where an
integer may be stored. Obviously, when we add a pointer (itself a large integer), the location it
points may not be in the memory layout.

However, subtraction of two pointers is realistic. It returns the number of data types that can
fit in the two pointers.

Example of Subtracting Two Pointers

Let us take the array in the previous example and perform the subtraction of pointers of a[0]
and a[9]

#include <stdio.h>

int main(){

int a[]= {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
int *x = &a[0]; // zeroth element
int *y = &a[9]; // last element

printf("Add of a[0]: %ld add of a[9]: %ld\n", x, y);


printf("Subtraction of two pointers: %ld", y-x);

Output

Add of a[0]: 140729162482768 add of a[9]: 140729162482804


Subtraction of two pointers: 9
It can be seen that the numerical difference between the two integers is 36; it suggests that the
subtraction is 9, because it can accommodate 9 integers between the two pointers.

Comparison of Pointers

Pointers may be compared by using relational operators such as "==", "<", and ">". If "p1" and
"p2" point to variables that are related to each other (such as elements of the same array), then
"p1" and "p2" can be meaningfully compared.

Example of Comparing Pointers


In the following example, we are declaring two pointers and initializing them with the first and
last elements of the array respectively. We will keep incrementing the first variable pointer as
long as the address to which it points is either less than or equal to the address of the last
element of the array, which is "&var[MAX − 1]" (i.e., the second pointer).

#include <stdio.h>
const int MAX = 3;
int main() {
int var[] = {10, 100, 200};
int i, *ptr1, *ptr2;
// Initializing pointers
ptr1 = var;
ptr2 = &var[MAX - 1];

while (ptr1 <= ptr2) {


printf("Address of var[%d] = %p\n", i, ptr1);
printf("Value of var[%d] = %d\n", i, *ptr1);

/* point to the previous location */


ptr1++;
i++;
}

return 0;
}
Output:

Address of var[0] = 0x7ffe7101498c


Value of var[0] = 10
Address of var[1] = 0x7ffe71014990
Value of var[1] = 100
Address of var[2] = 0x7ffe71014994
Value of var[2] = 200

Applications of Pointers in C

One of the most important features of C is that it provides low-level memory access with the
concept of pointers. A pointer is a variable that stores the address of another variable in the
memory.

The provision of pointers has many applications such as passing arrays and struct type to a
function and dynamic memory allocation, etc. In this chapter, we will explain some important
applications of pointers in C.

4.13 Accessing Arrays through pointers

Array elements can also be accessed through the pointer. You need to declare and initialize a
pointer to an array and using it you can access each element by incrementing the pointer
variable by 1.

The pointer to an array is the address of its 0th element. When the array pointer is incremented
by 1, it points to the next element in the array.
Example

The following example demonstrates how you can traverse an array with the help of its pointer.

#include <stdio.h>

int main(){

int arr[] = {1,2,3,4,5};


int *ptr = arr;

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


printf("arr[%d]: %d\n", i, *ptr);
ptr++;
}

return 0;
}
Output
Run the code and check its output −

arr[0]: 1
arr[1]: 2
arr[2]: 3
arr[3]: 4
arr[4]: 5

4.14Pointer and String in C

In C programming, pointers are a powerful tool that allow us to work with strings efficiently.
Strings in C are essentially arrays of characters terminated by a null character (\0). A pointer
to a string refers to the memory address where the string starts, and can be manipulated using
pointer arithmetic.

1. Strings as Character Arrays

In C, a string is an array of characters, and it can be declared like this:

char str[] = "Hello";

In memory, this string will be stored as:

arduino

'H' 'e' 'l' 'l' 'o' '\0'

The \0 is the null terminator, marking the end of the string.


2. Pointers and Strings

A pointer can also point to the first element of a string (character array). When we use pointers,
we can work with strings more flexibly.

Syntax:

char *str = "Hello";

In this case, str points to the memory location where the string "Hello" is stored. It is important
to note that strings declared this way are usually stored in a read-only section of memory, and
you should avoid modifying them.

3. Pointer Arithmetic and Strings

We can use pointer arithmetic to navigate through the characters in a string. For example, if str
points to the first character of the string, str + 1 points to the second character, str + 2 to the
third, and so on.

Example:

#include <stdio.h>

int main() {
char *str = "Hello"; // Pointer to string

// Using pointer to access characters


printf("First character: %c\n", *str); // H
printf("Second character: %c\n", *(str + 1)); // e

// Printing string using pointer


while (*str != '\0') {
printf("%c", *str); // Dereference and print each character
str++; // Move to next character
}
printf("\n");

return 0;
}
Explanation:

• *str dereferences the pointer to get the first character.


• str++ increments the pointer to point to the next character in the string.
• This process continues until the null terminator (\0) is reached.

4. Modifying Strings with Pointers

If a string is declared as a character array, it can be modified using a pointer.

Example:
#include <stdio.h>

int main() {
char str[] = "Hello"; // Modifiable character array

char *ptr = str; // Pointer to the string

*ptr = 'J'; // Modify the first character


printf("%s\n", str); // Output: Jello

*(ptr + 1) = 'a'; // Modify the second character


printf("%s\n", str); // Output: Jallo

return 0;
}
Explanation:

• We modify the string through the pointer by dereferencing it (*ptr), and the changes
are reflected in the original string.
• *(ptr + 1) accesses the second character, allowing us to change it.

5. Pointer to String vs Array of Characters

• Pointer to String:
o The string is stored in a read-only section, and modifying it can cause undefined
behavior.
o Example:

c
Copy code
char *str = "Hello"; // Do not modify this string!

• Array of Characters:
o The string is stored in modifiable memory (usually on the stack), and you can
modify the string.
o Example:

c
Copy code
char str[] = "Hello"; // Can be modified
6. Common String Operations using Pointers

Here are a few examples of common string operations done using pointers:

1. Length of a String (strlen):

#include <stdio.h>

int stringLength(const char *str) {


const char *ptr = str; // Save the original pointer
while (*ptr != '\0') {
ptr++;
}
return ptr - str; // Pointer arithmetic to get length
}

int main() {
char str[] = "Hello";
printf("Length of string: %d\n", stringLength(str)); // Output: 5
return 0;
}
2. Copying a String (strcpy):

#include <stdio.h>

void stringCopy(char *dest, const char *src) {


while (*src != '\0') {
*dest = *src;
src++;
dest++;
}
*dest = '\0'; // Null-terminate the copied string
}

int main() {
char src[] = "Hello";
char dest[10];

stringCopy(dest, src);
printf("Copied string: %s\n", dest); // Output: Hello

return 0;
}
Summary:

• Strings in C are arrays of characters terminated by \0.


• Pointers can be used to point to the first character of the string and manipulate the
string using pointer arithmetic.
• Strings declared as arrays can be modified, but strings declared as pointers (char *str =
"text") should not be modified, as they often point to read-only memory.

4.15 Pointers to Functions (call by value and call by reference)

In C programming, a pointer to a function is a pointer that points to the address


of a function, allowing you to pass the function itself as a parameter or use it indirectly through
the pointer. Let's discuss how pointers to functions can be used with call by value and call by
reference.

1. Pointer to Function with Call by Value

In call by value, the function receives a copy of the variable’s value. Any modifications made
to the parameter inside the function do not affect the original value.
Example: Call by Value with a Pointer to a Function

#include <stdio.h>

// Function that adds two numbers (Call by Value)


int add(int a, int b) {
return a + b;
}

// Function pointer declaration


int (*func_ptr)(int, int);

int main() {
// Assign the address of the 'add' function to 'func_ptr'
func_ptr = &add;

int x = 10, y = 20;

// Calling the function using the pointer (Call by Value)


int result = func_ptr(x, y);

printf("Result (Call by Value): %d\n", result); // Output: 30

return 0;
}

In this example, the values of x and y are passed to the function pointer func_ptr, which points
to the add function. The values are passed by value, meaning the original values of x and y are
not modified.

2. Pointer to Function with Call by Reference

In call by reference, the function receives a reference (pointer) to the variable, so any changes
made to the parameter inside the function will affect the original variable.

Example: Call by Reference with a Pointer to a Function

#include <stdio.h>

// Function to swap two numbers (Call by Reference)


void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}

// Function pointer declaration


void (*func_ptr)(int *, int *);

int main() {
// Assign the address of the 'swap' function to 'func_ptr'
func_ptr = &swap;
int x = 10, y = 20;

// Calling the function using the pointer (Call by Reference)


func_ptr(&x, &y);

printf("After Swap (Call by Reference): x = %d, y = %d\n", x, y); // Output: x = 20, y = 10

return 0;
}

In this example, the addresses of x and y are passed to the function pointer func_ptr, which
points to the swap function. Since the function operates on the addresses, it modifies the
original variables x and y.

Key Differences:

• Call by Value: The function receives copies of the arguments. Modifications inside the
function do not affect the original variables.
• Call by Reference: The function receives pointers to the arguments. Modifications
inside the function affect the original variables.

4.16 Pointers and Arrays in C

In C programming, the concepts of arrays and pointers have a very important role. There is
also a close association between the two. In this chapter, we will explain in detail the
relationship between arrays and pointers in C programming.

Arrays in C
An array in C is a homogenous collection of elements of a single data type stored in a
continuous block of memory. The size of an array is an integer inside square brackets, put in
front of the name of the array.

Declaring an Array
To declare an array, the following syntax is used

data_type arr_name[size];
Each element in the array is identified by a unique incrementing index, starting from "0". An
array can be declared and initialized in different ways.
You can declare an array and then initialize it later in the code, as and when required. For
example

int arr[5];
...
...
a[0] = 1;
a[1] = 2;
...
...
You can also declare and initialize an array at the same time. The values to be stored are put as
a comma separated list inside curly brackets.

int a[5] = {1, 2, 3, 4, 5};


Note: When an array is initialized at the time of declaration, mentioning its size is optional, as
the compiler automatically computes the size. Hence, the following statement is also valid −

int a[] = {1, 2, 3, 4, 5};


Example: Lower Bound and Upper Bound of an Array
All the elements in an array have a positional index, starting from "0". The lower bound of the
array is always "0", whereas the upper bound is "size − 1". We can use this property to traverse,
assign, or read inputs into the array subscripts with a loop.

#include <stdio.h>

int main()
{

int a[5], i;

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


scanf("%d", &a[i]);
}

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


printf("a[%d] = %d\n",i, a[i]);
}

return 0;
}
Output
a[0] = 712952649
a[1] = 32765
a[2] = 100
a[3] = 0
a[4] = 4096
Pointers in C
A pointer is a variable that stores the address of another variable. In C, the symbol (&) is used
as the address-of operator. The value returned by this operator is assigned to a pointer.

To declare a variable as a pointer, you need to put an asterisk (*) before the name. Also, the
type of pointer variable must be the same as the type of the variable whose address it stores.
In this code snippet, "b" is an integer pointer that stores the address of an integer variable "a"

int a = 5;
int *b = &a;
In case of an array, you can assign the address of its 0th element to the pointer.

int arr[] = {1, 2, 3, 4, 5};


int *b = &arr[0];
In C, the name of the array itself resolves to the address of its 0th element. It means, in the
above case, we can use "arr" as equivalent to "&[0]":

int *b = arr;
Example: Increment Operator with Pointer
Unlike a normal numeric variable (where the increment operator "++" increments its value by
1), the increment operator used with a pointer increases its value by the sizeof its data type.

Hence, an int pointer, when incremented, increases by 4.

#include <stdio.h>

int main(){

int a = 5;
int *b = &a;

printf("Address of a: %p\n", b);


b++;
printf("After increment, Address of a: %p\n", b);

return 0;
}
Output
Run the code and check its output −

Address of a: 6422036
After increment, Address of a: 6422040
The Dereference Operator in C
In C, the "*" symbol is used as the dereference operator. It returns the value stored at the address
to which the pointer points.

Hence, the following statement returns "5", which is the value stored in the variable "a", the
variable that "b" points to.

int a = 5;
int *b = &a;
printf("value of a: %d\n", *b);
Note: In case of a char pointer, it will increment by 1; in case of a double pointer, it will
increment by 8; and in case of a struct type, it increments by the sizeof value of that struct type.

Example: Traversing an Array Using a Pointer


We can use this property of the pointer to traverse the array element with the help of a pointer.

#include <stdio.h>

int main(){

int arr[5] = {1, 2, 3, 4, 5};


int *b = arr;

printf("Address of a[0]: %d value at a[0] : %d\n",b, *b);

b++;
printf("Address of a[1]: %d value at a[1] : %d\n", b, *b);

b++;
printf("Address of a[2]: %d value at a[2] : %d\n", b, *b);

b++;
printf("Address of a[3]: %d value at a[3] : %d\n", b, *b);

b++;
printf("Address of a[4]: %d value at a[4] : %d\n", b, *b);

return 0;
}
Output

address of a[0]: 6422016 value at a[0] : 1


address of a[1]: 6422020 value at a[1] : 2
address of a[2]: 6422024 value at a[2] : 3
address of a[3]: 6422028 value at a[3] : 4
address of a[4]: 6422032 value at a[4] : 5

Passing String Pointers to a Function


Let us have a look at another example, where we will pass string pointers to a function.

Example

In this program, two strings are passed to the compare() function. A string in C is an array of
char data type. We use the strlen() function to find the length of the string.

#include <stdio.h>
int compare(char *, char *);
int main()
{
char str1[] = "BAT";
char str2[] = "BALL";
int ret = compare(str1, str2);
return 0;
}
int compare (char *x, char *y)
{
int val;
if (strlen(x) > strlen(y)){
printf("Length of Str1 is greater than or equal to the length of Str2");
}
Else
{
printf("Length of Str1 is less than the length of Str2");
}
}
Output
When you run this code, it will produce the following output −

Length of Str1 is less than the length of Str2

4.17 Pointer to Structure

If you have defined a derived data type using the keyword struct, then you can declare a
variable of this type. Hence, you can also declare a pointer variable to store its address. A
pointer to struct is thus a variable that refers to a struct variable.

Define a new derived data type using the "struct" keyword

Syntax: Defining and Declaring a Structure

struct name
{
member1;
member2;
.
.
};

Then declare a variable of this derived data type as following


struct type var;

You can then declare a pointer variable and store the address of var. To declare a variable as a
pointer, it must be prefixed by "*"; and to obtain the address of a variable, we use the "&"
operator.

struct type *ptr = &var;

Accessing the Elements of a Structure

To access the elements of a structure with pointer, we use a special operator called the
indirection operator (→) .

Here, we define a user-defined struct type called book. We declare a book variable and a
pointer.
struct book

char title[10];

double price;

int pages;

};

struct book b1 = {"Learn C", 675.50, 325},

struct book *strptr;

To store the address, use the & operator.

strptr = &b1;

Using the Indirection Operator

In C programming, we use the indirection operator ("→") with struct pointers. It is also called
the "struct dereference operator". It helps to access the elements of a struct variable to which
the pointer references to.

To access an individual element in a struct, the indirection operator is used as follows

strptr -> title;

strptr -> price;

strptr -> pages;

The struct pointer uses the indirection operator or the dereference operator to fetch the values
of the struct elements of a struct variable. The dot operator (".") is used to fetch the values with
reference to the struct variable. Hence,

b1.title is the same as strpr -> title

b1.price is the same as strptr -> price

b1.pages is the same as strptr -> pages

Example: Pointers to Structures


The following program shows the usage of pointers to structures. In this example, "strptr" is a
pointer to the variable "struct book b1". Hence, "strrptr → title" returns the title, similar to
"b1.title" does.

Open Compiler

#include <stdio.h>

#include <string.h>

struct book{

char title[10];

double price;

int pages;

};

int main(){

struct book b1 = {"Learn C", 675.50, 325};

struct book *strptr;

strptr = &b1;

printf("Title: %s\n", strptr -> title);

printf("Price: %lf\n", strptr -> price);

printf("No of Pages: %d\n", strptr -> pages);

return 0;

Output
Title: Learn C

Price: 675.500000

No of Pages: 325

4.18 Dymamic Memory Allocation

Since C is a structured language, it has some fixed rules for programming. One of them
includes changing the size of an array. An array is a collection of items stored at contiguous
memory locations.

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.
This procedure is referred to as Dynamic Memory Allocation in C.
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.
They are:
1. malloc()
2. calloc()
3. free()
4. realloc()
Let’s look at each of them in greater detail.
C 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.

Syntax of malloc() in C

ptr = (cast-type*) malloc(byte-size)

Example:

Ptr=(int*) malloc(100*szeof(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.

Example of malloc() in C

#include <stdio.h>

#include <stdlib.h>

int main()

// This pointer will hold the

// base address of the block created

int* ptr;
int n, i;

// Get the number of elements for the array

printf("Enter number of elements:");

scanf("%d",&n);

printf("Entered number of elements: %d\n", n);

// Dynamically allocate memory using malloc()

ptr = (int*)malloc(n * sizeof(int));

// Check if the memory has been successfully

// allocated by malloc or not

if (ptr == NULL) {

printf("Memory not allocated.\n");

exit(0);

else {

// Memory has been successfully allocated

printf("Memory successfully allocated using malloc.\n");

// Get the elements of the array

for (i = 0; i < n; ++i) {

ptr[i] = i + 1;

// Print the elements of the array

printf("The elements of the array are: ");


for (i = 0; i < n; ++i) {

printf("%d, ", ptr[i]);

return 0;

Output

Enter number of elements: 5

Memory successfully allocated using malloc.

The elements of the array are: 1, 2, 3, 4, 5,

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.
If space is insufficient, allocation fails and returns a NULL pointer.
Example of calloc() in C

#include <stdio.h>
#include <stdlib.h>
int main()
{
// This pointer will hold the
// base address of the block created
int* ptr;
int n, i;
// Get the number of elements for the array
n = 5;
printf("Enter number of elements: %d\n", n);
// Dynamically allocate memory using calloc()
ptr = (int*)calloc(n, sizeof(int));
// Check if the memory has been successfully
// allocated by calloc or not
if (ptr == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {
// Memory has been successfully allocated
printf("Memory successfully allocated using calloc.\n");
// Get the elements of the array
for (i = 0; i < n; ++i) {
ptr[i] = i + 1;
}
// Print the elements of the array
printf("The elements of the array are: ");
for (i = 0; i < n; ++i) {
printf("%d, ", ptr[i]);
}
}

return 0;
}
Output
Enter number of elements: 5
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,
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);
Example:
#include <stdio.h>
#include <stdlib.h>

int main()
{

// This pointer will hold the


// base address of the block created
int *ptr, *ptr1;
int n, i;

// Get the number of elements for the array


n = 5;
printf("Enter number of elements: %d\n", n);

// Dynamically allocate memory using malloc()


ptr = (int*)malloc(n * sizeof(int));

// Dynamically allocate memory using calloc()


ptr1 = (int*)calloc(n, sizeof(int));
// Check if the memory has been successfully
// allocated by malloc or not
if (ptr == NULL || ptr1 == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {

// Memory has been successfully allocated


printf("Memory successfully allocated using malloc.\n");

// Free the memory


free(ptr);
printf("Malloc Memory successfully freed.\n");

// Memory has been successfully allocated


printf("\nMemory successfully allocated using calloc.\n");

// Free the memory


free(ptr1);
printf("Calloc Memory successfully freed.\n");
}

return 0;
}

Output
Enter number of elements: 5
Memory successfully allocated using malloc.
Malloc Memory successfully freed.
Memory successfully allocated using calloc.
Calloc Memory successfully freed.
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'.

Example
#include <stdio.h>
#include <stdlib.h>

int main()
{

// This pointer will hold the


// base address of the block created
int* ptr;
int n, i;
// Get the number of elements for the array
n = 5;
printf("Enter number of elements: %d\n", n);

// Dynamically allocate memory using calloc()


ptr = (int*)calloc(n, sizeof(int));

// Check if the memory has been successfully


// allocated by malloc or not
if (ptr == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {

// Memory has been successfully allocated


printf("Memory successfully allocated using calloc.\n");

// Get the elements of the array


for (i = 0; i < n; ++i) {
ptr[i] = i + 1;
}

// Print the elements of the array


printf("The elements of the array are: ");
for (i = 0; i < n; ++i) {
printf("%d, ", ptr[i]);
}

// Get the new size for the array


n = 10;
printf("\n\nEnter the new size of the array: %d\n", n);

// Dynamically re-allocate memory using realloc()


ptr = (int*)realloc(ptr, n * sizeof(int));

// Memory has been successfully allocated


printf("Memory successfully re-allocated using realloc.\n");

// Get the new elements of the array


for (i = 5; i < n; ++i) {
ptr[i] = i + 1;
}

// Print the elements of the array


printf("The elements of the array are: ");
for (i = 0; i < n; ++i) {
printf("%d, ", ptr[i]);
}

free(ptr);
}
return 0;
}
Output
Enter number of elements: 5
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,

Enter the new size of the array: 10


Memory successfully re-allocated using realloc.
The elements of the array are: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
______________
PART-A

PART-A

1. What is the need for Structure in C?


2. What is Structure? Write its syntax and example.
3. Write the differences between Structure and Union.
4. Distinguish between Array and Structure.
5. How will you access the members of structure?
6. What is Array of Structure? Give an example.
7. Define Nested structure with an example.
8. How will you pass structure as an argument to a function?
9. What is type defining structure? Give an example.
10. Define union. Write its syntax and example.
11. What is Pointer with example?
12. How to declare the Pointer variable? Give an example.
13. List the different type of Pointer.
14. How to in initialize Pointer variable in C?
15. what is dereferencing operator in pointer?
16. What is mean by Pointer to Pointer in C?
17. What is Double Pointer in C?
18. How to use a pointer to access a variable?
19. How do you access pointer variables in structure?
20. what is Pointer arithmetic?
21. Which arithmetic operations are valid on pointers in C?
22. What is the Pointer * and & in C?
23. What is the application of Pointer in C?
24. What do you mean by dynamic memory allocation?
25. What is calloc and malloc?
26. What s difference between dynamic and static memory allocation?

PART-B
1. Explain the concept of Structure with relevant example program.
2. Describe Array of Structures with suitable example.
3. Define a structure called Student that contains the name, regno, marks of five subjects
and percentage. Write a program to read the details of name, regno and marks of five
subjects for 30 students, calculate the percentage and display the name, regno, marks
of the subjects and percentage of each student. (Use Array of Structure concept)
4. Write a C program to define a Structure ‘Employee’ that reads and display the details
such as empno, empname, department name and salary. The structure has to store 100
employees in an organization (Use Array of Structure concept)
5. Explain in detail about Structure within Structure (Nested Structure) with relevant
example program.
6. Discuss Array within Structure with suitable example.
7. Explain how to pass structure as arguments to function with example.
8. Describe the concept of Type defining structures with an example.
9. Explain about Pointer in C? With Suitable example.
10. Explain about arithmetic Pointer in C with suitable example.
11. Illustrate about following term
a. Double Pointer
b. Dereferencing operator in C
12. Write a program to access Pointer variable in structure.
13. How to access array element using Pointer in C.
14. Write a program for accessing structure member using Pointer?
15. Explain about Dynamic Memory Allocation in C.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy