Advertisement

Incrementing Pointers

Started by April 28, 2000 09:37 PM
34 comments, last by ziplux 24 years, 8 months ago
Hello. I''m having a little trouble understanding pointers, I''ve been told before that I should "increment a pointer," but I don''t really understand what that means. I *think* that this:

buffer[x * (y+pitch)] = 5;
 
is the same as:

buffer += x * (y+pitch);
buffer = 5;
 
Am I correct in assuming this? If so, I don''t understand how the complier can know when you''re advancing a pointer and when you''re setting it to a value. Sorry if this makes absolutely no sense, but maybe someone can help me, I''m starting to confuse myself . Thanks in advance. Visit our web site: Asylum Entertainment
My Geekcode: "GCS d s: a14 C++$ P+(++) L+ E-- W+++$ K- w++(+++) O---- M-- Y-- PGP- t XR- tv+ b++ DI+(+++) D- G e* h!"Decode my geekcode!Geekcode.com
Visit our web site:Asylum Entertainment
Ahh.. no.. those are both changing the value of the pointer. In fact, the ptr = 5 will likely give a warning or error because you almost never (except in systems programming or low level stuff) need to set a pointer to a constant value (except for 0

Say you have a pointer to a int.

int *iPtr;
and an int..
int x;

to set the pointer so that it points to x you use the ''address of'' operator, which is &
like this:

iPtr = &x

to write to the value of x via the pointer, you would use the pointer dereference operator, which is *
like so

*iPtr = 5; // same as x = 5

note this:
in pointer math, the value of a pointer is always changed based on the size of the object the pointer points to.

for instance.. if a pointer ''ptr'' is pointing to the location 50 in memory, and it is an int *, then ptr+1 would point to location 50 + sizeof(int), this makes sense as it is advancing the pointer to the next int

pointers to structures (or classes) are useful too.

struct MyStruct
{
int a, b, c;
};

MyStruct s;
MyStruct *p = &s

normally to access the members of the struct you would do something like:

s.a = 5;
s.b = 10;

to access them through the pointer you use the -> operator:
p->c = 15;

in your example:

buffer[x * (y+pitch)] = 5;

is the same as:
*(buffer + x * (y+pitch)) = 5;

first the pointer is index with the proper value
this is all done in parentheses because * (pointer dereference) has higher precedence than the mathematical operators.

then after correct position has been found, you assign to that position with the deref. operator *

adamm@san.rr.com
Advertisement
oops.. hit enter there before I was finished.. but I have to leave soon anyway

I''ll just leave one more -quick- note on why you''d use a pointer over using the value directly.

1) All parameters to a function are passed by value (that is, they are copied). This makes it impossible for a function to change the value of the data used to call it (it could only change its local copy). However, you can pass a pointer to the data and the function can change the data through the pointer. (A reference is actually a hidden pointer.. or you might say an automatically dereferenced pointer, but it''s bad style to use a reference argument to change data passed to a function because it''s not apparent from looking at the call that data is being changed!

2) If you have an array of large structures (large being anything much bigger than a basic data type.. such as an int), and you will be moving them around or whatnot (say you''re sorting them for instance), it is much faster to move pointers around than to move the actual data, so you would use an array of pointers to the actual data and sort that instead.

3) Similarly, if you''re passing large data to a function, it can be inefficient. What you would want to do is pass a pointer to the data, since pointers are generally small data types (4 bytes usually.. sometimes 2 or 6 or 8.. but small nonetheless). If you are worried about the data being changed accidentally, you can pass a constant pointer ie.

void Function(BigStruct const *data); // this function cant accidentally change ''data''
const is useful in debugging, as well as allowing you to pass more data to your function (the compiler will often not let you pass a constant pointer to a function that takes a non-constant pointer for instance). So use const liberally.

Note that there is a difference between these two:

int const *p1;
int * const p2;

in the first, the data that p1 points to is constant, meaning you can change what data p1 points to, but you cant change the data that it points to.. (meaning *p1 = 5; would be illegal, but p1 = &x would be fine)

the second is the opposite. you can change the data that the pointer points to, but you cant change -what- the pointer points to. so *p2 = 5; would be fine, but p2 = &x would be illegal.

ok well i -really- have to go now.. i''m late!

if you have any further questions feel free to email me and i''ll do my best to help

good luck!

Adam M.

adamm@san.rr.com
adamm@san.rr.com
Ok I''m all ready to leave
Sorry for the rushed messages, but I''ll elaborate a bit on what I was saying about using const whenever you could.

The purpose of const is, of course, to make a value constant so that it can''t be changed
Thus, the compiler cannot legally pass a const pointer to a function that takes a non-const pointer, because that function would be able to change what the pointer changed to.

So let''s say you wrote a function like this:

void Print(char *str); // prints out the string ''str''

and you went to call it like this:

Print("Hello, world!");
seems simple enough..
nope.. error..
"Hello, world!" is a char const *; all string literals are.

Thus, you must (and should) declare the function like this:
void Print(char const *str); // works fine now

