# Annoyances with pointer offsets.

This topic is 4614 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

As part of my DIB implementation, I'm reminded of this little annoyance.
int luiMain[2];

luiMain[0] = 10;
luiMain[1] = 10;

*(&luiMain[0] + 1) == luiMain[1]


In order to add 1 byte, instead of 4 bytes, you gotta cast it...
#include <stdio.h>
void main()
{
int *laiMain;
int luiX;
laiMain = malloc(4*5);
laiMain[0] = 1;
laiMain[1] = 5;
laiMain[2] = 10;
laiMain[3] = 15;
laiMain[4] = 20;

for(luiX=0;luiX<=8;luiX++) printf("laiMain[%d]=%d\n", luiX, *(((char *)&laiMain[0]) + luiX));
}


Anyone know a way to disable this? lol, why did they decide on this?! It really doesn't help at all! [Edited by - Thevenin on July 4, 2005 8:41:48 PM]

##### Share on other sites
Looks like you're trying to inspect individual bytes within each int.

Do you use/understand hex? If so... why not use this instead?

	int luiX;	laiMain[] = { 1, 5, 10, 15, 20 };        for(luiX = 0; luiX < sizeof(laiMain); luiX++)             printf("laiMain[%d]=%.8X\n", luiX, &laiMain[luiX]);

Seems like that would be the simplest way to inspect bytes (in groups of four)

I'm at a loss as to why you need to iterate through the array of ints one byte at a time, though [smile]

##### Share on other sites
The need arose because I went and did this...

void *Surface = [int][int][struct loRGB][struct loRGB][struct loRGB]...

The first two ints are the width and height, and the rest (Roughly 250k) are all RGB structs.

Inaddition, instead of calling it a void, I went and called it...

struct tRGB *Surface = [int][int][struct loRGB][struct loRGB][struct loRGB]...

So now its impossible to access the first two ints properly without breaking off of the "Multiple of 3" rule imposed by the automated structure cast.

I work with Hex quite often when cheating on DungeonCrawl, but in the programming environment I've never figured out what 0x means, is that just a symbol representing that the following is in Hex?

##### Share on other sites
They did it that way because if you have a pointer to something it makes no sense for p+1 to point into the middle of it. It also falls out naturally from the syntax for arrays.

##### Share on other sites
Quote:
 Original post by Anon MikeThey did it that way because if you have a pointer to something it makes no sense for p+1 to point into the middle of it. It also falls out naturally from the syntax for arrays.

But, but but but.. but

Array[x+1] == I'm ok with that +1 shifting it the sizeof(element).
Array[x] + 1 == This is ludakris, it should shift it 1 byte, not sizeof(element) [headshake]

##### Share on other sites
Quote:
 Original post by TheveninArray[x+1] == I'm ok with that +1 shifting it the sizeof(element).Array[x] + 1 == This is ludakris, it should shift it 1 byte, not sizeof(element) [headshake]

Those are quite diffrent, one references the element at element (x + 1) the other is the element at x and has one added to it. But let's pretend you ment
&Array[x] + 1
then that wouldn't reference an element but is equal to Array + x + 1, and I guess understanding that is the source of the your problem. Array[x] is just convinent shorthand for *(Array + x), actually it extends so far as to actually being able to write x[Array] (disregarding the fact that anyone who actually use that construct should be shot.

##### Share on other sites
Quote:
 Original post by TheveninThe need arose because I went and did this...void *Surface = [int][int][struct loRGB][struct loRGB][struct loRGB]...The first two ints are the width and height, and the rest (Roughly 250k) are all RGB structs.Inaddition, instead of calling it a void, I went and called it...struct tRGB *Surface = [int][int][struct loRGB][struct loRGB][struct loRGB]...So now its impossible to access the first two ints properly without breaking off of the "Multiple of 3" rule imposed by the automated structure cast.I work with Hex quite often when cheating on DungeonCrawl, but in the programming environment I've never figured out what 0x means, is that just a symbol representing that the following is in Hex?
Can you please show what you mean in terms of real C++ code with regards to tRGB above. You can't possibly mean a 5-dimensional array!

Also, please explain what you mean by a "multiple of 3 rule". Those first two ints are aligned to int boundaries as far as I'm concerned from what you've posted this far.

I do not see a reason for you to attempt to circumvent the automatic pointer offset arithmetic, thus far. If it's behaviour seems wrong, then you are probably doing something in a bad way. Show some real code so we can show you the way that you should really be doing it.

##### Share on other sites
KISS. (I assume plain C.)

