C-Array-Pointer-equations

Rule

Description

Example

Rule 1

A pointer can hold the address of a static global variable

#include <stdio.h>

static double a = 5.12312312;

int main()
{
    double *ptr;

    ptr = &a;

    *ptr = 7.3453; // a is now changed to 7.345300

    printf("%f\n", a); // prints 7.345300

    return 0;
}

Rule 2

A pointer can hold the address of a non-static global variable

#include <stdio.h>

char a = 'A';

int main()
{
    char *ptr;

    ptr = &a;

    *ptr = 'G'; // a is now changed to 'G'

    printf("%c\n", a); // prints G

    return 0;
}

Rule 3

A pointer can hold the address of a static local variable

#include <stdio.h>

int main()
{
    static int a = 500;
    int *ptr;

    ptr = &a;
    *ptr = 1000; // a is now changed to 1000

    printf("%d\n", a); // prints 1000

    return 0;
}

Rule 4

A pointer can hold the address of a local variable stored on stack

#include <stdio.h>

int main()
{
    int a = 500;
    int *ptr;

    ptr = &a;
    *ptr = 1000; // a is now changed to 1000

    printf("%d\n", a); // prints 1000

    return 0;
}

Rule 5

A pointer can hold the address of a memory block allocated dynamically by malloc, calloc, realloc

#include <stdio.h>

int main()
{
    int *ptr;

    ptr = malloc(sizeof(int));
    // ptr now points to a single block of integer of 4 bytes

    *ptr = 100;

    printf("%d\n", *ptr); // prints 100

    free(ptr); // free the memory allocated using malloc

    return 0;
}
#include <stdio.h>
#include <stdlib.h>

void display_1(int *ptr)
{   
    int i;

    for(i = 0; i < 5; i++)
        printf("%d\n", ptr[i]);
}

void display_2(int *ptr)
{
    int i;

    for(i = 0; i < 5; i++, ptr++)
        printf("%d\n", *ptr);
}

void display_3(int *ptr)
{
    int i;

    for(i = 0; i < 5; i++, ptr++)
        printf("%d\n", ptr[0]);
}

int main()
{
    int *ptr;

    ptr = malloc(sizeof(int) * 5);
    // ptr now points to starting address of a 5 blocks of integers

    ptr[0] = 0;
    ptr[1] = 100;
    ptr[2] = 200;
    ptr[3] = 300;
    ptr[4] = 400;

    display_1(ptr);
    display_2(ptr);
    display_3(ptr);

    free(ptr); // free the memory allocated using malloc

    return 0;
}

Rule 6

More than one pointer can point to same memory location

#include <stdio.h>

int main()
{
    int a = 5;
    int *p, *q, *r;

    p = &a;
    q = &a;
    r = p;

    *p = 10;
    printf("%d\n", a); // a is now 10

    *q = 20;
    printf("%d\n", a); // a is now 20

    *r = 30;
    printf("%d\n", a); // a is now 30

    return 0;
}

Rule 7

[ ] and * can be interchanged in arrays (Single dimension, Double dimension, etc., )
  • Rule defined for int x[], char x[], float x[], double x[], struct ABC x[], union ABC x[]

#include <stdio.h>

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

int main()
{
    x[2] = 10;
    *(x + 2) = 100;

    printf("%d\n", x[2]);

    return 0;
}

Rule 8

[ ] and * can be interchanged in pointers (Single pointer, Double pointer, etc., )
  • Rule defined for int *x, char *x, float *x, double *x, struct ABC *x, union ABC *x

#include <stdio.h>

int x[5] = {1, 2, 3 ,4, 5};
int *ptr = x;

int main()
{
    x[2] = 10;
    *(x + 2) = 100;
    ptr[3] = 200;

    printf("%d\n", x[2]); // --> prints 100
    printf("%d\n", x[3]); // --> prints 200
    printf("%d\n", ptr[3]); // --> prints 200

    return 0;
}

Rule 9

*ptr is always equal to ptr[0]
  • Where ptr is pointing to simple variable, OR

  • Where ptr is pointing to any element in an array, OR

  • Where ptr is pointing to any element in a contiguous memory alloacted using malloc,realloc

  • Rule defined for int *x, char *x, float *x, double *x, struct ABC *x, union ABC *x

