Pointer row addresses have unexpected numbers

M

Malcolm Nooning

I can see that in the pasted results of the code snippet (also pasted
below), there are 48 decimal bytes between rows of an array. The
coded subtraction of row addresses is showing 12 instead of 48. I
cannot figure out why. I see the same result on my Windows cygwin and
my Linux CentOS boxes. Any idea what is going on?

//----------- Paste code snippet
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int nrows = 5; /* Both nrows and ncols could be evaluated */
int ncols = 10; /* or read in at run time */
int row;
int **rowptr;

rowptr = malloc(nrows * sizeof(int *));

if (rowptr == NULL)
{
puts("\nFailure to allocate room for row pointers.\n");
exit(0);
}

printf("\nIndex &rowptr[row] &rowptr[row][0] Ptr(hex) Ptr(dec)
Diff(dec)");

for (row = 0; row < nrows; row++)
{
rowptr[row] = malloc(ncols * sizeof(int));
if (rowptr[row] == NULL)
{
printf("\nFailure to allocate for row[%d]\n",row);
exit(0);
}
printf("\n %d %u %u %p %d",
row, &rowptr[row], &rowptr[row][0], rowptr[row],
rowptr[row] );
if (row > 0)
printf(" %d",(int)(rowptr[row] - rowptr[row-1]));
}

return 0;
}
//-----------------------------------------
// Results
//
// Index &rowptr[row] &rowptr[row][0] Ptr(hex) Ptr(dec) Diff(dec)
// 0 6685048 6750616 0x670198 6750616
// 1 6685052 6750664 0x6701c8 6750664 12
// 2 6685056 6750712 0x6701f8 6750712 12
// 3 6685060 6750760 0x670228 6750760 12
// 4 6685064 6750808 0x670258 6750808 12
 
N

Nobody

I can see that in the pasted results of the code snippet (also pasted
below), there are 48 decimal bytes between rows of an array. The
coded subtraction of row addresses is showing 12 instead of 48. I
cannot figure out why. I see the same result on my Windows cygwin and
my Linux CentOS boxes. Any idea what is going on?

The result of subtracting two pointers is the number of *elements* between
the pointers, not the number of bytes. 12 integers is 48 bytes.
 
M

Morris Keesan

I can see that in the pasted results of the code snippet (also pasted
below), there are 48 decimal bytes between rows of an array. The
coded subtraction of row addresses is showing 12 instead of 48.

And without looking at any of your code, I can tell you that you're
subtracting pointers, and that
sizeof(whatever type the pointers point to) == 4.
 
M

Malcolm Nooning

The result of subtracting two pointers is the number of *elements* between
the pointers, not the number of bytes. 12 integers is 48 bytes.

But, there are 10 integers (int ncols = 10) per row, not 12.
Where do the extra two come from?
 
M

Malcolm Nooning

Probably housekeeping space used by the allocator.

No, that cannot be.
The C books tell us that whenever two pointers are subtracted we get
the number of the elements between what they point to. This is the
gist of what "Nobody", and Morris Keesan, were stating above.
However, just going by that, the answers should all be 10, not 12. A
programmer would need to rely on the results of pointer subtraction
being well defined. There is something else going on, and I would
really like to get a solid understanding of what it is.
 
I

Ian Collins

No, that cannot be.

Oh yes it can!
The C books tell us that whenever two pointers are subtracted we get
the number of the elements between what they point to.

To pointers within the same object. Your rowptr[row] and rowptr[row-1]
are the results of different allocations.
A
programmer would need to rely on the results of pointer subtraction
being well defined.

It is....
There is something else going on, and I would
really like to get a solid understanding of what it is.

....but not between pointers in different blocks.
 
W

Willem

Malcolm Nooning wrote:
)> Probably housekeeping space used by the allocator.
)
) No, that cannot be.
) The C books tell us that whenever two pointers are subtracted we get
) the number of the elements between what they point to. This is the
) gist of what "Nobody", and Morris Keesan, were stating above.
) However, just going by that, the answers should all be 10, not 12. A
) programmer would need to rely on the results of pointer subtraction
) being well defined. There is something else going on, and I would
) really like to get a solid understanding of what it is.

It's really very easy.
You're comparing the results of *different calls* to malloc().
The books are talking about *one* array or block.
You're comparing apples and oranges.

The standard sais that comparing pointers that point into two different
objects (i.e. two different calls to malloc(), or two static arrays,
or whatever), gives undefined results.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
M