typedef struct tRGB_s {  int x;  int y;  // The easiest thing is to just add a level of indirection.  // C's unbelievably weak typing also lets you get away with just declaring  // an array[1] here, and then over-allocating memory accordingly to create  // the struct.  struct loRGB* data;} tRGB;tRGB* createTRGB(int x, int y) {  tRGB* thing = malloc(sizeof tRGB); if (!thing) return NULL;  thing->x = x; thing->y = y; thing->data = malloc(sizeof (struct loRGB) * x * y);  if (!thing->data) { free(thing); return NULL; }  return thing;}int destroyTRGB(tRGB* target) {  if (!target) return -1;  free(target->data); // it is an invariant that this won't be NULL.  free(target);  return 0;}tRGB* cloneTRGB(tRGB* src) {  tRGB* result = createTRGB(src->x, src->y); if (!result) return NULL;  for (int i = 0; i < src->x * src->y; ++i) { result->data = src->data; }  return result;}int assignTRGB(tRGB* src, tRGB* dest) {  if (!(src && dest)) return -1;  tRGB* other = cloneTRGB(src); if (!other) return -1;  dest->x = other->x; dest->y = other->y;  free(dest->data); dest->data = other->data; free(other);  return 0;}

In C++ this kind of thing becomes much easier:

struct tRGB {  int x;  int y;  loRGB* data;  tRGB(int x, int y) : x(x), y(y), data(new loRGB[x*y]) {}  tRGB(const tRGB& other) x(other.x), y(other.y), data(new loRGB[x*y]) {    for (int i = 0; i < x*y; ++i) { data = other.data; }  }  tRGB& operator=(const tRGB& rhs) {    // copy and swap idiom, for exception safety. I used something similar in    // the C code.    tRGB other(rhs);    x = other.x; y = other.y; std::swap(data, other.data);  }  ~tRGB() { delete[] data; }};

##### Share on other sites
I do not mean a 5-dimensional array.

(&array[1] + 1) is EXACTLY equivalent to (&array[2])

I'm fine with this if its bytes (Since +1 byte <=> the next byte), but when working with structures (Or any variable greater than 1 byte in size), I disagree with the standards.

Quote:
 Original post by iMalcIf it's behaviour seems wrong, then you are probably doing something in a bad way. Show some real code so we can show you the way that you should really be doing it.

Ok.

You have a very large block of linear memory...
[][][][][][][][][][][][][][][][][]

You store int's in the first two
[int][int][][][][][][][][][][][][]

Than you store struct RGB (A structure of 3 unsigned characters) in the remaining.
[int][int][sturct RGB][sturct RGB][sturct RGB][sturct RGB][sturct RGB]...

And you call this a surface.

Now when you call my sDrawSurface() function, you don't have to specify the width and height of the surface your drawing, because it already knows, because its already in the surface itself (My reason for doing it this way).

Its really just this simple.

The "Multiple of 3" rule is reference to the fact, that I cannot say arrSurface[{Some Decimal Value Here}] and get the height.

Observe...
struct RGB MyRGBArray;

MyRGBArray[0] == 0th byte.
MyRGBArray[1] == 3rd byte.
MyRGBArray[2] == 6th byte.
MyRGBArray[3] == 9th byte.
MyRGBArray[4] == 12th byte.

However, my the width and height are on the 0th byte && 4th byte.

And so I was hoping....

&MyRGBArray[0] + 4 == 4th byte.

However, it actually equals....

&MyRGBArray[0] + 4 == 12th byte.

Which is ludakris!

##### Share on other sites
arrays are meant to store 1 data type. array indexing and pointer arithmetic work the same way. use a byte as your pointer type if you want to increment by the size of a byte.

How about instead of trying to hack something into working, you use the right tool for the job, such as a struct?

struct RGB
{
unsigned char r,g,b;
}

struct mysurfacestruct
{
int a;
int b;
RGB color1;
RGB color2;
RGB color3;
}

then you can have an array of these structs if you want.

##### Share on other sites
You mean...

struct mysurfacestruct
{
int a;
int b;
struct RGB *colors;
}

And than....

mySurface.colors = malloc(width*height);

Since otherwise it would be a struct with indefinent elements.

##### Share on other sites
right. I forgot about it holding an arbitrary number of RGB elements.

##### Share on other sites
Quote:
 (&array[1] + 1) is EXACTLY equivalent to (&array[2])

That's because foo really means *(foo + i).

Quote:
 I'm fine with this if its bytes (Since +1 byte <=> the next byte), but when working with structures (Or any variable greater than 1 byte in size), I disagree with the standards.

I don't. It's perfectly rational. Get over it. Pointer arithmetic is intended to iterate over arrays - as such the step must be the size of the array element. If you want to apply a different offset, cast to char*.

template<class T>T* byte_offset(T* ptr, long offset){   return (T*)(offset + (char*)ptr);}

##### Share on other sites
char *byte = (char*) &intary[5];char b0 = byte[0]char b1 = byte[1]char b2 = byte[2]char b3 = byte[3]

##### Share on other sites
Think of it this way. int *p = foo();

p now points to an int. You can dereference p and do any sort of int related thing you want. If p+1 pointed to the next byte rather than the next element what would p point to? It would point to garbage. Dereferencing p may very well crash your app (because of alignment or other hardware design issues). The fact that in this particular case ((int *)((byte *)p)+1) might point to something useful is an accident caused by circumventing the type system.

Besides, the vast majority of time people work with elements and having to go p+sizeof(*p) all the time would be annoying and very error-prone.

##### Share on other sites
Keep in mind that on some systems, unaligned memory accesses aren't possible:

int foo;*static_cast<int*>(static_cast<char*>(&foo) + 1); // Boom// I think this happens to be ok on x86 architecture, but will blow up on// almost everything Motorola ever made :/

##### Share on other sites
x[y] is *(x+y) is *(y+x) is y[x], now and for ever.

As a result you can write something silly like cout << 4["Hello"] to print 'o'.

Even if it did do what you wanted in your example, you still end up with an integer when you dereference it, not the byte you wanted. You'd need to cast it regardless. The current method is better because you can skip multiplying by it's size, which you would need to do in every other case.

##### Share on other sites
The better way I spoke of would be:
struct RGB {  unsigned char r, g, b;};struct MySurface {  int width, height;  RGB colorData[0]; //May have to use a 1 here if your compiler wont allow zero length arrays.};
Of course, you'd allocate a MySurface with (width*height*3)+8 bytes.
It's laid out exactly the same in memory and you can access everything sensibly.

Do you now see how you were basically using a high-level-language as if it were a low-level-language (like asm). Make sure that your data structure matches the actual data. You were making things hard for yourself by not doing so.

Compiler pointer arithmetic addressing behaviour IS CORRECT, there is no question about that.