Users Online

· Guests Online: 4

· Members Online: 0

· Total Members: 185
· Newest Member: meenachowdary055

Forum Threads

Newest Threads
No Threads created
Hottest Threads
No Threads created

Latest Articles

FAQ: C Pointers

FAQ (Frequently Asked Questions) >C Pointers
01 What is the Concept of ‘word’ in C Programming02 What is Difference between a Pointer and an Ordinary Variable in C03 Can Datetype of a Value be determined by Examining its Bits in C?04 Can a Pointer in C Automatically Allocate Memory When it is Declared
05 How are Operators addressof (&) and asterisk (*) Work in Context with C Pointers06 What are Advantage of C Pointers with Modular Programming07 What is Indirection or Dereferencing a C Pointer and Does a Pointer have In-Built Property of Indirection08 What is an Uninitialized or Illegal Pointer in C Programming and What Happens on Indirection of an Illegal Pointer
09 Explain Pointer Constants in C with Examples10 What is the Concept of Pointer Compatibility in C Programming11 What is the Difference Between Various Pointers, const type * pname, type * const pname, and const type * const pname in C12 What is the Difference Between Pointer to Constant and Regular Pointer in C Language
13 Can we use addressof Operator ‘&’ to Determine Address of a Register Variable in C?14 Explain NULL Pointer in C with Examples15 Explain NULL Pointer Indirection in C Programming with Examples16 Which Pointer Expressions in C Programming are called as L-Values
17 Explain Pointer Operations in C with Examples18 Explain Double Pointer or Pointer-to-Pointer in C Programming with Examples
01 What is the Concept of ‘word’ in C Programming
This C Tutorial explains the Concept of ‘word’ in C Programming with Example(s).
A WORD in C Programming refers to ANSI Standard size of type int on Linux as 4 bytes or 32 bits. For example:

/* word_size.c -- Program displays size of a word on Linux Platform */
#include <stdio.h>
int main(void)
{
int int_size;

printf("Size of all integers is %d bytes\n", sizeof (int));
printf("Size of integer variable int_size is %d bytes\n",
sizeof int_size);
return 0;
}

However, word size on some systems is 2 bytes. Note however that bigger the size of type int, larger the range of values can be stored. For instance on Linux system, the range of integers is:

/* Minimum and maximum values a `signed int' can hold. */
Minimum Value -2147483648
Maximum Value 2147483647

/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
Maximum Value 4294967295U /* U stands as unsigned int */
Top
02 What is Difference between a Pointer and an Ordinary Variable in C
Question: What is the Difference between a Pointer and an Ordinary Variable in C?
Answer: Okey! We here unravel the differences between Ordinary and Pointer Variables we use in our C Programs as per programming requirements. What is a Variable? First, we should know this. A variable is some storage space set aside, as per type of variable, in memory by the compiler. Precisely, this storage is referred to as a Location in memory into which values are stored. Every Location in memory has an address and always has some value stored in it called as garbage. For example:

/*
* diff_ord_ptr_var.c -- program shows differences between ordinary
* and pointer variables
*/
#include <stdio.h>
#define PRICE 50 /* PRICE is a Symbolic Constant not a Variable */
int main(void)
{
char ch = 'A'; /* ch is character variable */
int ival = 100, count; /* ival is an integer variable */
float fval = 3.3; /* fval is a float variable */
double dval = 5.6; /* dval is a double variable */

char *cp = &ch; /* cp is a pointer to char */
char **dcp = &cp; /* dcp holds address of pointer-to-char */
int *ip = &ival, *ip1; /* ip is a pointer to integer */
float *fp = &fval; /* fp is a pointer to float */
double *dp = &dval; /* dp is a pointer to double */
50.23456; /* a float constant */

printf("\nValues of Ordinary Variables:\n\tcharacter ch is %10c,"
"\n\tinteger ival is %10d,\n\tfloat fval is\t %10f,"
"\n\tdouble dval is\t %10lf\n", ch, ival, fval, dval);

/* lf is printf specifier for type double */

printf("\nValues of Pointer Variables:\n\tcharacter pointer cp is %p,"
"\n\tinteger pointer ip is %p,\n\tfloat pointer fp is %15p,"
"\n\tdouble pointer dp is %p,\n\tpointer to pointer dcp is %p\n",
cp, ip, fp, dp, dcp);

printf("\nGarbage Values of Uninitialized:\n\tinteger \"count\" is %10d"
"\n\tpointer to int \"ip1\" is %10p\n\n", count, ip1);

/* %p is C99 printf specifier for addresses of memory */
return 0;
}

All the variables whether ordinary or pointer are alike in that when declared in the program allocated locations in memory by compiler. These locations or their addresses can’t be known in advance. That’s why we access locations by names of variables. Although, all variables, declared and not initialized in the program, have garbage values stored in them. But type of values stored differ for ordinary and pointer variables. Ordinary variables hold values of their type while pointers always hold addresses.

Observe the Output, below, when I run the above program on my Linux system:

Values of Ordinary Variables:
character ch is A,
integer ival is 100,
float fval is 3.300000,
double dval is 5.600000

Values of Pointer Variables:
character pointer cp is 0x7fff76c973df,
integer pointer ip is 0x7fff76c973d8,
float pointer fp is 0x7fff76c973d4,
double pointer dp is 0x7fff76c973c8,
pointer to pointer dcp is 0x7fff76c973c0

Garbage Values of Uninitialized:
integer "count" is 0
pointer to int "ip1" is 0xf0b2ff
Notice that pointer variable holds address; address of some variable or pointer variable while ordinary variables hold values of their respective types.
Top
03 Can Datetype of a Value be determined by Examining its Bits in C?
Question: Can datatype of a value be determined by Examining its Bits in C
Answer: Let’s first discuss how values either characters, integers, floats, doubles, character strings, addresses etc. are stored in computer memory. Computer Memory is Organised as continuous sequence of Binary Bits which are 1s or 0s for On and Off respectively. Because these bits serve no purpose in storing larger values when if used individually so these are combined into groups, each of 8 bits, called bytes. Further, compiler, on Linux system, allocates different amount of storage for each specific type of value. For instance, the smallest group being a Byte, comprising of 8-bits, suitable for type char, 4-Bytes group for type int etc. sizeof operator in C can be used to determine amount of storage space for different types including pointer variables. For example:

/*
* size_of_diff_types.c -- Program uses sizeof operator to determine size
* of different types
*/
#include <stdio.h>
int main(void)
{
char *cp, ch = 'A'; /* a character pointer */
int *ip, i = 23; /* an integer pointer */
float *fp, fl = 23.00; /* a float pointer */
double *dp, dbl = 23.00; /* a double pointer */

printf("\nSize of variable:\n\tcharacter ch is %d bytes\n\tinteger i is"
" %d bytes\n\tfloat fl is %d bytes\n\tdouble dbl is %d bytes\n",
sizeof(ch), sizeof(i), sizeof(fl), sizeof(dbl));

printf("\nSize of All:\n\tCharacters is %d bytes\n\tIntegers is %d "
"bytes\n\tFloats or Reals are %d bytes\n\tDoubles are %d bytes"
"\n", sizeof(char), sizeof(int), sizeof(float), sizeof(double));

printf("\nSize of A/An:\n\tCharacter Pointer is %d bytes\n\tInteger "
"Pointer is %d bytes\n\tFloat Pointer is %d bytes\n\tDouble "
"Pointer is %d bytes\n",
sizeof cp, sizeof ip, sizeof fp, sizeof dp);

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


When above program is run, output produced as follows:

Size of:
character ch is 1 bytes
integer i is 4 bytes
float fl is 4 bytes
double dbl is 8 bytes

Size of All:
Characters is 1 bytes
Integers is 4 bytes
Floats or Real are 4 bytes
Doubles are 8 bytes

Size of A/An:
Character Pointer is 8 bytes
Integer Pointer is 8 bytes
Float Pointer is 8 bytes
Double Pointer is 8 bytes
We observed different types take different amount of storage. However, notice that pointer of any type is allocated fixed 8 Bytes. Now, we try to recognise type of a value represented in binary, for example:

/* spaces between bytes are put for clarity */
11100111 01101100 11110000 00001111
With the above given sequence of bytes we dive into problem of correctly interpreting the value when its type isn’t known. Though, We can attempt this value as four characters or a single integer value or two short integers or some character string or address or some other value unless we know the type of value.
Top
04 Can a Pointer in C Automatically Allocate Memory When it is Declared
Question: Can a Pointer in C Automatically Allocate Memory When it is Declared
Answer: As we know Pointer is like any ordinary variable in that when it is declared, compiler allocates it a location in memory. Every location has an address and contents. The contents of a pointer is, however, address; address of some ordinary variable, other pointer or some function etc.. For example:

/*
* mem_alloc_to_ptr.c -- Program shows memory is allocated to ptr when
* declared
*/
#include <stdio.h>
int main(void)
{
int *ip, *ip1; /* pointer to integer declared */
int boys = 100; /* boys an int is initialized to 100 */
ip = &boys; /* ip holds the address of boys */

printf("\nAddress of pointer to integer \"ip\" in exp. \"ip = &boys\" "
"is %p\nand its contents, an address is %p\nand value it points"
" to is %d\n", &ip, ip, *ip);

printf("\npointer to integer \"ip1\" is declared but not initialized..."
"\n");
printf("Its Address in memory %p\nits contents, garbage address %p\n",
&ip1, ip1);
/* contents of ip1 is garbage address */

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

Above program when I run on my Linux system produces output as:

Address of pointer to integer "ip" in exp. "ip = &boys" is 0x7fffb7807088
and its contents, an address is 0x7fffb780707c
and value it points to is 100

pointer to integer "ip1" is declared but not initialized...
Its Address in memory 0x7fffb7807080
its contents, garbage address 0x7fffb7807170
Notice that even if a pointer is declared but not initialized, it holds Garbage address. Be sure not to dereference an uninitialized pointer!
Top
05 How are Operators addressof (&) and asterisk (*) Work in Context with C Pointers
Question: How are Operators addressof (&) and asterisk (*) Work in Context with C Pointers?
Answer: Well! Asterisk (*) is used as a binary operator when used in binary arithmetic meaning it then takes two operands on either side. When used as a Unary operator, it’s frequently used with pointers, pointer expressions and arrays. Address of operator (&) is generally used to fetch address of any operand as lvalue. lvalue means variable on the left side of assignment statement. Both these operators are frequently used with pointers. For example:

/*
* address_indirection1.c -- Program shows using of addressof (&) and
* indirection (*) operators with pointers
*/
#include <stdio.h>
int main(void)
{
int den = 11; /* den is initialized to value 11 */
int *ip = &den; /* ip is initialized address of integer den */

printf("In exp. \'ip = &den\',\nAddress of den is %p and\ncontents of "
"ip is %p\n", &den, ip);

return 0;
}
Output of the above program follows:

In exp. 'ip = &den',
Address of den is 0x7fffd3fec074 and
contents of ip is 0x7fffd3fec074

Notice that two addresses are same which means that pointer ip is also pointing to location where den is stored. Accessing the value of den by using asterisk (*) with pointer ip is called indirection or dereferencing the pointer. Let’s see how is this performed. For example:

/*
* address_indirection2.c -- Program shows using of addressof (&) and
* indirection (*) operators with pointers
*/
#include <stdio.h>
int main(void)
{
int den = 11; /* den is initialized to value 11 */
int *ip = &den; /* ip is initialized address of integer den */

printf("In exp. \'ip = &den\',\nAddress of den is %p and\nContents of "
"ip is %p\n", &den, ip);

printf("Value of den is %d\nAnd by performing indirection on pointer ip"
" is %d\n", den, *ip);/* '*' is an indirection operator in *ip */

return 0;
}
Output as,

In exp. 'ip = &den',
Address of den is 0x7fffe4b6eca4 and
Contents of ip is 0x7fffe4b6eca4
Value of den is 11
And by performing indirection on pointer ip is 11

Notice that value of den is 11 when accessed indirectly using asterisk (*) on pointer ip and so perhaps this process is called indirection or dereferencing the pointer. This is general with pointer to any type.
Top
06 What are Advantage of C Pointers with Modular Programming
This C Tutorial explains Advantage of C Pointers with Modular Programming with Example(s).
Let’s see an example of a C modular Program, in outline form, as:

/* c_mod_prog.c -- example of a C modular program */
#include <stdio.h>

/* function prototypes */
int shots();
int winner(int);
void display_winner_loser(int);

int main(void)
{
int x;
char y;

/* function calling */
shots();
winner(some_val);
display_winner_loser(some_val);

return 0;
}

int shots()
{
--- /* statements */
---

return win_shots;
}

int winner(int )
{
---
---

return no_winner;
}

void display_winner_loser(int )
{
---
---
}
Here in the above ex. program, observe that main() function has interfaces to the calling functions which are defined here, say in same file, however they could be defined in different files for their common access by other programs also. Now we consider importance of using pointers in modular C Programs. Let’s take some examples:

/* ptr_with_mod_c_prog1.c -- program shows modular c program */
#include <stdio.h>
void write_table(int);

int main(void)
{
int num;

printf("Wanna create Table of some number, enter number: ");
scanf("%d", &num);
write_table(num);

return 0;
}

void write_table(int copy) /* num copied into copy */
{
int i;

printf("\tTable of %d\n", copy);
for (i = 1; i <= 10; i++)
printf("%5d * %5d = %5d\n", copy, i, copy * i);

printf("\n");
}


Output of the program for number, say 5, is as:

Wanna create Table of some number, enter number: 5
Table of 5
5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25
5 * 6 = 30
5 * 7 = 35
5 * 8 = 40
5 * 9 = 45
5 * 10 = 50
Notice that value of num is copied into integer variable copy declared in the function write_table() and not the address of num variable. Here, We performed on the copy of value of num.

/*
* ptr_with_mod_c_prog.c -- program shows use of pointers in modular
* c program
*/
#include <stdio.h>
void find_char(char *, char);

int main(void)
{
char ch;
char str[] = "Hello, What are you doing these days?";

printf("User, which character u wanna find in string, enter character:"
" ");
ch = getchar();
find_char(str, ch); /* str, a string, is an address */

return 0;
}

void find_char(char *sp, char ch_cpy)
/* address of string str copied into sp, pointer to string */
{
char ch;

while ( (ch = *sp++) != '\0' && ch != ch_cpy)
;

if (ch_cpy == ch )
printf("Character \"%c\" is found!\n", ch_cpy);
else
printf("Character \"%c\" isn't found!\n", ch_cpy);
}


Output of the above program for characters, say q, r, is as:

User, which character u wanna find in string, enter character: q
Character "q" isn't found!

User, which character u wanna find in string, enter character: r
Character "r" is found!
Notice, however, here that we copied the address of string “str” into the pointer variable “sp” declared in the function find_char() and not the full string as it is. Using of pointer here saved lots of memory by copying the address of the first character of string “str” and not the full string irrespective of string length. Also, using pointer, we performed manipulations on the original string.
Top
07 What is Indirection or Dereferencing a C Pointer and Does a Pointer have In-Built Property of Indirection
Question: What is Indirection or Dereferencing a C Pointer and Does a Pointer have In-Built Property of Indirection?
Answer: A pointer variable is like an ordinary variable in that it is allocated location, by compiler, in memory when declared in the program. But unlike ordinary variable, a pointer holds address. Since memory is Byte addressable, every byte has address. Address itself is a constant value. Pointer holds addresses, meaning that what address does it hold, it points to that location in memory. For example:

/* add_to_ptr.c -- Program shows how pointer is assigned an address */
#include <stdio.h>

int main(void)
{
int balls = 100;
int *ip = &balls;
/* ip is declared and initialized with address of integer balls */

printf("Address of balls in exp. \"balls = 100\" is %p\nand Value of ip"
" in exp. \"*ip = &balls\" is %p\n", &balls, ip);

return 0;
}
Output of the above program is as follows:

Address of balls in exp. "balls = 100" is 0x7fffb6801824
and Value of ip in exp. "*ip = &balls" is 0x7fffb6801824

Observe here that both addresses are same. Value of pointer variable, which is address of integer balls, points to the location allocated to integer balls. But how to access the value at that location. In simple ways, integer ‘balls’ gives value at that location. For example:

/*
* deref_ptr.c -- Program shows how pointer is dereferenced or performed
* upon indirection
*/
#include <stdio.h>

int main(void)
{
int balls = 100;
int *ip = &balls;
/* "ip" is declared and initialized with address of integer balls */

printf("\nAddress of balls in exp. \"balls = 100\" is %p\nand Value of "
"ip in exp. \"*ip = &balls\" is %p\n\n", &balls, ip);

printf("Value of integer balls in exp. \"balls = 100\" is %d\n", balls);
printf("\nAccessing the value of balls indirectly using\ninteger "
"pointer ip in the exp. \"*ip = &balls\" is %d\n\n", *ip);

return 0;
}
Output of the above program is given below:

Address of balls in exp. "balls = 100" is 0x7ffffb7f6ce4
and Value of ip in exp. "*ip = &balls" is 0x7ffffb7f6ce4

Value of integer balls in exp. "balls = 100" is 100

Accessing the value of integer balls indirectly using
integer pointer ip in the exp. "*ip = &balls" is 100

Notice in the last printf() statement, we accessed the value of the integer balls indirectly using integer pointer ip. Since we have indirectly accessed balls, we perhaps call this Indirection or Dereferencing the pointer and unary operator (*) the Indirection operator. Pointer doesn’t have built-in property of Indirection. Preceding a pointer with unary (*) operator, like *ip; in the exp. *ip = &balls, is read as “go to the location pointed to by pointer, and access the value at that location”.

Also note that Indirection operator is one of very few operators which makes pointer expressions as ‘modifiable lvalues’ meaning that such expressions represent locations in memory and can be used on left side of assignment ‘=’ operator.
Top
08 What is an Uninitialized or Illegal Pointer in C Programming and What Happens on Indirection of an Illegal Pointer
Question: What is an Uninitialized or Illegal Pointer in C Language and What Happens on Indirection of an Illegal Pointer?
Answer: As we know, pointers, whether initialized or uninitialized, hold addresses. And we perform Indirection on pointers to access values, indirectly, at locations pointed to by them. For example:

/* access_initialized_pointer.c -- Program accessing initialized pointers */
#include <stdio.h>

int main(void)
{
int some = 20;
int *iptr = &some; /* iptr initialized with address of 'some' */

printf("\nAddress of integer \'some\' in exp. \'int some = 20\' is %p\n"
"and where \'iptr\' is pointing to, in exp. 'int *iptr = &some',"
" is\n%p\n", &some, iptr);

printf("\nLet's see what happens when we access initialized pointer "
"\'ptr\' in exp.\n\'int *iptr = &some\'\n");
printf("This gives Value %d of variable \'some\'\n\n", *iptr);

return 0;
}
Notice output of above program, when run on Linux machine,


Address of integer 'some' in exp. 'int some = 20' is 0x7fff34ff3454
and where 'iptr' is pointing to, in exp. 'int *iptr = &some', is
0x7fff34ff3454

Let's see what happens when we access initialized pointer 'ptr' in exp.
'int *iptr = &some'
This gives Value 20 of variable 'some'

Observe here that addresses of integer some and location where iptr is pointing to are same. And we performed Indirection on iptr to access the value at location pointed to by iptr, precisely the storage allocated to the integer some, to get the value of some which is 20.

Now, this time we turn to see an example with Uninitialized pointer, then performing Indirection on it and observe the output.

/*
* deref_uninitialized_ptr.c -- Program shows what happens when accessing
* uninitialized pointers
*/
#include <stdio.h>

int main(void)
{
int *ip1; /* ip1 declared pointer-to-integer, but not initialized */
int *ip2; /* ip2 declared pointer-to-integer, but not initialized */
char *cp; /* cp declared pointer-to-character, but not initialized */
float *fp; /* fp declared pointer-to-float, but not initialized */

printf("Default Address \'ip1\' holds as %p\n", ip1);
printf("Default Address \'ip2\' holds as %p\n", ip2);
printf("Default Address \'cp\' holds as %p\n", cp);
printf("Default Address \'fp\' holds as %p\n", fp);

printf("\nNow, see, what happens when we access uninitialized pointers"
"...\n");
printf("%d %d %c %f\n", *ip1, *ip2, *cp, *fp);

return 0;
}

Output:


Default Address 'ip1' holds as (nil)
Default Address 'ip2' holds as 0x7fff69f3bd80
Default Address 'cp' holds as 0x400420
Default Address 'fp' holds as (nil)

Now, see, what happens when we access uninitialized pointers...
Segmentation fault (core dumped)
So, what happened here, when we attempted to perform Indirection on uninitialized pointers? This caused an ERROR which ABORTED the program & displayed the massage “Segmentation fault”. What does this mean? Let’s try to know. Actually, when we compiled the program, compiler allocated the program a fixed storage in memory. This is called ‘Address Space’ of the program. But Uninitialized pointer, ip1 holds the default address, here nil fortunately, pointing nowhere in the memory, and when performed Indirection upon ip1, tried to access the location, in memory allocated to program, but not found and resulted in error causing Segmentation fault and aborted the program.

Generally, Uninitialized pointers hold default addresses which refer to locations beyond the scope of memory allocated to program by compiler. And hence, upon Indirection of such pointers Segmentation Fault occurs!
Top
09 Explain Pointer Constants in C with Examples
This C Tutorial explains Pointer Constants in C and Define their Purposes with Examples.
Every location, specifically every byte, in memory has an address. This address itself is a constant, so is a pointer constant. Remember that left side of assignment operator ‘=’ must be a Modifiable LValue meaning that expression on the left side must represent some location in memory. Let’s take few examples of pointer constants below:

/*
* ptr_const1.c -- Program shows if we can assign pointer constant some
* value
*/
#include <stdio.h>

int main(void)
{
int a = 50;

printf("Address of a is %p and value of a is %3d\n", &a, a);

&a = 100; /* &a is a pointer constant*/
printf("After &a = 100; Address of a is %p and value of a is %3d\n",
&a, a);

return 0;
}

Observe the output below:

ptr_const1.c: In function ‘main’:
ptr_const1.c:10:12: error: lvalue required as left operand of assignment
Notice the Type of ERROR occured! “lvalue required as left operand of assignment” because address of integer ‘a’ (&a) is a pointer constant, doesn’t point to any location/object in memory, so can’t be assigned with any value. O key, now, we turn next to see if we can convert pointer constant to modifiable lvalue? Consider the examples below:


/*
* ptr_const2.c -- Program shows if we can convert pointer constant to
* lvalue
*/
#include <stdio.h>

int main(void)
{
int a = 50;

printf("\t\tAddress of a is %p and value of a is %3d\n", &a, a);

*(&a) = 100; /* &a is a pointer constant*/
printf("After *(&a) = 100; Address of a is %p and value of a is %3d\n",
&a, a);

return 0;
}

Observe the output below:

Address of a is 0x7fff8bf1054c and value of a is 50
After *(&a) = 100; Address of a is 0x7fff8bf1054c and value of a is 100
Notice that Indirection operator (*) converted the pointer constant ‘&a’ to a modifiable lvalue. See how expression *(&a) is interpreted as, go to the address ‘&a’ and access the location/value over there.

/*
* ptr_const3.c -- Program shows how integer literal is type cast to
* pointer constant to modifiable lvalue
*/
#include <stdio.h>

int main(void)
{
printf("Program shows accessing the location by its address...\n");

*(int *)10000 = 100;
/* integer literal 10000 type cast to constant pointer (int *)10000 */
/*
* constant pointer (int *)10000 then converted to pointer-to-integer
* *(int *)10000
*/
/* accessing address 10000, assigning 100 there */

printf("After *(int *)10000 = 1000; value at address (int *)10000 is "
"%d\n", *(int *)10000);
return 0;
}


Output as:


Program shows accessing the location by its address...
Segmentation fault (core dumped)
But this time, fortunately, even after integer literal converted to modifiable lvalue, program aborted! Because we tried to access the address beyond the storage allocated to our program. What if we could have been successful in accessing that address i.e. *(int *)10000? Simple, that location should have had rewritten with new value 100 and older contents if any, address, some value, address to some function etc.. were lost. This might even cause system unstable.

Uses of Pointer Constants

Operating system uses Pointer Constants to interact with Hardware directly. For example, OS needs to communicate with input/output device controllers to start i/o operations and to obtain the results of prior operations. On most machines, interaction with input/output disk controllers is accomplished through reading and writing values at specific memory addresses. Instead of accessing the memory, however, these operations access the device controller interface, the addresses of which are known in advance.
Top
10 What is the Concept of Pointer Compatibility in C Programming
This C Tutorial Explains the Concept of Pointer Compatibility in C Programming with Examples.
The rules for assigning one pointer to another are tighter than the rules for numeric types. For example, you can assign an int value to a double variable without using a type conversion, but you can’t do the same for pointers to these two types. Let’s see a simple C program to exemplify this.

/*
* ptr_compatibility.c -- program illustrates concept of pointer
* compatibility
*/
#include <stdio.h>

int main(void)
{
int n = 5;
long double x;

int *pi = &n;
long double *pld = &x;

x = n; /* implicit type conversion */
pld = pi; /* compile-time error: assigning pointer-to-int to */
/* pointer-to-long-double */

return 0;
}
These restrictions extend to more complex types. Suppose we have the following declarations:

int *pi;
int (*pa)[3]; /* pointer to an array of 3 integers */
int ar1[2][3];
int ar2[3][2];
int **p2pi; /* a pointer-to-pointer-to-int, a double pointer */

/* Then we have the following: */
pi = &ar1[0][0]; /* both pointer-to-int */
pi = ar1[0]; /* both pointer-to-int */
pi = ar1; /* not valid because ar1 is an array of 3 integers */

pa = ar1; /* both pointer-to-int[3] */
pa = ar2; /* not valid because ar2 is an array of 2 integers */

p2pi = π /* both pointer-to-int * */
*p2pi = ar2[0]; /* both pointer-to-int */
p2pi = ar2; /* not valid */
Notice that the non valid assignments all involve two pointers that don’t point to the same type. For example, ‘pi’ points to a single int, but ‘ar1’ points to an array of three ints. Similarly, ‘pa’ points to an array of three ints, so it is compatible with ‘ar1’, but not with ‘ar2’, which points to an array of two ints.



The last two examples are somewhat tricky. The variable p2pi is a pointer-to-pointer-to-int, whereas ar2 is a pointer-to-array-of-two-ints (or, more concisely, pointer-to-int[2]). So p2pi and ar2 are of different types, and therefore we can’t assign ‘ar2’ to ‘p2pi’. But ‘*p2pi’ is of type pointer-to-int, making it compatible with ‘ar2[0]’. Recall that ‘ar2[0]’ is a pointer to its first element, ‘ar2[0][0]’, making ‘ar2[0]’ type pointer-to-int also.

In general, multiple indirection is tricky. For instance, consider the next snippet of code:

int *p1;
const int *p2;
const int **p2p;

p1 = p2; /* not valid -- assigning const to non-const */
p2 = p1; /* valid -- assigning non-const to const */

p2p = &p1; /* not valid -- assigning non-const to const */
As we have seen earlier, assigning a const pointer to a non-const pointer is invalid, because we could use the new pointer to alter const data. But assigning a non-const pointer to a const pointer is okay, provided that we’re dealing with just one level of indirection:

p2 = p1; /* valid -- assigning non-const to const */

But such assignments no longer are safe when we go to two levels of indirection. If it were allowed, we could do something like this:

const int **pp2;
int *p1;
const int n = 13;

pp2 = &p1; /* not allowed, but suppose it were */
*pp2 = &n; /** valid, both const, but sets p1 to point at n */
*p1 = 10; /* valid, but changes const n */
But notice then non-constant pointer-to-int ‘p1’ modified constant integer n. Therefore multi-level indirection is not allowed.
Top
11 What is the Difference Between Various Pointers, const type * pname, type * const pname, and const type * const pname in C
Question: What is the Difference Between Various Pointers, const type * pname, type * const pname, and const type * const pname in C
Answer: We are already familiar with symbolic constants created using ‘const’ keyword. For example:

/* sym_const.c -- Program creates and accesses symbolic constant */

#include <stdio.h>

int main(void)
{
const int gz = 122; /* gz is a symbolic constant */

gz = 111; /* What? If allowed? */
return 0;
}

Output as below:

sym_const1.c: In function ‘main’:
sym_const1.c:8:2: error: assignment of read-only variable ‘gz’
Notice what happened when we tried to modify constant integer ‘gz’ with new value, here, 111. It caused an ERROR stating “assignment of read-only variable ‘gz’”. Actually, when we declare some variable to be constant, it’s allocated storage in read-only area of memory allocated to our program. Hence, we can’t modify constants.

Undoubtedly, we can also create symbolic constants using #define statements. O key, now, Let’s further unravel the use of ‘const’ keyword through more examples:

/*
* use_const_keyword1.c -- Program shows if we can modify
* non-constant data using pointer to constant data
*/
#include <stdio.h>
#define MONTHS 12 /* MONTHS, a symbolic constant */

int main(void)
{
double rainfall[MONTHS] = {2.12, 3.1, 0.34, 4.00, 1.1, 1.23, 2.345,
3.121, 3.232, 0.023, 1.023, 2.234};

const double *dp = rainfall; /* dp, pointer to constant double, assigned
* address of first element of rainfall */

*dp = 3.12; /* modifying rainfall[0], if allowed? */
rainfall[0] = 3.12; /* if allowed */
rainfall[2] = 2.22; /* if allowed */

return 0;
}
Output when run on Linux,

use_const_keyword1.c: In function ‘main’:
use_const_keyword1.c:17:2: error: assignment of read-only location ‘*dp’
Remember that a pointer to constant can be made to point constant as well as non constant data. Here, in the above ex. rainfall is non-constant data and address of first element i.e. &rainfall[0] is assigned to ‘dp’. Note here that since ‘dp’ is pointer to constant data of type double, can’t be used to modify the data. However, in rainfall, an array of non-constant doubles, we can modify values of its elements.

Actually, pointer to constant is normally used as a formal argument in a function for actual array argument in order to protect values of array elements from accidental alterations. For example:

#include <stdio.h>
void show(const double *); /* use of const with formal arg */

int main(void)
{
----
----
show(rainfall);
return 0;
}

void show(const double *srf)
{
double rfd;
while (( rfd = *srf++) != 0)
printf("%lf\t", rfd);

printf("\n");
}
Here, in the above ex., pointer ‘srf’ to constant double data prevents actual values in array rainfall from modifications.

In the following fragment of code, although, pointer ‘dp’ is pointing to first element of the array rainfall, we can cause it to point to any element of the rainfall or to any other data of type double. Let’s see an example:

double race_miles = 10.0;
double rainfall[MONTHS] = {2.12, 3.1, 0.34, 4.00, 1.1, 1.23, 2.345,
3.121, 3.232, 0.023, 1.023, 2.234};

double *dp = rainfall; /* dp points to rainfall[0] */
dp = &rainfall[5]; /* if allowed? */
dp = &race_miles; /* if allowed? */
/* dp points to where variable race_mile is stored */

/* now modified 'dp' to pointer-to-const-double */
const double *dp = rainfall; /* dp points to constant data */
/* dp assigned the address of first element of rainfall */

dp = &rainfall[2]; /* if allowed? */
O key, let’s see, in the following example, if we can cause pointer ‘dp’ to point to some other location than the location/address it was initially assigned to it.


double rainfall[MONTHS] = {2.12, 3.1, 0.34, 4.00, 1.1, 1.23, 2.345,
3.121, 3.232, 0.023, 1.023, 2.234};

double * const dp = rainfall;
/* dp assigned the address of first element of rainfall */

dp = &rainfall[2]; /* if allowed? */
In the above fragment of code, ‘dp’, a constant pointer is initialized with address of first element of array rainfall. It can’t be made to point elsewhere other than it was originally initialized to point to.

Now, we can use const keyword twice to cause pointer to point to constant or non constant data and the address it was originally initialized with. For example:

double rainfall[MONTHS] = {2.12, 3.1, 0.34, 4.00, 1.1, 1.23, 2.345,
3.121, 3.232, 0.023, 1.023, 2.234};

const double * const dp = rainfall;
/* dp assigned the address of first element of rainfall */

dp[0] = 0.123; /* if allowed */
dp[4] = 2.123; /* if allowed */
dp = &rainfall[2]; /* if allowed? */
Of course, in above ex., pointer ‘dp’ is a constant pointer to constant data, therefore, can neither be used to modify the values of any array location nor can be used to point to any other location or other data of type double.
Top
12 What is the Difference Between Pointer to Constant and Regular Pointer in C Language
Question: What is the Difference Between Pointer to Constant and Regular Pointer in C Language
Answer: O key! First, we try to understand what a regular pointer is, how is this declared, initialized and used in a C program? Consider a program, for example:

/*
* diff_regptr_and_ptr2const1.c -- Program shows what happens when regular
* pointer is assigned addresses of non-constant and constant data
*/
#include <stdio.h>

int main(void)
{
float pass_per = 60.9; /* pass_per is non-constant float */
const float fare = 31.35; /* fare is constant float */
float *fp = &pass_per; /* fp, regular pointer to float */

printf("\nIn the exp. \"float *fp = &pass_per\":\n");
printf("fp is a regular pointer to float pass_per, value of "
"pass_per is %f\n", *fp);
printf("Now, we try modify pass_per using regular pointer fp...\n");

*fp = 70.9;

printf("O key, now, in exp. \"*fp = 70.9\", pass_per is %f\n", *fp);
printf("\nNow, let's see what happens when fp is assigned address of"
" some \"constant data\"\n");

fp = &fare; /* assigned fp address of constant fare */

printf("\nIn the exp. \"fp = &fare\":\n");
printf("fp is a regular pointer to constant float \"fare\", value of"
" fare is %f\n", *fp);
printf("Now, we try to modify constant fare using fp...\n");

*fp = 62.70;

printf("O key, now, in the exp. \"*fp = 62.70\", value of constant "
"data fare is %f\n\n", *fp);

return 0;
}
We test the program for output below:

test1.c: In function ‘main’:
test1.c:20:8: warning: assignment discards ‘const’ qualifier from pointer
target type [enabled by default]
[root@localhost ch06_Pointers]# ./a.out

In the exp. "float *fp = &pass_per":
fp is a regular pointer to float pass_per, value of pass_per is 60.900002
Now, we try modify pass_per using regular pointer fp...
O key, now, in exp. "*fp = 70.9", pass_per is 70.900002

Now, let us see what happens when fp is assigned address of some "constant
data"

In the exp. "fp = &fare":
fp is a regular pointer to constant float "fare", value of fare is 31.350000
Now, we try to modify constant fare using fp...
O key, now, in the exp. "*fp = 62.70", value of constant data fare is
62.700001
So we observed behaviour of regular pointer is quite alarming when the same is assigned address of “constant data”. Program compiled well with a “Warning: assignment discards ‘const’ qualifier from the target type [enabled by default]”. Be careful! Never use regular pointer with constant data as this can modify even constant data.


Now, this time it’s turn to consider pointer to constant, again through some examples:

/*
* diff_regptr_and_ptr2const2.c -- Program shows what happens when pointer
* to const is assigned address of non-constant and constant data
*/
#include <stdio.h>

int main(void)
{
int holidays = 69; /* non-constant holidays */
const int teachers = 98;
/* teachers declared and initialized to be constant */

const int *cip = &holidays;
/* cip is a pointer-to-constant-integer */

printf("\nFor Non-Constant Integer \"holidays\":\n");
printf("In exp. \"const int *cip = &holidays\", no of holidays in 2014"
" %d\n", *cip);

printf("\nO key, now we try to modify non- constant integer "
"\"holidays\" \nusing pointer to constant integer \"cip\"\n");
*cip = 100; /* modifying holidays using cip */

printf("In exp. \"*cip = 100\", we tried to modify no of holidays in "
"2014 from 69 to %d\n", *cip);

cip = &teachers;
/* assigning pointer-to-constant-int address of const data 'teachers' */

printf("\nFor Constant Integer \"teachers\":\n");
printf("In exp. \"cip = &teachers\", there are %d teachers in a school."
"\n", *cip);

printf("\nO key, now we try to modify constant integer \"teachers\"\n"
"using pointer-to-constant-integer \"cip\"\n");
*cip = 100; /* modifying teachers using cip */

printf("In exp. \"*cip = 100\", we tried to modify no of teachers in a "
"school from 98 to %d\n", *cip);

return 0;
}
Let’s analyse output of the program below:

[root@localhost ch06_Pointers]# gcc diff_regptr_and_ptr2const2.c
diff_regptr_and_ptr2const2.c: In function ‘main’:
diff_regptr_and_ptr2const2.c:14:2: error: assignment of read-only location
‘*cip’
diff_regptr_and_ptr2const2.c:24:2: error: assignment of read-only location
‘*cip’
Wow! Using pointer-to-constant is very-very safe! However, pointer-to-constant, in ex. prog. ‘cip’, was assigned addresses of non-constant and constant data at places without any problem but when we tried ‘cip’ to modify data whether constant or non-constant, pointed to by ‘cip’, it simply couldn’t. Instead, it caused errors at compile time with massage “error: assignment of read-only location ‘*cip’”.

A practical consequence of pointer-to-constant is to use pointer as a formal argument in a function which processes data and thus prevents data from being modified occidentally. For example:


/* adv_ptr2const.c -- Program displays advantages of pointer-to-constant */
#include <stdio.h>
#define FAM_MEM 5
#define SUB 5
void modify_const_data(const float *, int); /* fun. prototype */

int main(void)
{
const float expenses[FAM_MEM] = {360.00, 437.12, 45.65, 338.34, 98.987};
/* array of constant floats */
float marks[SUB] = {34.03, 56.98, 66.78, 68.0, 80.0};
/*array of non-constant floats */

modify_const_data(marks, SUB);
modify_const_data(expenses, FAM_MEM);

return 0;
}

void modify_const_data(const float *base, int val) /* fun. def. */
{
int i, FLAG = 1;
const float *copy;

for (i = 0; i < val; i++) {
copy = base++;
if (FLAG) {
printf("Now, we try to modify elements of array...\n");
FLAG = 0;
}
*copy += 10.0; /* increment each array element by 10.0 */
}
}
Observe the output as:

[root@localhost ch06_Pointers]# gcc adv_ptr2const.c
adv_ptr2const.c: In function ‘modify_const_data’:
adv_ptr2const.c:30:9: error: assignment of read-only location ‘*copy’
Here, in the function: modify_constant_data(), pointer to constant ‘*copy’ receives both non-constant and constant data but prevents original data from alterations.
Top
13 Can we use addressof Operator ‘&’ to Determine Address of a Register Variable in C?
Question: Can we use address of Operator (&) to Determine Address of a Register Variable in C
Answer: addressof operator ‘&’ is a unary operator fetches us address of its operand/data object occupied in memory. But registers are not the part of memory. Instead, these are components of CPU. Further, there are only a few registers that are used for data storage. Therefore, addressof operator doesn’t get us address of operands of type register. Well! Whenever we declare a variable to be register, this generates instructions suggesting compiler to allocate variable storage in the register memory but not a compulsion. Instead, this is fully dependent on compiler’s choice if to give operand storage in memory or registers. For example:

/*
* addof_vs_reg.c -- program shows if we can fetch address of variable of
* type register
*/

#include <stdio.h>

int main(void)
{
int me = 1;
register int you = 2; /* 'you' declared to be register */

printf("Address of me in exp. \"int me = 1\" is \t\t%p\nAddress of you "
"in exp. \"register int you = 2\" is %p\n", &me, &you);

return 0;
}

Observe the output below:

addof_vs_reg.c: In function ‘main’:
addof_vs_reg.c:9:3: error: address of register variable ‘you’ requested
Requesting for address of a variable declared to be type register causes compile time error with massage as “error: address of register variable ‘you’ requested”.
Top
14 Explain NULL Pointer in C with Examples
This C Tutorial Explains NULL Pointer in C Programming with Examples.
A NULL Pointer in C is a special type of pointer which points to nowhere i.e. not anywhere. Pointers declared in program but not initialized contain garbage addresses, pointing to locations beyond the storage allocated to program by the compiler. But these are not NULL Pointers. For example:

/*
* uninitialized_pointer.c -- Program shows several different uninitialized
* pointers
*/
#include <stdio.h>

int main(void)
{
int *iptr; /* iptr declared pointer-to-integer */
int *ip; /* ip declared pointer-to-integer */
char *cp; /* cp declared pointer-to-character */
float *fp; /* fp declared pointer-to-float */

printf("Default Address \"iptr\" holds as %p\n", iptr);
printf("Default Address \"ip\" holds as %p\n", ip);
printf("Default Address \"cp\" holds as %p\n", cp);
printf("Default Address \"fp\" holds as %p\n", fp);

return 0;
}

Output:

Default Address "iptr" holds as (nil)
Default Address "ip" holds as 0x7fff69f3bd80
Default Address "cp" holds as 0x400420
Default Address "fp" holds as (nil)

O key! Now, look at how can we make a pointer NULL and understand its purpose in a program? Consider an example, below,

/* null_pointer.c -- Program shows how to make a pointer NULL */

#include <stdio.h>

int main(void)
{
int *nptr = 0; /* making nptr a NULL pointer */
char *cp = 0; /* making cp a NULL pointer */
float *fp = 0; /* making fp a NULL pointer */

printf("In exp. /"int *nptr = 0/"\n");
if (!nptr) /* test if nptr is NULL or not */
printf("nptr is a NULL pointer!\n\n");
else
printf("\nnptr is not a NULL pointer!\n\n");

printf("In exp. /"char *cp = 0/"\n");
if (!cp) /* test if cp is NULL or not */
printf("cp is a NULL pointer!\n\n");
else
printf("cp is not a NULL pointer!\n\n");

printf("In exp. /"float *fp = 0/"\n");
if (!fp) /* test if fp is NULL or not */
printf("fp is a NULL pointer!\n\n");
else
printf("fp is not a NULL pointer!\n\n");

return 0;
}
See the output below:

In exp. "int *nptr = 0"
nptr is a NULL pointer!

In exp. "char *cp = 0"
cp is a NULL pointer!

In exp. "float *fp = 0"
fp is a NULL pointer!
We observed in above program, how we, by assigning ZERO ‘0’ to pointer to any type, made it a NULL Pointer. This is a source code convention. Internally, however, the value for NULL pointer actually be something different and compiler takes care of translating between zero and internal value.


Remember that Null pointer points to nowhere in memory so NEVER Dereference it for this causes Segmentation Fault.

Basically, any uninitialized pointer, if in a program, is made NULL and then used differently, for ex. function can return NULL if searching an array for a particular value and not found, or set last element of an array of pointers as NULL for ease of accessing the array.
Top
15 Explain NULL Pointer Indirection in C Programming with Examples
This C Tutorial Explains Indirection of a NULL Pointer in C Programming and Describes Pros and Cons of Null Pointer, with examples.
As we know that a NULL pointer is one that points to nowhere in memory. For example:

int *ip = 0; /* 'ip' is a pointer-to-int initialized with value zero */
In the above pointer initialization, pointer ‘ip’ is made NULL by assigning value zero. So, what will happen if we perform Indirection or Dereferencing upon such a pointer? Indirection is to “go to the location pointed to by the pointer and access the location for value there.” But NULL pointer is not pointing to any location; where to go in memory to access value over there? We take an example to understand this:

/*
* indirection_nullptr.c -- Program shows how to make null pointer and what
* happens on its indirection
*/
#include <stdio.h>

int main(void)
{
int *nptr = 0; /* making nptr a NULL pointer */

printf("In exp. "int *nptr = 0"n");
if (!nptr)
printf("nptr is a NULL pointer!n");
else
printf("nptr is not a NULL pointer!n");

printf("nNow we try Indirection '*' on NULL Pointer 'nptr' to see "
"what happens...n");
printf("The Value at location pointed to by 'nptr' is %dn", *nptr);

return 0;
}
Output, when program is run, as below:

In exp. 'int *nptr = 0'
nptr is a NULL pointer!

Now we try Indirection '*' on NULL Pointer 'nptr' to see what happens...

Segmentation fault (core dumped)

Notice here that performing Indirection on NULL Pointer ‘nptr’ caused Segmentation Fault which means we tried to accessing a location that didn’t exist in program’s address space. Therefore, it’s very important to test a pointer for NULL before performing indirection upon it in order to prevent a program from being aborted because of Segmentation fault.

O key! we, now, modify the above program as:

/*
* testfornullptr.c -- Program emphasizes test a pointer for NULL before
* applying indirection on it
*/
#include <stdio.h>

int main(void)
{
int *nptr = 0; /* making the 'nptr' a NULL pointer */

printf("In exp. 'int *nptr = 0'n");
if (!nptr) { /* If 'nptr' is a NULL or not */
printf("'nptr' is a NULL pointer!n");
printf("BEWARE! DON'T PERFORM INDIRECTION UPON IT!n");
}
else {
printf("'nptr' is not a NULL pointer!n");
printf("nNow we try Indirection '*' on NULL Pointer 'nptr'"
" and see what happens...n");
printf("The Value at location pointed to by 'nptr' is %dn",
*nptr);
}
return 0;
}
Here is Output,

In exp. 'int *nptr = 0'
'nptr' is a NULL pointer!
BEWARE! DON'T PERFORM INDIRECTION UPON IT!
Remember, firstly, in any program, make any uninitialized pointer a NULL Pointer. Then always test for NULL before performing indirection upon such a pointer to prevent the program from being aborted by Seg Fault.


Pros and Cons

An array of pointers can set its last pointer ‘NULL’ for ease of accessing its elements. Example:

char *str[] = {"o key! ", "this is an ", "array of ",
"pointers to characters!", 0};
A function, for example, searching an array for a particular character can return NULL pointer if desired character isn’t found.

Null pointers are used to mark end of linked lists for their easy traversing.
Top
16 Which Pointer Expressions in C Programming are called as L-Values
Question: Which Pointer Expressions in C Programming are called as L-Values?
Answer: We already know that lvalue refers to some location or storage used by some data object, for example: variables, arrays, structures, pointers etc. Further, ‘l’ in lvalue stands for left side of assignment “=” operator meaning that left side of assignment must be an expression which results in some location in memory. Let’s take a few examples:

int index = 0; /* index, an integer, is initialized with 0 */
char address[100]; /* address, an array of 100 characters *
float avg_rain; /* avg_rain has some garbage */
float temperature;
float *fp = &avg_rain;
/*
* *fp, a pointer-to-float, is initialized with address of float
* 'avg_rain'
*/
All the above data objects are stored in memory at specified locations. Their addresses can be obtained by using unary operator called addressof operator ‘&’. Addressof operator returns address of first byte of storage allocated to the data object.

Now, see, if constants are allocated to specified locations, can we determine their addresses using addressof operator? We take some examples:

500;
45.0; /* all these are constants *
'A';
All the above constants are stored in memory but where? We can’t know this? Actually, constants don’t have lvalues. And that’s why we can’t assign them values! Let’s try to find their addresses:

/*
* determine_add_const.c -- Program shows if we can determine address of
* constants
*/
#include <stdio.h>

int main(void)
{
500; /* integer constant */
45.06; /* float constant */
'A'; /* character constant */

printf("Address of integer '500' is %p\n", &(500));
printf("Address of float '45.06' is %p\n", &(45.06));
printf("Address of character \'A\' is %p\n", &('A'));

return 0;
}
Output as below:

[root@localhost ch06_Pointers]# gcc determine_add_const.c
determine_add_const.c: In function ‘main’:
determine_add_const.c:9:43: error: lvalue required as unary ‘&’ operand
determine_add_const.c:10:43: error: lvalue required as unary ‘&’ operand
determine_add_const.c:11:45: error: lvalue required as unary ‘&’ operand
Note that addressof operator operates on operands having lvalues. Constants don’t have!

O key! Now, we try to modify the above mentioned data objects, below:

int index = 100; /* now index is assigned 100 */
char address[100]; /* address is an array of 100 characters */
float avg_rain = 3.203; /* avg_rain is assigned 3.203 */
*fp = &temperature; /* *fp is assigned address of float temperature */
Because the left side of the assignment can be modified, lvalue is properly referred to as modifiable lvalue.

Until now, we are cleared with what an lvalue is! Let’s further talk about it with reference to pointer expressions. Addressof operator ‘&’ and indirection / dereferencing operator ‘*’ are frequently used with pointers. Let’s unravel some pointer expressions to understand how these two operators work, for example:

int men = 100, women = 150;
int *ip = &men;
/* *ip = &men, assigns 'ip' address of location where men is stored */
In exp. “*ip = &men”, pointer to integer ‘ip’ points to location of men in the memory. To access the value of men using ‘ip’, we need to perform indirection on ‘ip’. Let’s see how,

printf("There are %d men working in a factory.\n", *ip);

Let’s interpret a simple exp. *ip. ‘ip’ holds the address of location of men. When we performed indirection on ‘ip’, it caused to go to location pointed to by ‘ip’, that is location of men, and access the value there, whether to read value from or to write value there. That’s why ‘*ip’ represents both as value and location and hence is an lvalue.

Take some little bit complex pointer exp., for example:

int NH_India = 228;
int *ip = &NH_India;
int new;

new = ++*ip;
In the exp. “new = ++*ip”, ++ and * are unary operators have associativity from right to left. So indirection is applied first and value at the location pointed to by ‘ip’ is taken, which is here 228. Then pre-increment operator to operate. But pre-increment operator increments its operand by 1, then makes a copy of incremented value and use that copy in the surrounding expression. See program below:

/* ptrexp_as_lvalue1.c -- program shows pointer expressions */
#include <stdio.h>

int main(void)
{
int NH_India = 228;
int *ip = &NH_India;
int new;

printf("When \"new\" not initialized it is %d and NH_India is %d\n",
new, NH_India);

new = ++*ip;

printf("After \"new = ++*ip\", new is %d and NH_India is %d\n",
new, NH_India);

return 0;
}
Output of the above program:

[root@localhost ch06_Pointers]# gcc ptrexp_as_lvalue1.c
[root@localhost ch06_Pointers]# ./a.out
When "new" not initialized it is 32767 and NH_India is 228
After "new = ++*ip", new is 229 and NH_India is 229
Notice, integer ‘NH_India’ is incremented by 1. But if exp. ++*ip represents an lvalue? Can we write

new = ++*ip;
as
++*ip = new; /* if allowed? */
Of course, not! Why? Because, we have already seen above that ‘++*ip’ gives an integer value and not a location.

/* ptrexp_as_lvalue2.c -- program shows pointer expressions as lvalues */
#include <stdio.h>

int main(void)
{
int NH_India = 228;
int *ip = &NH_India;
int new = 100;

printf("When \"new\" initialized it is %d and NH_India is %d\n",
new, NH_India);

++*ip = new; /* if allowed? */

printf("After \"++*ip = new\", ++*ip is %d and NH_India is %d\n",
new, NH_India);
return 0;
}
Output is below:

[root@localhost ch06_Pointers]# gcc ptrexp_as_lvalue2.c
ptrexp_as_lvalue2.c: In function ‘main’:
ptrexp_as_lvalue2.c:11:15: error: lvalue required as left operand of
assignment
Note the error: lvalue required as left operand of assignment. What if we write the expression as:

++*ip;
as
*ip++;
Again, there are two operators * and ++. But this time ++ is used as post increment operator and post increment operator has higher precedence than ‘*’ operator. Let’s continue to emphasize on their working. Remember that pre and post increment operators create copies of values of their operands and that copy is used in the surrounding exp.. Also remember that in case of pre-increment, copy is created after operand is modified while in post-increment copy is created before operand is incremented.

So, in exp. “*ip++”, ‘++’ operates first, copy of value of ‘ip’, which is address of integer NH_India, is created, then pointer ‘ip’ is incremented to point to next integer and then indirection is performed on copy and value at the location pointer ‘ip’ was pointing to before increment is assigned to new.


new = *ip++;
/*
* ptrexp_as_lvalue3.c -- program shows where pointer points to when
* incremented
*/
#include <stdio.h>

int main(void)
{
int NH_India = 228;
int *ip = &NH_India;
int new = 100;

printf("When \"new\" initialized it is %d and value of *ip is %p\n",
new, ip);

new = *ip++;

printf("After \"new = *ip++\", new is %d and \"new value\" of *ip is "
."%p\n", new, ip);

.return 0;
}
Look closely at the output below:

[root@localhost ch06_Pointers]# gcc ptrexp_as_lvalue3.c
[root@localhost ch06_Pointers]# ./a.out
When "new" initialized it is 100 and value of *ip is 0x7fffe9828340
After "new = *ip++", new is 228 and "new value" of *ip is 0x7fffe9828344
Notice pointer *ip’s earlier and current values. Although, *ip is incremented by 1 it’s value changed from 0x7fffe9828340 to 0x7fffe9828344. Actually, when we say, a pointer is incremented by 1, we mean it’s moved forward by one storage unit of the type it’s pointing to.

Now, we see what happens when we set the exp. “*ip++” on the left side of assignment.

*ip++ = new;
Again, ‘*ip++’ doesn’t represent a location but a value. And a value can’t be assigned any other value. Therefore, this statement results in lvalue error.

There are numerous pointer expressions which are lvalues and used frequently in programs. However, on the other side, not all pointer expressions are lvalues.

Examples of pointer expressions having lvalues:

*ip;
*++ip;
*ip++;
Examples of pointer expressions with no valid lvalues:

++*++ip;
ip++; and ip++;
(*ip)++;
++*ip++;
Note, you can apply above given reasoning to understand pointer expressions, in examples above, which are lvalues and which aren’t.
Top
17 Explain Pointer Operations in C with Examples
This C Tutorial Explains Different Pointer Operations in C Programming with examples.
Let’s start by considering the fragment of code given below:

char ch = 'A';
char *cp = &ch;

printf("character ch is %c\n", *cp);

cp++; /* cp, pointer-to-char is incremented by 1 */
printf("After cp++, where does cp point to?\n");
Since type ‘char’ takes one byte, when ‘cp’, pointer-to-char, is incremented by 1, it’s value, address of character ch, gets incremented by 1, that is ‘cp’ points to next byte. What does that byte contain whether a character or some other value? We can’t predict this simply by bit pattern of that byte. As we know we require type of value to predict what’s contained in that location. Let’s see another fragment of code below:

int goggles = 1885;
int *ip = &goggles; /* ip is initialized address of int goggles */

printf("value of goggles is %d\n", *ip);
ip++; /* ip is incremented by 1 */
printf("After ip++, where does ip point to?\n");
As we know that address of a variable of type which is allocated more than one byte of storage, viz, int, float, double etc, is the addrerss of first byte of storage. Since type ‘int’ on linux system takes 4 bytes, does pointer-to-int ‘ip’ after incremented by 1 points to somewhere inside the integer or some elsewhere?

Actually, when we increment a pointer, say, for example, by 1, integer 1 is scaled to proper size before addition to the pointer. Meaning that by what integer value pointer is to be incremented by is multiplied by size of type pointed to by pointer. For example, here ‘ip’ points to integer. when ‘ip’ is incremented by 1, 1 is multiplied by size of type int i.e. 4 bytes. So, next time when ‘ip’ is incremented by 4, 4 is scaled to 16 bytes before adding to ‘ip’. For example,

if 'ip' has address 1000, and is incremented by 10,
then 10 is scaled to 40 bytes before addition to the 'ip'.
After addition, 'ip' points to address 1040.
Therefore, when performing addition on a pointer, size of a pointer increments by no. of storage units and not by no. of bytes. This is the beauty of scaling that pointer arithmetic doesn’t depend on type pointer is pointing to. Meaning that if a pointer points to character, when incremented by 1, points to next character, or if it points to float, points to next float when incremented by 1 and so on.

Till now, we considered scalar varibles for pointer arithmetic. But C standard defines two arithmetic forms for pointers, first is as:

pointer +- pointer;
Remember here that both pointers must point to elements of the same array. For example:

/*
* two_ptrs.c -- Program shows manipulation of an array using two pointers
* to array
*/

#include <stdio.h>
#define FAMILIES 10

int main(void)
{
int fam_mem[FAMILIES];
int *ip1, *ip2;

printf("Read in from user, family members for %d families...\n",
FAMILIES);

for (ip1 = &fam_mem[0], ip2 = &fam_mem[FAMILIES]; ip1 < ip2; ip1++)
scanf("%d", ip1);

return 0;
}

What happens here is that *ip1 and *ip2, during initialization step of for statement, take addresses respectively of first and one beyond last element of array fam_mem[FAMILIES], then test is performed to see if *ip1 has reached one beyond the last element of fam_mem[FAMILIES], and reads into the location, pointed to by pointer, no. of family members from the user and then pointer *ip is incremented and next iteration follows until pointer *ip1 has reached address of *ip2, i.e. address of one beyond the last element of fam_mem[FAMILIES].

Remember that indexing in arrays in C begins with 0 and end up with size of arrays minus 1. That is an index as size of an array defines one beyond the last element. Standard defines that effect of a addition and a subtraction is undefined if the result points to anything earlier than the first element of the array or if it points to any element more than one beyond the last element of the array. However, it’s legal for pointer to go one element past the end of array, but indirection may not be performed on it then. For example:

/*
* access_valid_invalid_indices.c -- Program explores what happens when
* access array beyond its valid indices
*/
#include <stdio.h>
#define FAMILIES 5

int main(void)
{
int fam_mem[FAMILIES];
int *ip1, *ip2;

printf("Read in from user, family members for %d families...\n",
FAMILIES);

for (ip1 = &fam_mem[0], ip2 = &fam_mem[FAMILIES]; ip1 < ip2; ip1++)
scanf("%d", ip1);
printf("\n");

printf("No. of family members for %d Families is as:\n", FAMILIES);

for (ip1 = &fam_mem[0], ip2 = &fam_mem[FAMILIES]; ip1 < ip2; ip1++)
printf("%d\t", *ip1);
printf("\n");

printf("\nAccessing array fam_mem[%d] with valid indices\n\n",
FAMILIES);

ip1 = &fam_mem[0];
ip1 + 4;

printf("After \"ip1 = &fam_mem[0]\" and \"ip1 + 4\"\nip1 + 4 contains"
" address %p and value at that address is %d\n",
ip1 + 4, *(ip1 + 4));

ip2 - 5;
printf("After \"ip2 = &fam_mem[%d]\" and \"ip2 - 5\"\nip2 - 5 contains"
" address %p and value at that address is %d\n",
FAMILIES, ip2 - 5, *(ip2 - 5));

printf("\nLet's access array fam_mem[%d] with invalid indices\n\n",
FAMILIES);

ip1 = &fam_mem[0];
ip1 - 1;
/* *ip1 points to one before first element of array fam_mem[] */

printf("After \"ip1 = &fam_mem[0]\" and \"ip1 - 1\"\nip1 - 1 contains"
" address %p and value at that address is %d\n",
(ip1 - 1), *(ip1 - 1));

ip2 = &fam_mem[FAMILIES];
printf("After \"ip2 = &fam_mem[%d]\"\n*ip2 contains address %p and "
"value at that address is %d\n", FAMILIES, ip2, *ip2);
printf("\n");
return 0;
}
Output of the program below:

Read in from user, family members for 5 families...
6
3
10
7
8

No. of family members for 5 Families is as:
6 3 10 7 8

Accessing array fam_mem[5] with valid indices

After "ip1 = &fam_mem[0]" and "ip1 + 4"
ip1 + 4 contains address 0x7fff26173f00 and value at that address is 8
After "ip2 = &fam_mem[5]" and "ip2 - 5"
ip2 - 5 contains address 0x7fff26173ef0 and value at that address is 6

Let's access array fam_mem[5] with invalid indices

After "ip1 = &fam_mem[0]" and "ip1 - 1"
ip1 - 1 contains address 0x7fff26173eec and value at that address is 0
After "ip2 = &fam_mem[5]"
*ip2 contains address 0x7fff26173f04 and value at that address is 0
Let’s consider the second form of pointer arithmetic that C Standard Defines:

pointer - pointer;
This form has meaning only when both pointer points to elements of the same array. Result of subtracting one pointer from another, when two points to elements of the same array, is of the type of signed integral ptrdiff_t. For example, consider the fragment of code below,

float marks[6] = {23, 55.5, 43, 87.5, 91, 66.45};
float *fp1, *fp2;

fp1 = &marks[3];
fp2 = &marks[5];

fp1 - fp2; /* ? */
fp2 - fp1; /* ? */
Result of pointer difference is measured in distance between the elements and not bytes. In above code, fp2 – fp1 is +2, even float takes 4 bytes on Linux system because distance is scaled/divided by the size of float. Again, scaling makes pointer subtraction independent of type of data pointer is pointing to.

Now, is fp1 – fp2 i.e. -2 valid? Yes, as long as two points to elements of the same array.

O key! We now consider following fragment of code,


float rainfall[5] = {2.1, 0.33, 3.12, 1.5, 2.22};
float marks[5] = {56.6, 66.32, 87.5, 91.0, 34.9};

float *fp1, *fp2;

fp1 - fp2; /* ? */
fp2 - fp1; /* ? */
Subtraction of two pointers pointing to different arrays worth for nothing as programmer has no way of knowing where two arrays have been allocated relative to one another. Without this knowledge, distance from one pointer from another has no meaning.

Remember that most compilers don’t check whether result of pointer expression falls within legal bounds. Therefore, it is up to the programmer to make sure it does.

Relational operations on Pointers

Relational operations are also constrained on pointers, meaning that we can compare values of two pointers using operators <, <=, > and >= if they belong to elements of same array. For example: We have seen above that

for (fp1 = &marks[0]; fp1 < &marks[6]; fp1++)
scanf("%f", fp1);
in which we compared ‘fp1’, pointer-to-float, with pointer constant &marks[6]. Once ‘fp1’ incremented to one beyond the last element of array marks[6], for loop terminates.

Comparing the values of two arbitrary pointers is not defined by the standard. However, we can compare values of any two pointers for equality or inequality because result doesn’t depend on where the compiler has allocated the data. We try rewrite the above for loop using ‘!=’ operator,

for (fp1 = &marks[0]; fp1 != &marks[6]; fp1++)
printf("%f\t", *fp1);

if (fp1 == &marks[0])
*fp1 = 65.0;
Top
18 Explain Double Pointer or Pointer-to-Pointer in C Programming with Examples
This C Tutorial Explains Double Pointer or Pointer-to-Pointer in C Programming with Examples.
Basically, a pointer holds address; address of some variable, pointer variable, function, structure, array etc. When pointer holds address of some other pointer variable it’s called pointer-to-pointer or double pointer. For example:

/* ptr2ptr1.c -- Program shows double pointer, it's declaration and uses */
#include <stdio.h>
int main(void)
{
int a = 50; /* 'a' an integer initialized value 50 */
int *b = &a; /* b is pointer-to-integer */
int **c = &b; /* c is pointer-to-pointer-to-int or double pointer */

printf("\nValue of integer a in exp. \"a = 50\" is %d\n", a);
printf("O key! After exp. \"int *b = &a\", value of a using pointer"
" *b is %d\n", *b);

printf("\nNow, we use double pointer **c in exp. \"int **c = &b\" "
"to find\nvalue of a as %d\n", **c);

printf("\nO key! We now try to modify integer a using double pointer"
" **c.\n");
**c = 2 * a;

printf("After \"**c = 2 * a\", value of a %d\n", **c);
printf("\n");

return 0;
}

Notice the output below:


Value of integer a in exp. "a = 50" is 50
O key! After exp. "int *b = &a", value of a using pointer *b is 50

Now, we use double pointer **c in exp. "int **c = &b" to find
value of a as 50

O key! We now try to modify integer a using double pointer **c.
After "**c = 2 * a", value of a 100
So, what you observed while accessing integer variable ‘a’ using double pointer ‘**c’ and further modified ‘a’ using **c? Let’s understand this. ‘*b’ is a pointer to an integer, here to integer ‘a’.


int *b = &a; /* *b points to int a */
And, ‘**c’ is a pointer-to-pointer-to-integer i.e.

int **c = &b; /* **c is assigned address of pointer *b */
O key! We further unravel ‘**c’. What is given below segment of code, for example,

c; /* ? */
*c; /* ? */
**c; /* this is value of integer a */

printf("c is a double pointer and have address as %p.\n", c);
printf("*c is value at address (%p) is %p\n", c, *c);
printf("**c is a value of type int, which is %d\n", **c);
printf("\n");

Let’s understand the output,

c is a double pointer and have address as 0x7fffbc1f73a8.
*c is value at the address (0x7fffbc1f73a8) is 0x7fffbc1f73b4
**c is a value of type int, which is 100
Notice that c is a pointer-to-pointer-to-integer, so c holds address of another pointer, here we say ‘b’. What happens when we perform indirection ‘*’ on c. This causes go to the location of pointer ‘*b’ and access the value in that location i.e. address of integer ‘a’ which was assigned to pointer ‘*b’. And when we further perform indirection on ‘*c’ i.e. ‘*(*c)’, we accessed integer ‘a’.

We make an inference from above that as many levels of pointer to pointer we add, an equal no. of ‘*’ operators precede the pointer.
Top
Render time: 0.29 seconds
7,457,471 unique visits