Malcolm Nooning

No, that cannot be.

Oh yes it can!
The C books tell us that whenever two pointers are subtracted we get
the number of the elements between what they point to.

To pointers within the same object.  Your rowptr[row] and rowptr[row-1]
are the results of different allocations.
A
programmer would need to rely on the results of pointer subtraction
being well defined.

It is....
There is something else going on, and I would
really like to get a solid understanding of what it is.

...but not between pointers in different blocks.

Aha! That is the answer. To be explicit for those as dull as myself,
in the snippet below
rowptr[0] = malloc(ncols * sizeof(int));
The contents of rowptr[0] is a pointer to 10 integers.
The contents of rowptr[1] is also pointer to 10 integers, but that
pointer could be pointing anywhere the compiler found free memory for
it, which is not necessarily contiguous with that of rowptr[0]. Thus,
there is no "right" answer for the subtraction (int)(rowptr[row] -
rowptr[row-1]). It does not even have to be consistent. It just
happened to be 12 consistently because the compiler found contiguously
free memory each malloc. The other 2 elements might be housekeeping,
but it might be for absolutely nothing. My gcc has been around for 20
years, so I suppose it is pretty efficient by now. It is undoubtedly
for housekeeping.

Thanks, Ian
 
K

Keith Thompson

Nobody said:
The result of subtracting two pointers is the number of *elements* between
the pointers, not the number of bytes. 12 integers is 48 bytes.

Furthermore, the behavior of subtracting two pointers to separately
allocated objects (which is what the program in the original post
does) is undefined.
 
B

Barry Schwarz

But, there are 10 integers (int ncols = 10) per row, not 12.
Where do the extra two come from?

Firstly, there is no requirement for the results of separate calls to
malloc to be in any order. The fact that they are 48 bytes apart is
just an artifact of your particular implementation.

Secondly, the first call to printf in the for loop invokes undefined
behavior so none of the results can be trusted.

Thirdly, if malloc succeeds it must allocate at least as much space as
you asked for but it can allocate more and use the excess to contain
control information (such as the amount of space to free). I expect
on your system the eight bytes in front of the returned value are
used for this or a similar purpose.

What I do find a little surprising is that rowptr[0] contains a value
over 0x10000 away from &rowptr[4]. Given that all five elements of
rowptr contain addresses close to each other, I would have expected
these five areas to follow closely after rowptr in memory. It's
almost as if the first call to printf allocated (and freed) some
temporary space and it is not being reused.

Of course, &rowptr[row][0] and rowptr[row] must always be the same
value, even if you choose to print it in two different bases.
 
N

Nobody

But, there are 10 integers (int ncols = 10) per row, not 12.
Where do the extra two come from?

That's a different issue.

Subtraction of pointers is only defined when both pointers point within
the same array (or to the element immediately past the end of the array),
so your code provokes undefined behaviour.

The reason why it happens in this specific case is that glibc's malloc()
always returns a pointer aligned to a 16-byte boundary, so it's not
possible for two pointers returned from malloc() to differ by 40 bytes.

If your array elements had been structures whose size wasn't either a
multiple or fraction of 16, the difference (in bytes) between the
two pointers wouldn't necessarily have been a multiple of the
structure's size, so the result of the subtraction would be meaningless.

The C standard only requires that pointers returned from malloc() meet the
largest alignment requirements for any standard type. glibc just happens
to be a bit more conservative (16 bytes is likely to satisfy the
standard's requirement on any platform which is likely to exist within the
foreseeable future).

If you have larger alignment requirements (e.g. for SIMD calculations or
page-aligned blocks), you have to either use an alternative (and
non-portable) allocation mechanism or over-allocate and extract a suitably
aligned region yourself.
 
S

Skybuck Flying

My god,

Are you saying you have been programming in C for over 20 years and only now
do you understand a pointer array ?

Wow... just wow lol.

Bye,
Skybuck.
 
S

Skybuck Flying

Nobody said:
The result of subtracting two pointers is the number of *elements* between
the pointers, not the number of bytes. 12 integers is 48 bytes.

What a bullshit.

But then again the C language is bullshit.

So what you are saying is you are either wrong, or you are incomplete.

It turns out you are not wrong, it turns out you are incomplete.

