0

I'm trying to become "a real man", aka moving from C++ to C. Pointers and malloc get confusing at times. I'm using gcc without any flags, 64 bit linux.

So my first question is:

int* c;
int* d;
void* shared = malloc(sizeof(int)*2);
c = shared;
d = shared + sizeof(int);
*c = 123;
*d = 321;

printf("c: %p, *c: %i\n", (void*)c, *c);
printf("d: %p, *d: %i\n", (void*)d, *d);
printf("sizeof(c): %lu, sizeof(d): %lu\n", sizeof(c), sizeof(d));

outputs: c: 0x1c97050, *c: 123 d: 0x1c97054, *d: 321 sizeof(c): 8, sizeof(d): 8

Converting the two memory addresses to decimal and checking their difference gives 4. Meaning they are 4 bytes away from each other in the memory? So that means int is represented on 4 bytes, sizeof(int) = 4.

But a pointer (of any kind I guess but in our case to an int) is represented on 8 bytes, due the 64bit memory? Meaning I made a mistake by mallocing only 4 bytes instead of the required 8 bytes (int instead of int*).

But then how come I am not losing any data? Pure coincidence/luck?

Mark Rowra
  • 49
  • 1
  • 1
  • Feel free to use pointers in C++ as well -- they work exactly the same way. – Ben Voigt Aug 28 '15 at 17:04
  • I don't see a real question here. `sizeof(d)` is 8. – Eugene Sh. Aug 28 '15 at 17:04
  • why are you thinking you are losing data? what data are you losing? – user3528438 Aug 28 '15 at 17:04
  • 2
    You've stored two ints in the space of two ints, of course you can do that – harold Aug 28 '15 at 17:05
  • 3
    You know there is a difference between a pointer and the object it **points to**? – too honest for this site Aug 28 '15 at 17:07
  • And adding/subtracting anything to `void *` is UB – user3528438 Aug 28 '15 at 17:07
  • @user3528438: Right, but the compiler should actually complain. So OP seems either to ignore the warning/error or he did not even enable such basic warnings. – too honest for this site Aug 28 '15 at 17:09
  • @Olaf I did more research and it turns well defined as a GCC extension. – user3528438 Aug 28 '15 at 17:10
  • 1
    @user3528438: Not in standard-compliance mode. Actually, the standard doe not allow operations on `void *` and I think this is one of the more negative extensions of gcc just to safe some casts to `char *`. However, if not asked explicitly, one should assume standard-compliance. – too honest for this site Aug 28 '15 at 17:13
  • The 4-byte difference you're seeing is the difference between the values (addresses) *stored in* the pointers -- it's not the difference between the addresses of the pointers themselves. – Dmitri Aug 28 '15 at 17:13
  • @Olfaf the compiler is not complaining because it is probably `gcc` which by default is compiling GNU C. – ouah Aug 28 '15 at 17:14
  • @likely, but not explcitly stated. Hmm, as you say now... I wonder if there is a way to disable this questionable "feature" but keep others enabled. Anyway, OP really should not use `void *` here. Why does he hate his compiler that much? – too honest for this site Aug 28 '15 at 17:19
  • `shared + sizeof(int);` is a constraint violation. You should get a diagnostic message. In ISO C you cannot perform arithmetic on `void *` . Some compilers have an extension to convert it to `(void *)((char *)shared + sizeof(int))` – M.M Aug 29 '15 at 03:42
  • [use `%zu` to print the result of `sizeof`](https://stackoverflow.com/q/940087/995714). using the wrong format specifier is UB – phuclv Apr 29 '18 at 12:24

4 Answers4

6

The storage taken up by your pointer objects (c and d) is not related to the storage taken up by your data (the objects those pointers point to).

Here's a hypothetical memory map showing how those values could be laid out (addresses for c and d made up out of thin air, assumes big-endian layout):

  Item            Address                0x01  0x02  0x03  0x04
  ----            -------                ----  ----  ----  ----
shared            0x0000000001c97050       00    00    00    7b
                  0x0000000001c97054       00    00    01    41
                  ...    
     c            0x000000fffff86400       00    00    00    00
                  0x000000fffff86404       01    c9    70    50
     d            0x000000fffff86408       00    00    00    00
                  0x000000fffff8640c       01    c9    70    54

In your malloc call, you allocated space to store 2 int objects, each of which takes up 4 bytes. The first element of shared, which lives at address 0x0000000001c97050, stores the 4-byte value 123, and the second element which lives at address 0x0000000001c97054 stores the 4-byte value 321.

The pointer c, which lives at address 0x000000fffff86400, stores the 8-byte address of the first element of shared, which is 0x0000000001c97050. Similarly, the pointer d, which lives at address 0x000000fffff86408, stores the address of the second element of shared, which is 0x0000000001c97054.

TL;DR - you allocated the right amount of memory for your data, which is what matters.

Gratuitous Rant

I'm trying to become "a real man", aka moving from C++ to C

Learning C doesn't make you manly; it makes you someone who knows C. There's a lot of bad mythology that's built up around the C language, C programming, and C programmers. Yes, its low-level abstractions force you to be on your toes at all times, but that doesn't make you manly, it just makes you paranoid. C's the right tool for a fairly narrow application domain (systems programming, non-graphical server-side processing, etc.), but for general applications programming, it's been eclipsed by languages that are far easier to use.

Besides, Real Programmers use Fortran.

John Bode
  • 119,563
  • 19
  • 122
  • 198
1

You malloc enough space for the datatype you store there, which is (32-bit) int. That's fine.

The result is a 64-bit address, stored in c and/or d, and that takes 8 bytes sizeof(c). The compiler allocated the storage (more properly, arranged for the allocation to occur at runtime) for c and d for you when you declared them, and it was smart enough to provide sizeof(int*) for those two variables. You didn't cause a problem in the memory layout of c and d, because your malloc call doesn't affect the layout of variables declared in your code.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
1

The difference between the two int * gives the size of an int not the size of an int *. The size of an int * is 8 in your system.

To print the size of an int * you have to do:

 printf("%zu\n", sizeof (int *));

which is more or less what you did in your example and that displays the value 8.

ouah
  • 142,963
  • 15
  • 272
  • 331
0

There is no overlapping in your memory allocation, thats why you are not loosing data, if you want to realise data loose scenario then try this. here *c is pointer to long and *d is pointer to int

void main()
{

  long int *c;
  int *d;
  void *shared = malloc(sizeof(int)*2);
  c= shared;
  d= shared + sizeof(int);

  printf("size of int in this machine = %d\n",sizeof(int));
  printf("size of long in this machine = %d\n",sizeof(long));

  *d = 0xCDCDCDCD;
  *c = 0xABABABABABAB;

  printf("c: %p, *c: %x\n", (void*)c, *c);
  printf("d: %p, *d: %x\n", (void*)d, *d);
  printf("sizeof(c): %lu, sizeof(d): %lu\n", sizeof(c),sizeof(d));
}

here *c=0xABABABABABAB will enter inside memory of *d and erase value there.

Output:

size of int in this machine = 4
size of long in this machine = 8
c: 0x7feb81c04ac0, *c: abababab
d: 0x7feb81c04ac4, *d: abab
sizeof(c): 8, sizeof(d): 8
logonmanish
  • 124
  • 1
  • 7