16 April 2009

How to measure the size of a variable

Let us go through a small test to find out if this entire snippet is really worth reading. The test begins now.  We should complete it in 60 seconds!

Consider these  declarations in a code.

     char x, y, *p, **pp;
     char  *array[5], arr[5];
     char  *f(int), **g(int) ;

   struct node  a, b,* h(int); / * assume the size of node is 20 */

Then, what will be the values of the following?

1.    sizeof(x)
2.    sizeof(y)
3.    sizeof(*p)
4.    sizeof(p)
5.    sizeof(**pp)
6.    sizeof(*pp)
7.    sizeof(pp)
8.    sizeof(* array [0])
9.    sizeof(array[0])
10.   sizeof(arr [5] )
11.   sizeof(*f(5))
12.   sizeof(f(5))    /* is the size of a function?! */
13.   sizeof(**g(6))
14.   sizeof(*g(6))
15.   sizeof(g(6))
16.   sizeof(a)
17.   sizeof(*b)
18.   sizeof(b)
19.   sizeof(*h(5))
20.   sizeof(h(5))


Considering that size of char is 1 byte and pointers have a size of 4 bytes. Here  are the answers.

1.    1 byte
2.    1 byte
3.    1 byte
4.    4 bytes
5.    1 byte
6.    4 bytes
7.    4 bytes
8.    1 byte
9.    4 bytes
10.   1 byte
11.   1byte
12.   4 bytes
13.   1 byte
14.   4 bytes
15.   4 bytes
16.   20 bytes
17.   20 bytes
18.   4 bytes
19.   20 bytes
20.   4 bytes

We are almost sure; we got all the answers right, but did we beat the clock? Did we do it within 60 seconds?

Well! Here is how to get the measure on size really fast… For this we need to remember the following two things. 

First: refresh what we discussed in the “Moving the Stars” snippet. That virtual equal to sign helps a lot in getting the size right. Second: Any pointer of any type has the size 4 bytes (we are by default considering 32 bit machines. The pointer size can, of course, change with machines.)

Let us answer the questions we put earlier…

Question 1 and Answer:
     We have
      char x;

     Which can be read as
      char = x

     Therefore,
      sizeof(x) = sizeof(char) = 1

Question 2 and Answer:
     As above, the answer is again 1 byte

Question 3 and Answer:
     Given
      char *p;
     What is the sizeof(*p)?

     Because char = *p, therefore
      sizeof(*p)= sizeof(char) = 1

Question 4 and Answer:
     Given
      char  *p;
     What is the sizeof(p)?

     Because char *  = p, therefore,
      sizeof(p) = sizeof(char *) = 4

Question 5 and Answer:
     Given
      char **pp;
     What is the sizeof (**pp)?

     Because char = **pp, therefore
      sizeof (**pp) = sizeof (char) = 1

Question 6 and Answer:
     Given,
      char **pp;
      What is the  sizeof(*pp)?

     Because char * =*pp, therefore
      sizeof(*pp) = sizeof(char *) = 4

Question 7 and Answer:
     Given,
      char **pp,
     What is the sizeof (pp)?

     Because char ** = p, therefore
      sizeof(p) = sizeof(char **) = 4


Question 8 is interesting, because we are apparently trying to find the size of a function, which is unusual. But we can compute the size of functions. However what it means is the size of its return values.

Let us take up Question 8 and Answer:

     Given char * f(int); what is sizeof(*f(5));

     Because char = * f(int), therefore
      sizeof (* f(5)) = sizeof(char) = 1


Question 9 and Answer:

     Given  char *f(int) what is  sizeof(f(5))?

     Because  char * = f(int), therefore       sizeof (f(5)) = sizeof(char *) = 4.


Now that we know what we mean by size of a function, the remaining questions should be easy to answer quickly. Let's do it to be sure. This trick works with any C/C++ declarations.

By the way, why do we need to know the size of any variable correctly, the answer is to malloc correctly to get the correct amount of memory. If we give a wrong size for memory allocation, chances are that we will take days
to find out why the program misbehaves in strange ways.

This 
snippet has helped to explain in detail the aspects of sizeof.

04 April 2009

Refresh your Pointers knowledge

This little piece of literature will let us prevent a category of defects related to pointers. But first, let us take a small test. It will help us to decide if the entire snippet  is really worth reading. So here are the questions.

Consider, following are some of the declarations in a piece of code.
     int x , y, *p, **pp ;
   int *array[5], arr[5];
   int *f(int), **g(int);


Now, for which of the following eight statements the compiler will complain and for which it will not complain?
Let us try the test; check if we can hit it right in less than sixty seconds!
1.    x = y;
2.    *p = array [0];
3.    *p = **pp;
4.    x = f (4);
5.    p = *g (3);
6.    array [0] = arr[0];
7.    arr [0] = * array [1];
8.    array [5] = **g (3);


Here are the answers. For all odd number statements 1,3,5… .. the compiler will not complain.
For all even number statements 2,4,6… . The compiler will complain.

Let us now figure out quickly some of the mistakes we saw earlier. The way to find  what works and what does not, is rather simple. That is because, we can consider a C/C++ declarations as an equation with an “=” sign, across which you can move the stars!

Let's hold on! We will see what we meant above

Let us consider the declaration  int * x;

Let's imagine an "equal to" sign in between as follows

     int = * x ; /* this one tells you that *x is int */

We can move the star across the “=” sign, as shown here:

     int * = x ; /* this one tells that x is an integer pointer or a
pointer to an integer*/


One more example will make things clearer.

     int ** y

Let's imagine it as:

     int = **y   (this means  **y is an integer).


After moving one star across:

     int * = *y ( this means that *y is an integer pointer).

After moving one more star across:
     int ** = y,  this means that y is an integer pointer pointer.



Now , let us combine the above two examples
      In the first example we saw  *x  is an integer
     In the second example we saw that  **y  is also an integer.

So, the compiler will not complain, if we write
     *x = **y
          or
     **y = *x

Similarly,
     x = * y   is also ok with the compiler because both the sides are
int *.

By now we have seen, how to quickly find what will work and what will not work by  MOVING THE STARS!
It is a good idea to have a look at the declarations for minimizing related defects.

Let us go back to the quiz questions we discussed earlier. We will go through the answers quickly by using this  MOVING THE STARS! method.

We have copied and pasted the declarations over here for easy reference:
     int x , y, *p, **pp ;
     int *array[5], arr[5];
     int *f(int), **g(int);

1.    x = y  is correct, because both sides are int
2.    *p = array [0] is wrong, because LHS is int but RHS is  int *
3.    *p = **pp    is correct because both sides are int.
4.    x = f (4) is wrong because LHS is  int and RHS is int *.
5.    p= *g (3) is correct because both sides are int *
6.    array [0] = arr [0] is wrong because LHS is int *  but RHS is  int.
7.    arr [0] = * array [1]   is correct, because both sides are  int.
8.    array [5] = ** g (3) is wrong, because LHS is  int*  while RHS is int.


Experience shows that regularly using this little trick helps in writing as well as reading code faster.
Of course, it also helps us in reducing mistakes.