The correct answer is it depends on the pointer TYPE. So C is no different
than typed pointers in pascal. Except only difference is pascal pointers do
not allow pointer arithmetic by default. Also subtracting pointers in
pascal/delphi not possible.Unless perhaps a compiler directive is used the
new pointer math directive... which probably means pointers are treated as
memory addresses which are simply integers pointing towards the smallest
addressable element in virtual memory which in PC's is a byte.

Long story short your bullshit was interesting in another way.

// int *vA;
// int *vB;

void *vA;
void *vB;

vA = &vArray[3];
vB = &vArray[4];

printf("%d \n", vB - vA);


It turns out C can't even do pointer arithemtic like Delphi can.

For such a powerfull language "as they used to claim C was" back in the old
ms-dos days it has fallen in grace... if it ever had such a thing.

All this time I was actually under the impression that C could do pointer
arithmetic but apperently it cannot.

The only thing it can apperently do is treat a typed pointer as an array...
big fokking whoopie.

Not being able to use untyped pointers for simply virtual memory byte
arithmetic is absolutely beyond me ! hahahaha... yes yes insert your nagging
"most be cross-platform compatible" BS.

Let me know when you try to compile code that was written for a byte based
memory system which is then used for something else like a 7 bit system.

Though I can imagine it might work... never seen it though. So perhaps this
little part of the rant don't hold, but yet it might.

I just like to point out to everybody that Delphi is now actually more
powerfull than C at the pointer area !

An area where C is famous for...

Now go eat your hart out ! ;)

I will stop now before your heart explodes of anger ! ;) =D

Haha,
Bye,
Skybuck ;) :)
 
S

Skybuck Flying

Hmmm... not having used the new directive much yet... I still don't know
what it can quite do...

It appears I was wrong and the people at embarc keep head in ass:

program Project1;

{$APPTYPE CONSOLE}

{$POINTERMATH ON}

uses
SysUtils;

procedure Main;
var
vArray : array[0..9] of integer;
vA : pointer;
vB : pointer;
vC : pointer;
begin
vA := @vArray[4];
vB := @vArray[5];
vC := vB - vA; // does not compile.

writeln( integer(vC) );
end;

begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
ReadLn;
end.

Pretty annoying.

Oh well... me crawl back into my Delphi cave.

Pretend like nothing happened, because that's exactly what happened.

Ok not quite true...

At least now Delphi can work with typed pointers unlike these untyped
pointers above...

I am so sure of it... I am not even going to test it ?!

Noooo ofcourse I am going to test it lol:

Fucking unbelievable... even this **** doesn't compile:

procedure Main;
var
vArray : array[0..9] of integer;
vA : pointer;
vB : pointer;
vC : pointer;

vFuckYouBitchesA : Pbyte;
vFuckYouBitchesB : Pbyte;
vFuckYouBitchesC : Pbyte;
begin
vA := @vArray[4];
vB := @vArray[5];
// vC := vB - vA;

writeln( integer(vC) );


vFuckYouBitchesA := @vArray[4];
vFuckYouBitchesB := @vArray[5];
vFuckYouBitchesC := vFuckYouBitchesB - vFuckYouBitchesA;

writeln( integer(vC) );

end;

**** the bitches at embarcadero... for making my live more difficult than
absolutely need to be.

Well at least we still have strong type checking.

I take back everything I said about C.

C can still go **** people like you guys in the ASS... haha.

Someday Delphi will be what it should be...

Someday...

Bye,
Skybuck.
 
S

Skybuck Flying

I hate fags that say an untyped pointer points to nothing.

It's even in the Delphi help:

"
This directive affects only typed pointers. Variables of type Pointer do not
allow the pointer math features, since type Pointer is effectively pointing
to a void element, which is 0 bytes in size. Untyped var or const parameters
are not affected because they are not really pointers.
"

Like a pointer can point to nothing and something at the same time...

It's absolutely rubbish.

Keep C rubbish out of Delphi me says.

Bye,
Skybuck.
 
S

Skybuck Flying

I shall give a better definition of what an untyped pointer should be in
Delphi:

"An untyped pointer is a pointer that points to the basic allocation unit of
the memory system."

That might sound a bit too technically related to memory manager, though
that too plays a roll in the background.

Though it's probably suited.

It could be augmented by a different view of a pointer because it can be
looked upon from different perspectives:

"An untyped pointer contains an address which range corresponds to the range
of the memory system."

Also not completely through, virtual memory has 2 GB usually available.
Yet the pointer is 32 bit... but that last bit can be ignored and is not
important.

