Pointers And Strings

  1. A string is a collection of characters ending with a '\0'.

    char str1[] = { 'A', 'j', 'a', 'y', '\0' } ;
    char str2[] = "Ajay" ;

    In "Ajay", '\0' is assumed.

  2. If a string is defined and initialized at the same place mentioning its dimension is optional.

  3. While returning the size of a string the sizeof operator counts '\0'.

  4. Base address of a string is address of zeroth element of the string.

  5. Following string library functions are frequently used:

    char str1[] = "Ajay" ;
    char str2[10] ;
    char str3[] = "Kumar" ;

    int l, m, n ;
    l = strlen ( str1 ) ; // returns count of characters. Doesn;t count '\0'.
    strcpy ( str2, str1 ) ; // copies contents of str1 into str2
    strcat ( str3, str1 ) ; // appends contents str3 with that of str1
    m = strcmp ( str1, str2 ) ; // compares two strings, returns zero if equal, non-zero otherwise
    n = strcmp ( str1, "Ajay" ) ; // compares two strings, returns zero if equal, non-zero otherwise

    If the two strings are unequal the ascii difference between first non-matching pair of characters is returned.

  6. There are two ways to handle several strings:
    - using a 2-D array of characters
    - using an array of pointers to strings

char names[][20] = {

"Ajay",

"Atul",

"Ramesh",

"Sivaramakrishnan",

"Sameer"

} ;

char *n[] = {

"Ajay",

"Atul",

"Ramesh",

"Sivaramakrishnan",

"Sameer"

} ;

2-D array suffers from two limitations:
- Leads to lot of wastage of space
- Processing of 2-D array is tedious

Both disadvantages can be overcome using the array of pointers to strings. Array of pointers to strings suffers from the disadvantage that it always needs to be initialized, unless you decide to allocate space for each name dynamically using malloc( ) and then store the address in the array of pointers to strings.

What will be the output of the following program

main( )

{

static char *s[ ] = {

"ice",

"green",

"cone",

"please"

} ;

staic char **ptr[ ] = { s + 3 , s + 2 , s + 1 , s } ;

char ***p = ptr ;

printf ( "\n%s" , **++p ) ;

printf ( "\n%s" , *--*++p + 3 ) ;

printf ( "\n%s" , *p[-2] + 3 ) ;

printf ( "\n%s" , p[-1][-1] + 1 ) ;

}

Output:
cone
ase
reen

Explanation:
This time we seem to be faced with a galaxy of stars! We would do well to take the help of a figure 1. in crossing them one by one. At the outset, s[ ] has been declared and initialised as an array of pointers. Simply saying s gives us the base address of this array, 4006 as can be seen from Figure 1. ptr[ ] stores the addresses of the locations where the base addresses of strings comprising s[ ] have been stored, starting with the last string. To put it more clearly, ptr[0] stores the address 4012, which is the address at which base address of the string "please" is stored. Similarly, ptr[1] stores the address 4010, which is where the base address of the string "cone" is stored, and so on. Since ptr[ ] essentially stores addresses of addresses, it is a pointer to a pointer, and has been declared as such using ** .

Finally, the base address of ptr[ ] is assigned to a pointer to a pointer to a pointer, p. Reeling?! Going through the figure would decidedly aid you to get disentangled. Thus, p is assigned the address 6020.


Figure 1.

Having sorted out what is present where, we now proceed to the printf( ) s. Let us tackle the expressions one by one.

**++p

