From C compiler’s point of view, a variable name identifies some physical location within the computer where the string of bits representing the variable’s value is stored. There are basically two kinds of locations in a computer where such a value may be kept: Memory and CPU registers. It is the variable’s storage class
which determines in which of these two locations the value is stored. Moreover, a variable’s storage class represents that
Where the variable would be stored?
What will be the initial value of the variable, if the initial value is not specifically assigned? (i.e. the
default initial value)
What is the scope of the variable i.e. in which functions the value of the variable would be available. What is the life of the variable i.e. how long would the variable exist.
There are four storage classes in C.
Automatic storage class Register storage class
Static storage class External storage class.
Automatic Storage Class:
The features of a variable defined to have an automatic storage class are as follows:
Storage : Memory
Default initial value : An unpredictable value, which is often called a garbage value. Scope : Local to the block in which the variable is defined.
Life : Till the control remains within the block in which the variable is defined.
An automatic storage class variable is declared as below and the fact that if the variable is not initialized it contains a garbage value.
//stclass1.c Output
1211 221 which is the garbage value since automatic variables are required to initialize properly. Scope and life of an automatic variable is illustrated as follows:
//stclass2.c
Output of the program is 1 1 1
Since all printf( ) statements occur within the outermost block.
When the control comes out of the block in which the variable is defined, the variable and its value is irretrievably lost.
E.g. //stclass3.c
Note that the compiler treats the three i’s as totally different variables, since they are defined in different blocks.
Register Storage Class:
Storage : CPU registers
Default initial value : Garbage value
Scope : Local to the block in which the variable is defined.
Life : Till the control remains within the block in which the variable is defined.
A value stored in a CPU register can always be accessed faster than the one which is stored in memory. Therefore if a variable is used at many places it is better to declare its storage class as register. Example of frequently used variables are loop counters. Storage class is named as register.
//stclass4.c
Here, even though the storage class of ‘i’ is declared as register, it is not necessary that the value of i would be
stored in a CPU register. Because the number of CPU registers are limited (14 in case of a micro-computer), and they are busy doing some other task. Then the variable works as if its storage class is automatic.
Register storage class cannot be used for all types of variables. E.g.
register float q; register double a; register long c;
These declarations are wrong because the CPU registers in a microcomputer are usually 16 bit registers and therefore cannot hold a float value or a double value, which require 4 and 8 bytes respectively for storing a value. For the above declarations error messages are not displayed, only the compiler treats the variables to be of automatic storage class.
Static Storage Class:
Storage : Memory
Default initial value : zero
Scope : Local to the block in which the variable is defined.
Life : Value of the variable persists between different function calls.
Consider the comparison of automatic storage class and static storage class using the given program. //stclass5.c
//stclass6.c
Like auto variables, static variables are also local to the block in which they are declared. The difference between them is that static variables don’t disappear when the function is no longer active.
Their values persist. If the control comes back to the same function again the static variables have the same values they had last time around.
External Storage Class
Storage: Memory Default initial value: zero Scope: Global
Life: As long as the program’s execution doesn’t come to an end.
External variables are declared outside all functions, yet are available to all functions that use them. E.g: stclass7.c
i is available to the functions increment() and decrement() since i has been declared outside all functions.
The function that uses an external variable should declare that variable external i.e., the keyword extern, as shown below:
//stclass8.c
The use of extern inside a function is optional as long as it is declared outside and above that function in the same source code file.
Consider the given program: //stclass9.c
Here, the local variable gets preference over the global variable hence for the printf(), present in main() output is 20. When display() is called and control reaches the printf(), the value of the global x i.e., 10 is printed.
Pointers
A Pointer is a variable that represents the location (address) of a variable, within the computer memory. Also, Pointers are special type of variables which stores the address of some another variable.
Consider the declaration, int i=3;
This declaration indicates the C compiler to:
Reserve space in memory to hold the integer value.
Associate the name i with this memory location.
Store the value 3 at this location.
i’s location in memory is represented by following memory map.
i
value at location
65524 location number (address)
From the above description, it is seen that the compiler has selected memory location 65524 as the place to store value 3. The location number 65524 is not a number to be relied upon, because some other time the compiler may choose a different location for storing value 3. The important point is i’s address in memory is 65524.
The following program can print address number:
#include<stdio.h> #include<conio.h> void main() { int i=3; clrscr();
printf("\nAddress of i=%u", &i); printf("\nValue of i=%d", i); getch(); } /****************************OUTPUT******************************** Address of i=65524 Value of i=3 *******************************************************************/
3
location name
#include<stdio.h> #include<conio.h> void main() { int i=3; clrscr();
printf("\nAddress of i=%u", &i); printf("\nValue of i=%d",i); printf("\nValue of i=%d",*(&i)); getch(); } /*******************************OUTPUT******************************** Address of i=65524 Value of i=3 Value of i=3 **********************************************************************/ #include<stdio.h> #include<conio.h> void main() { int i=3; clrscr();
printf("\nAddress of i=%u", &i); printf("\nValue of i=%d", i); getch(); } /****************************OUTPUT******************************** Address of i=65524 Value of i=3 *******************************************************************/
& is C’s ‘address of’ operator.
The address is printed out using %u which is a format specifier for printing an unsigned integer and since 65524 represents an address, there is no question of sign being associated with it.
The other pointer operator available in C is ‘*’, called ‘value at address’ operator. It gives the value stored at a particular address. The ‘value at address’ operator is also called ‘indirection’ operator.
E.g.
#include<conio.h> void main()
{
int i=3; clrscr();
printf("\nAddress of i=%u", &i); printf("\nValue of i=%d",i); printf("\nValue of i=%d",*(&i)); getch(); } /*******************************OUTPUT******************************** Address of i=65524 Value of i=3 Value of i=3 **********************************************************************/
The expression &i gives the address of the variable i. This address can be collected in a variable, by j=&i;
j is a variable which contains the address of other variable. (i in this case)
i j
65524 65522
i’s value is 3 and j’s value is i’s address.
Since j is a variable which contains the address of i, it is declared as, int *j;
This declaration means that j will be used to store the address of an integer value. Also, * stands for
‘value at address’. Thus int *j also means that the value at the address contained in j is an integer.
************************************************************************ #include<stdio.h> #include<conio.h> void main() { int i=3; int *j; j=&i; clrscr(); printf("\nAddress of i=%u",&i); printf("\nAddress of i=%u",j); printf("\nAddress of j=%u",&j); printf("\nValue of j=%u",j); printf("\nValue of i=%d",i); printf("\nValue of i=%d",*(&i)); printf("\nValue of i=%d",*j); getch(); } /********************************OUTPUT******************************* Address of i=65524 Address of i=65524 Address of j=65522 Value of j=65524 Value of i=3 Value of i=3 Value of i=3 **********************************************************************/
Consider the declarations,
int *alpha; char *ch; float *s;
Here alpha, ch and s are declared as pointer variables i.e., variables capable of holding addresses. Addresses are always going to be whole numbers, therefore pointers always contain whole numbers. *s means s is going to contain the address of a floating point value. Similarly char *ch
Is going to contain the address of a char value or in other words, the value at address stored in ch is going to be a character.
Pointer is a variable which contains address of another variable. This variable itself might be
another pointer. Thus pointer may contain, another pointer’s address. This concept is explained in
*********************************************************************** #include<stdio.h> #include<conio.h> main() { int i=3, *j, **k; j=&i; k=&j; clrscr();
printf("\nAddress of i=%u", &i); //65524 printf("\nAddress of i=%u", j); //65524 printf("\nAddress of i=%u", *k); //65524 printf("\nAddress of j=%u", &j); // 65522 printf("\nAddress of j=%u", k); //65522 printf("\nAddress of k=%u", &k); //65520 printf("\nValue of j=%u", &j); //65522 printf("\nValue of j=%u", &k); //65520 printf("\nValue of j=%u", j); //65524 printf("\nValue of k=%u", k); //65522 printf("\nValue of i=%d", i); //3 printf("\nValue of i=%d", *(&i)); //3 printf("\nValue of i=%d",*j); //3 printf("\nValue of i=%d",**k); //3 getch(); } *********************************************************************** i j k 65524 65522 65520
Variables j and k are declared as: int i, *j, **k;
Here i is an ordinary int, j is a pointer to an int (also called an integer pointer) whereas k is a pointer