Monday, October 29, 2007

Interesting C Program -18

Hi all,
Observe the output of the following program.


#include "stdio.h"
#define DPRINTI(X) printf("\n%s = %d \n",#X,X)
#define DPRINTF(X) printf("\n%s = %f\n",#X,X)
#define DPRINTC(X) printf("\n%s = %c\n",#X,X)
int main()
{
double x = 100.1;
int y = 5;
char z = 'a';
void *p;

p = &z;
DPRINTI(sizeof(*(char *)p));
DPRINTC(*(char *)p);
DPRINTI(p);

p = &y;
DPRINTI(sizeof(*(int *)p));
DPRINTI(*(int *)p);
DPRINTI(p);

p = &x;
DPRINTI(sizeof(*(double *)p));
DPRINTF(*(double *)p);
DPRINTI(p);

return 0;
}


The output is something like the following:


sizeof(*(char *)p) = 1

*(char *)p = a

p = 2293635

sizeof(*(int *)p) = 4

*(int *)p = 5

p = 2293636

sizeof(*(float *)p) = 8

*(double *)p = 100.100000

p = 2293640



Explanation goes like this.

Initially a pointer has been initialized of type void * (generic pointer). We are type casting that pointer p to point a location in which a character is stored. Then we are typecasting that pointer p to point a location in which an integer is stored. Later, we are again type casting that pointer p to point a location in which a float is stored. This program runs without any errors.
The character variable is stored in 2293635 location (Size is 1 byte), ie 2293635.
The Integer variable is stored in 2293636 location (Size is 4 bytes), ie 2293636, 2293637, 2293638 and 2293639.
The Float variable is stored in 2293640 location (Size is 8 bytes), ie 2293640, 2293641, 2293642, 2293643, 2293644, 2293645, 2293646 and 2293647.
Every thing seems simple.

Hey wait wait. How can Life be so simple?

Lets see what happens when the following code is executed?


#include "stdio.h"
#define DPRINTI(X) printf("\n%s = %d \n",#X,X)
#define DPRINTF(X) printf("\n%s = %f\n",#X,X)
#define DPRINTC(X) printf("\n%s = %c\n",#X,X)
int main()
{
double x = 100.1;
int y = 5;
char z = 'a';
void *p;

p = &x;
DPRINTI(sizeof(*(double *)p));
DPRINTF(*(double *)p);
DPRINTI(p);

p = &y;
DPRINTI(sizeof(*(int *)p));
DPRINTI(*(int *)p);
DPRINTI(p);

p = &z;
DPRINTI(sizeof(*(char *)p));
DPRINTC(*(char *)p);
DPRINTI(p);

return 0;
}

The output is something like this:


The output is something like the following:


sizeof(*(float *)p) = 8

*(double *)p = 100.100000

p = 2293640

sizeof(*(int *)p) = 4

*(int *)p = 5

p = 2293636

sizeof(*(char *)p) = 1

*(char *)p = a

p = 2293635



Dont you see something weird in the output?

The addresses of float, int, and char should be respectively,2293635, 2293643 and 2293647. ie. the starting address should be 2293635. From there float occupies 8 bytes. The next 4 bytes is occupied by Integer (2293643, 2293644,2293645 and 2293646 and the next 1 byte is occupied by character variable, which is 2293647.
But that is not happening.

Can anybody comment me with the reason for that?

4 comments:

srsasi said...

Nice explanation. I encountered the same problem. I have a doubt. Whats the use of allowing the typecasting of different type of pointers when it is not going to work :-/ ?

Balaji V said...

I am sorry for writing a wrong code instead of the intended.

srsasi said...

Memory for a variable is created when it is defined, not when it is referenced. Irrespective of ur pointer type, memory will be created well before assigning the pointer say float pointer to void pointer in ur code.

Balaji V said...

Thanks for sharing the knowledge with me.

Search Google

Books that I refer to...

  • The Complete Reference C, Fourth Edition
  • The C Programming Language