#include <stdio.h>

int x[5] = {1, 2, 3 ,4, 5};
int *ptr = x;

int main()
{
    ptr++; // ptr now points to x[1];
    *ptr = 100; // x[1] is now 100
    ptr[0] = 100; // x[1] is now 100
    ptr = ptr + 2; // ptr now points to x[3];
    *ptr = 300; // x[3] is now 300
    ptr[0] = 300; // x[3] is now 300
    x[4] = 400; // x[4] is now 400
    *(x + 4) = 400; // x[4] is now 400

    printf("%d\n", x[1]); // --> prints 100
    printf("%d\n", x[3]); // --> prints 300
    printf("%d\n", x[4]); // --> prints 400

    return 0;
}

Rule 10

Pointers can be incremented or decremented relative to current position in a memory block

#include <stdio.h>

int x[5] = {1, 2, 3 ,4, 5};
int *ptr = x;

int main()
{
    ptr++; // ptr now points to x[1];
    *ptr = 100; // x[1] is now 100
    ptr[0] = 100; // x[1] is now 100
    ptr = ptr + 2; // ptr now points to x[3];
    *ptr = 300; // x[3] is now 300
    ptr[0] = 300; // x[3] is now 300
    ptr--; // ptr now points to x[2]
    *ptr = 200;
    ptr[0] = 200;
    x[4] = 400; // x[4] is now 400
    *(x + 4) = 400; // x[4] is now 400

    printf("%d\n", x[1]); // --> prints 100
    printf("%d\n", x[1]); // --> prints 200
    printf("%d\n", x[3]); // --> prints 300
    printf("%d\n", x[4]); // --> prints 400

    return 0;
}

Rule 11

Pointers can be indexed with positive or negative index relative to current position in a memory block

#include <stdio.h>

int x[5] = {1, 2, 3 ,4, 5};
int *ptr = x;

int main()
{
    ptr++; // ptr now points to x[1];
    *ptr = 100; // x[1] is now 100
    ptr[0] = 100; // x[1] is now 100
    ptr = ptr + 2; // ptr now points to x[3];
    *ptr = 300; // x[3] is now 300
    ptr[0] = 300; // x[3] is now 300
    ptr[-1] = 200; // x[2] is now 200
    ptr[1] = 400; // x[4] is now 400

    printf("%d\n", x[1]); // --> prints 100
    printf("%d\n", x[1]); // --> prints 200
    printf("%d\n", x[3]); // --> prints 300
    printf("%d\n", x[4]); // --> prints 400

    return 0;
}

Rule 12

  • & and * operators can be exchanged across LHS and RHS similar to an equation

  • If * moves from LHS to RHS it becomes &
    • *p = a; p = &a;

  • If & moves from RHS to LHS it becomes *
    • p = &a; *p = a;

Rule 13

Subtraction of two pointers is allowed, when two pointers point to two blocks in contiguous memory

Rule 14

Addition of two pointers is NOT allowed

Rule 15

Multiplication of two pointers is NOT allowed

Rule 16

Division of two pointers is NOT allowed

Rule 17

& and * on same side of the equation, cancel each other

Rule 18

* on LHS and * on RHS can cancel each other to get address

Rule 19

Single dimension simple array:
  • Rule defined for int x[], char x[], float x[], double x[]

  • Element access will have at the most * or [ ]

  • Single pointer is used to store the address of single dimension array

#include <stdio.h>

void display_1(int arr[], int size)
{
    int i;

    printf("Iterate using array index\n");
    for(i = 0; i < size; i++)
        printf("%d\n", arr[i]);
}

void display_2(int *arr, int size)
{
    int i;

    printf("Iterate array as pointer\n");
    for(i = 0; i < size; i++, arr++)
        printf("%d\n", *arr);
}

void display_3(int *arr, int size)
{
    int i;

    printf("Iterate using array index\n");
    for(i = 0; i < size; i++, arr++)
        printf("%d\n", arr[0]);
}