I also said something about it being bad style to use a reference argument to allow a function to change a value.

take this function:

void nochange(int x) // uses x but doesnt change it
{
x = 5; // only changes local copy!
}

void change(int *x) // changes x
{
*x = 5; // changes what it was called with
}

later on...
int y = 7;

now you want to change y..

to get a pointer to y, you would use the address of operator..

like this:

change(&y);
it is obvious from looking at it, that y is possibly (probably) being changed by the function.

compare to:
nochange(y);

since y is being passed by value, it is impossible for the function to change it, since it could only change its local copy. this too should be obvious from looking at the call. but it''s not

enter the reference argument

void dumbchange(int &x) // no!
{
x = 5; // changes what it was called with!
}

int y = 7;
dumbchange(y);

this is perfectly legal, but very bad style.
it looks exactly like it was passed by value!
you dont need to use * in front of x = 5;
and you dont need the & in front of y
those are done automatically..

somebody could look at dumbchange(y) and assume that y wasnt being changed.

now as i stated earlier, it''s more efficient to pass a pointer to a large object than to pass a copy of it.

but putting all those *''s and ->''s next to everything can lead to some messy looking code at times..

this is okay:
void nochange(int const &x)
{
print(x);
}

nochange(y);

it LOOKS like a by-value call, and it''s safe to let people assume that y isn''t being changed.. because it cant be changed (int const &x is const!)

personally I prefer to use pointers and not references.. i prefer to use pointers all the time instead of pointers sometimes and references other times..

well now it is time for me to go.. out to eat
good luck with Extreme Tic Tac Toe!!

I checked out your web page

I''ve also struggled through most aspects of DirectX at one time or another (except that I haven''t done a lot of direct3d.. only some) and I''d be happy to help, if you don''t mind reading my huge answers!

What can I say, I like helping...

Have a nice night..
Adam M.

adamm@san.rr.com
adamm@san.rr.com
oh yeah!
one last thing!

i noticed this:
buffer[x * (y+pitch)]

If you are really indexing a memory buffer like that, you need to do y*pitch + x

Maybe you already knew this and just used that as an example.. but I figured I''d note it anyway.
adamm@san.rr.com
Thanks for all your help , I''m beginning to understand, but I still do not understand this:
quote: Original post by adammil

2) If you have an array of large structures (large being anything much bigger than a basic data type.. such as an int), and you will be moving them around or whatnot (say you''re sorting them for instance), it is much faster to move pointers around than to move the actual data, so you would use an array of pointers to the actual data and sort that instead.


Ok, this is what I am trying to do, move pointers instead of referencing the address of the data using brackets [x * (y+pitch)], because I have been told that it is faster that way. Basically, I have a buffer on the video card that is 16bits, and I want to move around it by incrementing a pointer, instead of referencing it with brackets, as in this snippet:
BYTE* lpSprite;...lpSprite = (BYTE*)srcDDSD.lpSurface;lpSprite += (srcRect.top * SpritePitch) + (srcRect.left * 2);...sTemp  = *((DWORD*)lpSprite);...sTemp = RGB16(255,0,0); 


I think that the code is the same as
lpSprite[(srcRect.top * SpritePitch) + (srcRect.left * 2)] = RGB16(255,0,0); 

or am I not getting something? Sorry if I am . Thanks for your help.

Visit our web site:
Asylum Entertainment
My Geekcode: "GCS d s: a14 C++$ P+(++) L+ E-- W+++$ K- w++(+++) O---- M-- Y-- PGP- t XR- tv+ b++ DI+(+++) D- G e* h!"Decode my geekcode!Geekcode.com
Visit our web site:Asylum Entertainment
Advertisement
I guess we posted at the same time, or I would have mentioned that that was just a mistake on my part, in my program it is written the way you said.

Visit our web site:
Asylum Entertainment
My Geekcode: "GCS d s: a14 C++$ P+(++) L+ E-- W+++$ K- w++(+++) O---- M-- Y-- PGP- t XR- tv+ b++ DI+(+++) D- G e* h!"Decode my geekcode!Geekcode.com
Visit our web site:Asylum Entertainment
BTW Thanks for checking out my site

Visit our web site:
Asylum Entertainment
My Geekcode: "GCS d s: a14 C++$ P+(++) L+ E-- W+++$ K- w++(+++) O---- M-- Y-- PGP- t XR- tv+ b++ DI+(+++) D- G e* h!"Decode my geekcode!Geekcode.com
Visit our web site:Asylum Entertainment
Well I''m about to go to bed, but I figured I would check the thread before I went..

Hmm.. well when I said that having an array of pointers can be more efficient than an array of data, I was referring to large data structures.. for instance if you had an array of phonebook entries, and each entry took up maybe about 80 bytes.. and you wanted to sort them, it would be faster to keep an array of pointers and sort the pointers because moving all those large blocks around would be rather slow, while moving small 4-byte pointers which fit nicely into the registers would be much faster.