Pointers could be said to be 31 bit, which is important to understand it's
range in this specific memory system case: 2^31

Try three:

"An untyped pointer is the basic pointer type which allows to address each
individual element of the memory system."

I think that last one nails it on the head.

Bye,
Skybuck.
 
S

Skybuck Flying

Malcolm Nooning said:
I can see that in the pasted results of the code snippet (also pasted
below), there are 48 decimal bytes between rows of an array. The
coded subtraction of row addresses is showing 12 instead of 48. I
cannot figure out why. I see the same result on my Windows cygwin and
my Linux CentOS boxes. Any idea what is going on?

//----------- Paste code snippet
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int nrows = 5; /* Both nrows and ncols could be evaluated */
int ncols = 10; /* or read in at run time */
int row;
int **rowptr;


Your naming convention also sucks pretty bad.

This should have been
rowptrptr

which might have alerted you to your stupidity.

Or better Delphi/Skybuck style:

PointerArrayPointerArray[6] - PointerArrayPointerArray[5]

If this doesn't trigger any bells when you wrote that BS code then I don't
know what will in your shit-code-case ! ;) :)

OH WAITTT I guess that's why Delphi has multi dimensional array support
which C doesn't have OOOOPPPSSIIEE I guess C is old-fart-news after all.

vPointer : array of array of pointer;

SetLength( vPointer, 10, 10 );

Now trying to make stupid mistake that you do:

vPointer[6] - vPointer[5];

Hey mister where is that second dimension ?!

Well ofcourse here it is:

vPointer[6,0] fuckyou vPointer[5,0]

Even better:

@vPointer[6,0] fuckyou @vPointer[5,0]

Always nice.

Of course you code style is bullshit anyway because any normal sane delphi
programmer would write:

vInteger : array of array of integer;

vInteger[6,0] - vInteger[5,0]

See how nice Delphi is ?!?

And how stupid your C is with all that RIDICILOUS DUMB PTR crap ! ;) :)

LOLOLOLOLOL

I LOL IN YOUR FACE ;) :) =D

Bye,
Skybuck.
 
S

Skybuck Flying

Sorry forgot to own you in Delphi newsgroup as well.

And when I say "you" I mean all C programmers and C language designers
HAHAHAHA LOL. With a little thanks to embarc.. (and others pasc.)

Repost:

Malcolm Nooning said:
I can see that in the pasted results of the code snippet (also pasted
below), there are 48 decimal bytes between rows of an array. The
coded subtraction of row addresses is showing 12 instead of 48. I
cannot figure out why. I see the same result on my Windows cygwin and
my Linux CentOS boxes. Any idea what is going on?

//----------- Paste code snippet
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int nrows = 5; /* Both nrows and ncols could be evaluated */
int ncols = 10; /* or read in at run time */
int row;
int **rowptr;


Your naming convention also sucks pretty bad.

This should have been
rowptrptr

which might have alerted you to your stupidity.

Or better Delphi/Skybuck style:

PointerArrayPointerArray[6] - PointerArrayPointerArray[5]

If this doesn't trigger any bells when you wrote that BS code then I don't
know what will in your shit-code-case ! ;) :)

OH WAITTT I guess that's why Delphi has multi dimensional array support
which C doesn't have OOOOPPPSSIIEE I guess C is old-fart-news after all.

vPointer : array of array of pointer;

SetLength( vPointer, 10, 10 );

Now trying to make stupid mistake that you do:

vPointer[6] - vPointer[5];

Hey mister where is that second dimension ?!

Well ofcourse here it is:

vPointer[6,0] fuckyou vPointer[5,0]

Even better:

@vPointer[6,0] fuckyou @vPointer[5,0]

Always nice.

Of course you code style is bullshit anyway because any normal sane delphi
programmer would write:

vInteger : array of array of integer;

vInteger[6,0] - vInteger[5,0]

See how nice Delphi is ?!?

And how stupid your C is with all that RIDICILOUS DUMB PTR crap ! ;) :)

LOLOLOLOLOL

I LOL IN YOUR FACE ;) :) =D

Bye,
Skybuck.
 
M

Malcolm Nooning

My god,

Are you saying you have been programming in C for over 20 years and only now
do you understand a pointer array ?

Wow... just wow lol.

Bye,
  Skybuck.

You misinterpreted. I am saying that gcc has been around for 20 years.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top