int main()
{
    int a[5] = {100, 200, 300, 400, 500};

    display_1(a, 5);
    display_2(&a[0], 5);
    display_3(a + 2, 3);

    return 0;
}

Rule 20

Double dimension simple array:
  • Rule defined for int x[][], char x[][], float x[][], double x[][]

  • Element access will have at the most ** or [ ][ ] or *[ ]

  • Pointer to an array is used to store the address of double dimension array

#include<stdio.h>

int main()
{
    int arr[3][4] = {
                        {1,2,3,4},
                        {5,6,7,8},
                        {1,6,7,4}
                    };
    int i, j;
    int (*p)[4];

    printf("Iterate array using arr and [] notation\n");
    for(i = 0; i < 3; i++)
    {
        for(j = 0; j < 4; j++)
        {
             printf("arr[%d][%d]=%d\n", i, j, arr[i][j] );
        }
        printf("\n\n");
    }

    printf("Iterate array using arr and * notation\n");
    for(i = 0; i < 3; i++)
    {
        for(j = 0; j < 4; j++)
        {
             printf("arr[%d][%d]=%d\n", i, j, *( *(arr + i) + j) );
        }
        printf("\n\n");
    }

    p = arr;

    printf("Iterate array using pointer to an array\n");
    for(i = 0; i < 3; i++)
    {
        for(j = 0; j < 4; j++)
        {
            printf("arr[%d][%d]=%d\n", i, j, *( *(p + i) + j) );
        }
        printf("\n\n");
    }

    return 0;
}

Rule 21

Three dimension simple array:
  • Rule defined for int x[][], char x[][], float x[][], double x[][]

  • Element access will have at the most ** or [ ][ ] or *[ ]

#include<stdio.h>

int main()
{
	int A[2][3][4] =
	{
		{
			{1,2,3,4},
			{5,6,7,8},
			{9,10,11,12},
		},
		{
			{13,14,15,16},
			{17,18,19,20},
			{21,22,23,24},
		}
	};

	int (*p)[3][4] = A;
	int i, j, k;

	printf("Iterate using Array index\n");
	for (i = 0; i < 2; i++) {
		for (j =0; j < 3; j++) {
			for (k =0; k < 4; k++)
					printf("%d\t", A[i][j][k]);
			printf("\n");
		}
	}

	printf("Iterate using pointer to array\n");
	for (i = 0; i < 2; i++) { 
		for (j = 0; j < 3; j++) {
			for (k = 0; k < 4; k++)
					printf("%d\t", *(*(*(p +i) + j) +k));
		printf("\n");
		} 
	}

	printf("\n");
	return 0;
}

Rule 22

Simple Single pointer:
  • Rule defined for int *x, char *x, float *x, double *x

  • Element access will have at the most * or [ ]

  • Single pointer can hold the address of a simple variable

  • Single pointer can hold the address of a simple single dimension array

Rule 23

Simple Double pointer:
  • Rule defined for int **x, char **x, float **x, double **x

  • Element access will have at the most ** or [ ][ ] or *[ ]

  • P equals &X

  • Q equals &P

  • *P equals P[0] equals X

  • *Q equals Q[0] equals P

  • *Q equals Q[0] equals &X

  • **Q equals Q[0][0] equals *Q[0] equals X

#include <stdio.h>

int main()
{
    int X = 5;
    int *P;
    int **Q;

    P = &X;
    Q = &P;

    Q[0][0] = 100;
    printf("%d\n", X); // prints 100

    *Q[0] = 200;
    printf("%d\n", X); // prints 200

    **Q = 300;
    printf("%d\n", X); // prints 300

    return 0;
}

Rule 24

Simple Triple pointer:
  • Rule defined for int ***x, char ***x, float ***x, double***x

  • Element access will have at the most *** or **[] or *[ ][ ] or [ ][ ][ ]

  • P equals &X

  • Q equals &P

  • R equals &Q

  • *P equals P[0] equals X

  • *Q equals Q[0] equals P

  • *Q equals Q[0] equals &X

  • **Q equals Q[0][0] equals *Q[0] equals X

  • *R equals R[0] equals Q

  • *R equals R[0] equals &P

  • **R equals R[0][0] equals *R[0] equals P

  • **R equals R[0][0] equals *R[0] equals &X

  • ***R equals R[0][0][0] equals **R[0] equals *R[0][0] equals X

#include <stdio.h>

int main()
{
    int X = 5;
    int *P;
    int **Q;
    int ***R;

    P = &X;
    Q = &P;
    R = &Q;

    Q[0][0] = 100;
    printf("%d\n", X); // prints 100

    *Q[0] = 200;
    printf("%d\n", X); // prints 200

    **Q = 300;
    printf("%d\n", X); // prints 300

    R[0][0][0] = 1000;
    printf("%d\n", X); // prints 1000

    *R[0][0] = 2000;
    printf("%d\n", X); // prints 2000

    **R[0] = 3000;
    printf("%d\n", X); // prints 3000

    ***R = 4000;
    printf("%d\n", X); // prints 4000

    return 0;
}

Rule 25

Single dimension structure array:
  • Element access will have at the most * or [ ] or ->

  • Single pointer is used to store the address of single dimension array

  • LHS of .(dot operator) must evaluate to a structure instance

  • RHS of .(dot operator) must evaluate to a structure member

  • LHS of ->(structure dereference operator) must evaluate to a structure instance

  • RHS of ->(structure dereference operator) must evaluate to a structure member

#include <stdio.h>
struct abc {
	int x;
} a[5];

int main()
{
	a[2].x = 5;
	(a + 2)->x = 10;
	(*(a + 2)).x = 20;
	return 0;
}

Rule 26

Double dimension structure array:
  • Element access will have at the most ** or [ ][ ] or *-> or *[ ] or [ ]->

#include <stdio.h>

struct abc {
	int x;
} b[3][4];

int main()
{
	b[1][2].x = 5;
	(*(b[1] + 2)).x = 5;
	(b[1] + 2)->x = 5;

	(*(b + 1))[2].x = 5;
	((*(b + 1)) + 2)->x = 5;
	(*((*(b + 1)) + 2)).x = 5;

	return 0;
}

Rule 27

Three dimension structure array:
  • Element access will have at the most *** or [ ][ ][ ], OR

  • Element access will have at the most *[ ][ ] or **[ ], OR

  • Element access will have at the most [ ][ ]-> or **-> or *[ ]->

#include <stdio.h>

struct abc {
	int x;
} c[2][3][4];

int main()
{
	c[1][2][3].x = 100;
	(c[1][2] + 3)->x = 100;
	(*(c[1][2] + 3)).x = 100;

	( (*(c[1] + 2)) + 3)->x = 100;
	( (*( (*(c + 1)) + 2)) + 3)->x = 100;
	(*( (*(c + 1)) + 2))[3].x = 100;
	(* ( (*( (*(c + 1)) + 2)) + 3)).x = 100;
	return 0;
}

Rule 28

Structure Single pointer:
  • Rule defined for “struct ABC X; struct ABC *Q;”

  • Element access will have at the most * or [ ] or ->

  • Single pointer can hold the address of a structure instance variable

  • Single pointer can hold the address of a single dimension struture array

  • LHS of .(dot operator) must evaluate to a structure instance

  • RHS of .(dot operator) must evaluate to a structure member

  • LHS of ->(structure dereference operator) must evaluate to a structure instance

  • RHS of ->(structure dereference operator) must evaluate to a structure member

  • P equals &X

  • (*P). equals P-> equals P[0] equals X

  • (*Q). equals Q-> equals Q[ ] equals A[]

#include <stdio.h>

struct abc {
    int x;
};

struct abc X; struct abc *P = &X;
struct abc A[5]; struct abc *Q = A;

int main()
{
    X.x = 5;
    P[0].x = 100;
    P->x = 100;
    (*P).x = 100;

    A[2].x = 5;
    (A + 2)->x = 10;
    (*(A + 2)).x = 20;

    Q[2].x = 200;// changes A[2].x to 200
    (Q + 2)->x = 200;
    (*(Q + 2)).x = 200;

    printf("%d\n", X.x); //prints 100
    printf("%d\n", A[2].x); //prints 200

    return 0;
}

Rule 29