The same thing wouldn''t apply here for two reasons.. first of all, you can''t just move blocks of screen memory around by manipulating pointers to them.. since the screen memory is a single contiguous block of memory that isnt being broken up into pieces which would be moved around.. and also because you are dealing with an array of pixels, which are nice and small (1 to 4 bytes depending on depth.. and all of those fit nicely into the registers as well.. in fact, 4-bytes is the natural register length of 386+ protected mode on the PC.. so using a pointer to access such small data would be much slower.. I''m talking about when each element of data is large (say at least 30 bytes) and can be moved around freely.



BYTE* lpSprite;
lpSprite = (BYTE*) srcDDSD.lpSurface;
lpSprite += (srcRect.top * SpritePitch) + (srcRect.left * 2);
sTemp = *((DWORD*)lpSprite);
sTemp = RGB16(255,0,0);

I think that the code is the same as

lpSprite[(srcRect.top * SpritePitch) + (srcRect.left * 2)] = RGB16(255,0,0);



actually, no :/

something more like this is what you''d want:

BYTE* lpSprite;
lpSprite = (BYTE*) srcDDSD.lpSurface;
lpSprite += (srcRect.top * SpritePitch) + (srcRect.left * 2);

*((WORD*)lpSprite) = RGB16(255, 0, 0);

Note that I used WORD and not DWORD, as you are using 16-bit mode (i''m assuming from the *2 and RGB16). a WORD is 16-bits, while a DWORD is 32 bits. Using a DWORD in 16-bit mode is useful when you need to read or write two pixels at once though.. but if you are just setting a single pixel then you would use a WORD *

To expand on that sample, I will demonstrate a rather poor surface filler using a pointer like that. The code isn''t optimized or even good style! But I hope it will serve as an example..

BYTE *Screen = srcDDSD.lpSurface + SpritePitch * srcRect.top + srcRect.left;
int x, y, wid, hei;

wid = srcRect.right - srcRect.left;
hei = srcRect.bottom - srcRect.top;

for(y=0;y{
// fill with black
for(x=0;xScreen += SpritePitch
}

i realize that I didn''t end up doing any pointer incrementing :/

note however:

*Screen++ might not do what you think. It does not increment whatever Screen points to. Since ++ has higher precedence, it returns what Screen points to and then increments the pointer.

hmm.. here''s a simpler example that does pointer incrementing..

int array[100];
int *p = array;
int i;

for(i=0;i<100;i++) *p++ = 0;

this would fill the array with zeros, but I would recommend using p, or even better, memcpy() [or CopyMemory, which is the same thing]

hmm.. as my final note for tonight, a lot of people would say that this:

int array[100];
int *p = array;
int i;
for(i=0;i<100;i++) *p++ = 0;

is faster than this:

int array[100];
int i;
for(i=0;i<100;i++) array = 0;<br><br>That certainly used to be true on older processors, but in my opinion, the reverse is now true.<br><br>array is probably faster than *p++ because of the fact that the pentium supports instructions like mov [eax+ecx], ebx so it can do the indexing and the move in the same instruction<br><br>whereas a pointer would require both an add instruction (to increment it) as well as a mov to copy the data<br><br>if you dont know anything about assembly, that probably means nothing to you :/<br><br>Well I hope I have been a help.. I have to go to bed now so I can get up and work on my own game… and hopefully it will be good enough to impress Poptronik so they will hire me!<br>I need money…. <img src="sad.gif" width=15 height=15 align=middle><br>Sort of sucks.. I started the game as a group project and I''ve ended up writing all but 7k of the source code.. ugh..<br><br>Anyway, I''m sure you don''t need to know about my problems <img src="smile.gif" width=15 height=15 align=middle><br>Good luck on the game, and with pointers..<br>Feel free to email if you want, and goodnight!<br><br>Adam M.<br>adamm@san.rr.com </i>
adamm@san.rr.com
Actually I forgot something very important.

You said:

Ok, this is what I am trying to do, move pointers instead of referencing the address of the data using brackets [x * (y+pitch)], because I have been told that it is faster that way.


When I said that brackets were probably faster, I meant only for simple indexing (ie, a loop like my example)

The reason you were told that using a pointer would be faster is so that you don''t end up re-calculating y*pitch+x for every pixel. Basically you would calculate that once to find the start and then increment the pointer. For things like blitting and filling, I would actually recommend a combination type thing like in my filler, where you have a pointer to the beginning of the line and you index it with brackets.

When I say a pointer to the beginning of the line, you see how I take the pointer and set it to the beginning of the area we are filling (like you did) and then in the main loop I merely indexed the pointer.
I couldn''t use brackets however, because my pointer was a BYTE * and I needed to cast it first..

but it''s the same thing
*(array + x) is the same as array[x]

The reason to keep a pointer to the next line is so you can use the faster indexing and also because it looks a little cleaner. Otherwise, you cant simply add the Pitch and get the next line. You have to add the difference between the number of bytes used by the pixels you incremented over and the Pitch.

I feel like I''m sounding very confusing.. :*(
Maybe it''s because I''m tired..

Well goodnight once again,
AM
adamm@san.rr.com

This topic is closed to new replies.

Advertisement