Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointers pointing to invalid location

Tags:

c

pointers

#include <stdio.h>

int main(void)
{ 
   int x = 1000;
   char *ptr = &x;
   printf("%d\n",*ptr);
   return 0;
 }

Output: -24 /*In gcc 4.4.3 in Ubuntu 10.04 OS*/ With a warning: initialization from incompatible pointer type

What I think if the base type of the pointer were of int type then it would have retrieved 4 bytes from the location it's pointing.Then the O/P would have been 1000.But as I changed the base type to char then it would retrieve 1 byte from location it's pointing when I dereference it.But how the answer is -24. Again when I changed the program as below

#include <stdio.h>

    int main(void)
    { 
       int x = 1000;
       float *ptr = &x;
       printf("%f\n",*ptr);
       return 0;
     }

The output becomes 0.000000 with same warning.when I derefence the pointer it would retrieve 4 bytes from the location it's pointing.But how the O/P is 0.000000.I'm bit confused.Can u guys plz explain it.I new in C programming, so any mistake in asking the question, plz forgive me. Thanx

like image 424
Parikshita Avatar asked Jul 23 '26 07:07

Parikshita


2 Answers

Dereferencing a character pointer got you the first character-sized chunk of the internal representation of 1000 as an integer. That character was then promoted to a int (as per the rules for varidac arguments), and interpreted as integer.

On you machine, with that compiler, the result was -24.

Character sized chunk was probably a 8-bit byte.

The integer was probably represented by 4 or 8 of those bytes.

The internal representation was probably 2s-complement, and was probably stored in little endian order.

Do you begin to see why the result wasn't easy for you to predict?


Doing the same thing with a float pointer returned a float sized chuck of memory instead of a char, and now you may have real (heh!) trouble because we don't know, at this point if the float representation will even fit in a int representation, so you may be accessing uninitialized memory.

In any case, when you dereferenced the float* it interpreted that memory as float (which has a rather more complex internal structure than a character or even a 2s-complement integer), and promoted it to a double (those rules for varidac arguments again) then an attempt was made interpret that representation as an integer (and if the float did fit in an int, the double probably doesn't, so you're interpreting part of the double as an int!). Ugh.

This situation is even worse than the last because it involves the IEEE floating point representation standards and two chances to have the sizes not match up at all.

So the lesson here is:

Don't do that.

And the subsidiary lesson, only for experts is

Still don't do it.

because if you want to perform all these silly reinterpretations you want to have exact and explicit control of them.

like image 100
dmckee --- ex-moderator kitten Avatar answered Jul 26 '26 01:07

dmckee --- ex-moderator kitten


1000 in hex is 0x3E8. If your system stores an int as a little-endian 32-bit value, then x is stored like this in memory:

+------+------+------+------+
| 0xE8 | 0x03 | 0x00 | 0x00 |
+------+------+------+------+
    ^
    |      ---increasing addresses--->
   &x

For the first case:

If your system has an 8-bit char, when you assign &x to char *ptr and then dereference it, you get the value 0xE8 interpreted as a char.

If your system treats the char type as signed, and if the signed representation is 2's complement, then 0xE8 is interpreted as -24.

For the second case:

If your system has a little-endian 32-bit float, when you assign &x to float *ptr and then dereference it, you get the value with a bit pattern of 0x000003E8 interpreted as float.

If your system represents float in the IEEE 754 format, then the most significant bit represents the sign (0 means it's positive), the next 8 most significant bits represents the exponent (0 means that the number is zero or denormalized - very small), and the remaining 23 bits represent the "significand" or "mantissa" (0x3E8 or 1000). This actually has the value 1000 * 2-149, which is approximately 1.4013 * 10-42 - you can see this value by using %g instead of %f in the printf format string.

like image 31
Matthew Slattery Avatar answered Jul 26 '26 03:07

Matthew Slattery



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!