Structure Double pointer:
  • Rule defined for “struct ABC **Q;”

  • Element access will have at the most ** or [ ][ ] or *-> or *[ ] or [ ]->

  • LHS of .(dot operator) must evaluate to a structure instance

  • RHS of .(dot operator) must evaluate to a structure member

  • LHS of ->(structure dereference operator) must evaluate to a structure instance

  • RHS of ->(structure dereference operator) must evaluate to a structure member

  • P equals &X

  • Q equals &P

  • (*P). equals P-> equals P[0] equals X

  • *Q equals Q[0] equals P

  • *Q equals Q[0] equals &X

  • (*(*Q)). equals (*(Q[0])). equals Q[0][0]. equals X

  • Q[0]-> equals (*Q)-> equals X

#include <stdio.h>

struct abc {
    int x;
};

struct abc X;
struct abc *P = &X;
struct abc **Q = &P;

int main()
{
    X.x = 5;
    P[0].x = 100;
    P->x = 100;
    (*P).x = 100;
    printf("%d\n", X.x); //prints 100

    (*(*Q)).x = 200;
    printf("%d\n", X.x); //prints 200

    (*(Q[0])).x = 300;
    printf("%d\n", X.x); //prints 300

    Q[0][0].x = 400;
    printf("%d\n", X.x); //prints 400

    Q[0]->x = 500;
    printf("%d\n", X.x); //prints 500

    (*Q)->x = 600;
    printf("%d\n", X.x); //prints 600

    return 0;
}

Rule 30

Structure Triple pointer:
  • Rule defined for “struct ABC ***Q;”

  • Element access will have at the most *** or [ ][ ][ ], OR

  • Element access will have at the most *[ ][ ] or **[ ], OR

  • Element access will have at the most [ ][ ]-> or **-> or *[ ]->

  • LHS of .(dot operator) must evaluate to a structure instance

  • RHS of .(dot operator) must evaluate to a structure member

  • LHS of ->(structure dereference operator) must evaluate to a structure instance

  • RHS of ->(structure dereference operator) must evaluate to a structure member

  • P equals &X

  • Q equals &P

  • R equals &Q

  • (*P). equals P-> equals P[0] equals X

  • *Q equals Q[0] equals P

  • **Q equals Q[0][0] equals *Q[0] equals X

  • *R equals R[0] equals Q

  • *R equals R[0] equals &P

  • **R equals R[0][0] equals *R[0] equals P

  • **R equals R[0][0] equals *R[0] equals &X

  • (*(*(*R))). equals (*(*R))-> equals (*(*R))[0]. equals (*R)[0][0]. equals X

  • (*R)[0]-> equals R[0][0][0]. equals R[0][0]-> equals (*(R[0][0])). equals X

#include <stdio.h>

struct abc {
    int x;
};

struct abc X;
struct abc *P = &X;
struct abc **Q = &P;
struct abc ***R = &Q;

int main()
{
    X.x = 5;
    P[0].x = 100;
    P->x = 100;
    (*P).x = 100;
    printf("%d\n", X.x); //prints 100

    (*(*Q)).x = 200;
    printf("%d\n", X.x); //prints 200

    (*(Q[0])).x = 300;
    printf("%d\n", X.x); //prints 300

    Q[0][0].x = 400;
    printf("%d\n", X.x); //prints 400

    Q[0]->x = 500;
    printf("%d\n", X.x); //prints 500

    (*Q)->x = 600;
    printf("%d\n", X.x); //prints 600

    (*(*(*R))).x = 1000;
    printf("%d\n", X.x); //prints 1000

    (*(*R))->x = 2000;
    printf("%d\n", X.x); //prints 2000

    (*(*R))[0].x = 3000;
    printf("%d\n", X.x); //prints 3000

    (*R)[0][0].x = 4000;
    printf("%d\n", X.x); //prints 4000

    (*R)[0]->x = 5000;
    printf("%d\n", X.x); //prints 5000

    R[0][0][0].x = 6000;
    printf("%d\n", X.x); //prints 6000

    R[0][0]->x = 7000;
    printf("%d\n", X.x); //prints 7000

    (*(R[0][0])).x = 8000;
    printf("%d\n", X.x); //prints 8000

    return 0;
}