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:

advertisement
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,

advertisement
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.

advertisement

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.

Sanfoundry Global Education & Learning Series – 1000 C Tutorials.

If you wish to look at all C Tutorials, go to C Tutorials.

advertisement
Manish Bhojasia, a technology veteran with 20+ years @ Cisco & Wipro, is Founder and CTO at Sanfoundry. He is Linux Kernel Developer & SAN Architect and is passionate about competency developments in these areas. He lives in Bangalore and delivers focused training sessions to IT professionals in Linux Kernel, Linux Debugging, Linux Device Drivers, Linux Networking, Linux Storage, Advanced C Programming, SAN Storage Technologies, SCSI Internals & Storage Protocols such as iSCSI & Fiber Channel. Stay connected with him @ LinkedIn