The first one prints out the string starting from the address **++p . The ++ goes to work first and increments p not to 6021, but to 6022. The C compiler has been made to understand that on incrementing a pointer variable, it is to point to the next location of its type. The words `of its type' hold significance here. A pointer to a char on incrementing goes one byte further, since a char is a 1-byte entity. A pointer to an int points 2 bytes further, as an int is a 2-byte entity. Also, a pointer by itself is always a 2-byte entity, so incrementing a pointer to a pointer would advance you by 2 bytes.

Having convinced ourselves that p now stores 6022, we go on to evaluate the expression further. *p signifies contents of 6022, i.e. 4010. **p means value at this address, i.e. value at 4010, which is the address 1010. The printf( ) prints the string at this address, which is "cone".

*--*++p + 3

p , presently contains 6022, which on incrementing becomes 6024. Value at this address is the address 4008, or in terms of s , s + 1 . On this the decrement operator -- works to give 4006, i.e. s . Value at 4006, or *( s ) is 1000. Thus the expression is now reduced to ( 1000 + 3 ), and what finally gets passed to printf( ) is the address 1003. Value at this address is a '\0', as at the end of every string a '\0' is inserted automatically. This '\0' is printed out as a blank by printf( ) .

*p[-2] + 3

The current address in p is 6024. *p[-2] can be thought of as *( *( p - 2 ) ) , as num[i] is same as *( num + i ) . This in turn evaluates as *( *( 6024 - 2 ) ) , i.e. *( *( 6020 ) ) , as p is a pointer to a pointer. This is equal to *( 4012 ) , as at 6020 the address 4012 is present. Value at 4012 is 1015, i.e. the base address of the fourth string, "please". Having reached the address of letter `p', 3 is added, which yields the address 1018. The string starting from 1018 is printed out, which comprises of the last three letters of "please", i.e. `ase'.

p[-1][-1] + 1

The above expression can be thought of as *( p[-1] - 1 ) + 1, as num[i] and *( num + i ) amounts to the same thing. Further, p[-1] can itself be simplified to *( p - 1 ) . Hence we can interpret the given expression as *( *( p - 1 ) - 1 ) + 1 . Now let us evaluate this expression.

After the execution of the third printf( ) , p still holds the address 6024. *( 6024 - 1 ) gives *( 6022 ) , i.e. address 4010. Therefore the expression now becomes *( 4010 - 1 ) + 1 . Looking at the figure you would agree that 4010 can be expressed as s + 2 . So now the expression becomes *( s + 2 - 1 ) + 1 or *( s + 1 ) + 1 . Once again the figure would confirm that *( s + 1 ) evaluates to *( 4008 ) and *( 4008 ) yields 1004, which is the base address of the second string "green". To this, 1 is added to yield the address of the first element, `r'. With this as the starting address, printf( ) prints out what is remaining of the string "green".

What will be the output of the following program

main( )

{

char str[ ] = "For your eyes only" ;

int i ;

char *p ;

for ( p = str, i = 0 ; p + i <<= str + strlen ( str ) ; p++, i++ )

printf ( "%c", *( p + i ) ) ;

}

Output
Fryu ysol

Explanation


Figure 2

The for loop here hosts two initialisations and two incrementations, which is perfectly acceptable. However, there must always be a unique test condition. In the initialisation part, p is assigned the base address of the string, and i is set to 0. Next the condition is tested. Let us isolate this condition for closer examination.

p + i <<= str + strlen ( str )

Since length of str[ ] is 18, str + strlen ( str ) would give the address of '\0' present at the end of the string. If we assume that the base address of the string is 4001, then the address of '\0' would be 4019. Since p has been assigned the base address of the string, in the first go, p + 0 would yield 4001. Since this is less than 4019, the condition holds good, and the character present at the address ( p + 0 ) , i.e. `F', is printed out. This can be understood better with the aid of the Figure 2. After this, both p and i are incremented, so that p contains 4002 and i contains 1, and once again the condition in the for loop is tested. This time ( p + i ) yields 4003, whereas the expression str + strlen ( str ) continues to yield 4019. Therefore again the condition is satisfied and the character at address 4003, i.e. `r' gets printed. Likewise, alternate elements of the string are outputted till i is 8, corresponding to which `l' is printed. Now, when p and i are incremented one more time, the test condition evaluates to:

p + i <<= str + strlen ( str )
4019 <<= 4019

The 18th element of str is of course the '\0', which is also printed out as a blank. On further incrementation of p and i , control snaps out of the for and the program execution is terminated.

0 comments: