Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Pointers


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
17 replies to this topic

#1 rockstar8577   Members   -  Reputation: 259

Like
0Likes
Like

Posted 15 March 2013 - 02:37 AM

Anyone have a good article on pointers? I understand them somewhat, but i don't get the full gist of them.



Sponsor:

#2 Vortez   Crossbones+   -  Reputation: 2704

Like
7Likes
Like

Posted 15 March 2013 - 03:16 AM

A pointer is just a variable that hold an address of a memory location, or if you prefer, the adresse of another variable.Every variables you create have an address in memory, the place where it is stored. In 32 bit OS, this address take up 32 bits, so, it's the same size as an unsigned integer. So if you take the address of a BYTE variable, wich is 8 bit, or 1 byte, it's address is still 32 bits width, hence the 4Gb memory limit on 32 bits OS.

 

Why is that usefull? Well it could be for many things. One of the most usefull thing you can do with them is to pass a pointer to a function, so it can modify it, instead of making a copy of the variable your passing to it. It's also usefull for passing arrays and structures to a function for the same purposes. For the case of structures, it is much efficient to pass an address as an argument, wich is only 4 bytes width, than making a copy of an entire structure of, say, 100 bytes in size.

 

Ex. using arrays:

 

void SumArrays(int *p1, int *p2, int *pResult){	for(int i = 0; i < 10; i++){		pResult[i] = p1[i] + p2[i];	}}void main(){	int Array1[10];	int Array2[10];	int SummedArray[10];	// Fill arrays with random values	for(int i = 0; i < 10; i++){		Array1[i] = rand() % 1000;		Array2[i] = rand() % 1000;	}		SumArrays(&Array1[0], &Array2[0], &SummedArray[0]);}

 

Whitout pointers, this wouldn't be possible because the arrays are all local to the main() function, but using pointers allow us to use them outside the function into another one.

 

That's not the only usage of pointers but that should give you a good idea.

 

I would like to make a better examples using pictures but i don't feel i have the force to make some, it would take me hours.

 

Have a look here instead, it's pretty well explained.


Edited by jbadams, 04 April 2013 - 05:47 AM.
Restored post contents from history.


#3 NightCreature83   Crossbones+   -  Reputation: 3030

Like
0Likes
Like

Posted 15 March 2013 - 04:28 AM

A pointer is just a variable that hold an address of a memory location, or if you prefer, the adresse of another variable.Every variables you create have an address in memory, the place where it is stored. In 32 bit OS, this address take up 32 bits, so, it's the same size as an unsigned integer. So if you take the address of a BYTE variable, wich is 8 bit, or 1 byte, it's address is still 32 bits width, hence the 4Gb memory limit on 32 bits OS.

 

You should never assume that a pointer has the same size as an unsigned int as the C++ standard doesn't mention that at all, and is not true when you are running a 64bit app where the pointer is 8 bytes big. A pointer will have the size of the memory address space used and this can differ considerable from an integer on a platform.

 

Assuming that your pointer size is always 4 bytes can lead to some weird bugs when you try to port your application to an other compiler or subsystem that doesn't have 4 byte pointers.
 


Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, Mad Max

#4 rockstar8577   Members   -  Reputation: 259

Like
0Likes
Like

Posted 15 March 2013 - 04:34 AM

Well i understand the basis of pointers. It's more the memory allocation for pointers that gets me.



#5 Vortez   Crossbones+   -  Reputation: 2704

Like
2Likes
Like

Posted 15 March 2013 - 05:14 AM

Yes, that why i said on a 32 bits OS. I agree with you about this assumption, that's what sizeof if for, i forgot to mention it.

 

As for memory allocation, it's not very different than allocating variables or arrays normally on the stack, except you have to remember to free your memory after using it. That's why, as a rule of thumb, i always write the code to free memory at the same time i allocate it. I also like to use the SAFE_DELETE macros from directx to handle that stuffs, since it protect you from trying to free a null pointer using only one line of code, and also make sure to reset the pointer to NULL afterward.

 

//These helper macro will release or delete safely the passed object#define SAFE_RELEASE(x)	       if((x) != NULL){(x)->Release();(x) = NULL;}#define SAFE_DELETE_ARRAY(x)   if((x) != NULL){delete[] (x);(x) = NULL;}#define SAFE_DELETE_OBJECT(x)  if((x) != NULL){delete (x);(x) = NULL;}

 

What do you not understand about allocating memory using pointers exactly?

 

Those two programs does exactly the same thing

 

BYTE Array[1000];BYTE *pArray = &Array[0]; // pArray have the same address as the 1st element of Array// Those 2 lines of code does the same exact thingsArray[0] = 123;pArray[0] = 123;
// Dynamically allocate an array of 1000 bytes and store the address of the 1st element in pArrayBYTE *pArray = new BYTE[1000];pArray[0] = 123;if(pArray != NULL)	delete [] pArray;
orSAFE_DELETE_ARRAY(pArray)

 

The only difference is the memory.deallocation. You also have to use the star symbol when assigning value to a variable, but it's not necessary for arrays like in this example. Another small difference is the use of -> instead of comma for structure, but both does the same thing really.


Edited by jbadams, 04 April 2013 - 05:47 AM.
Restored post contents from history.


#6 Vilem Otte   Crossbones+   -  Reputation: 1561

Like
2Likes
Like

Posted 15 March 2013 - 05:31 AM

It's good to think about how memory manager in operating system works. So you probably know that memory is broken into blocks, every block has some kind of it's header (sometimes called also bitmap), this header contains few data - whether block has been already allocated, and the size of the block.

 

Now imagine your memory, it might look like this (free blocks are unallocated, and lets say one '-' is a byte) - let's say that start is at address 0x10000000:

+----------------+------------+--------+------------+------------+
|      free      |#some#data##|  free  |#other#data#|    free    |
+----------------+------------+--------+------------+------------+

So it's clear to see that:

some data are at memory address 0x10000000 + 0x10 (or +16 in decimal)

other data are at memory address 0x10000000 + 0x24 (or +36 in decimal)

 

Now you want to allocate another 10 bytes of memory, so you call char* ptr = malloc(sizeof(char) * 10); (or in C++ call char* ptr = new char[10]) - what does it actually do? In short:

1.) It finds suitable free block (suitable = it is at least 10 bytes large, and better it is the smallest available that is at least 10 bytes large)

2.) It marks it used (possibly splitting it into 2 - because we wan't exactly 10 bytes of memory, not more)

3.) Returns address of that memory (e.g. pointer to that memory)

 

So, step 1:

+----------------+------------+--------+------------+------------+
|      free      |#some#data##|  free  |#other#data#|    free    |
+----------------+------------+--------+------------+------------+
^                             ^                     ^ 
Good, but larger than last    Too small             This one is good and smaller than 1st one :) we got a match

 

So we've found suitable block at address 0x10000000 + 0x30 (or +48 in decimal). It's time to go to step 2:

+----------------+------------+--------+------------+----------+--+
|      free      |#some#data##|  free  |#other#data#|###ptr####| f|
+----------------+------------+--------+------------+----------+--+
                                                    ^
                                                    Address 0x10000000 + 0x30

We just marked the block used and it's size as 10 bytes. Of course rest of bytes must form new block, that is still free.

 

Step 3:

Memory manager just returns pointer to address 0x10000000 + 0x30 to us.

 

So now we can perform any reads/writes to memory we allocated.

 

But what happens when we want to free or delete  that memory? It's a lot more simple, call free(ptr); or in C++ delete [] ptr; will just do following:

1.) Marks block in it's header as unused (e.g. free)

2.) Finds whether we can merge that blocks with free block before/behind it.

 

Let's use our scheme again, we want to deallocate other data, e.g. deallocate location 0x10000000 + 0x24.

 

Step 1 - mark it as unused, so it'll change into this right away:

 

+----------------+------------+--------+------------+----------+--+
|      free      |#some#data##|  free  |    free    |###ptr####| f|
+----------------+------------+--------+------------+----------+--+

Now you see that those 2 free blocks could be merged - why merge? What if we would like to allocate like 20 bytes on memory? Those 2 blocks together are 20 bytes of memory, but right now they're just 8 bytes and 12 bytes, so memory manager would say that both are larger than memory we want to allocate. So right now we just go through memory and merge free blocks together, resulting in this:

 

+----------------+------------+--------------------+----------+--+
|      free      |#some#data##|        free        |###ptr####| f|
+----------------+------------+--------------------+----------+--+

And it's done.

 

 

 

This is how memory manager in operating system works (of course simplified a bit) - you should get idea about what's behind memory allocation/delocation from this. Basically the pointer just stores address of where your allocated block begins, you have to remember size of allocation on your own.


My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com


#7 NightCreature83   Crossbones+   -  Reputation: 3030

Like
0Likes
Like

Posted 15 March 2013 - 07:09 AM

Yes, that why i said on a 32 bits OS. I agree with you about this assumption, that's what sizeof if for, i forgot to mention it.

 

As for memory allocation, it's not very different than allocating variables or arrays normally on the stack, except you have to remember to free your memory after using it. That's why, as a rule of thumb, i always write the code to free memory at the same time i allocate it. I also like to use the SAFE_DELETE macros from directx to handle that stuffs, since it protect you from trying to free a null pointer using only one line of code, and also make sure to reset the pointer to NULL afterward.

 

//These helper macro will release or delete safely the passed object
#define SAFE_RELEASE(x)	       if((x) != NULL){(x)->Release();(x) = NULL;}
#define SAFE_DELETE_ARRAY(x)   if((x) != NULL){delete[] (x);(x) = NULL;}
#define SAFE_DELETE_OBJECT(x)  if((x) != NULL){delete (x);(x) = NULL;}

Sadly does macros don't safe you from pointers cleaned up elsewhere in debug builds when they have 0xDEADBEEF, 0xFEFEFEFE, 0xCDCDCDCD, 0xFEEEFEEE, 0xBAADF00D or other patterns that indicate a heap cleanup somewhere. Most game engines that overwrite the default memory allocations and placement new will still use similar patterns in debug builds to tell you what's going on. You should get to know these patterns btw as they can help you debug memory issues, here is a link about the CRT Heap in Win32 http://www.nobugs.org/developer/win32/debug_crt_heap.html


Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, Mad Max

#8 kauna   Crossbones+   -  Reputation: 2836

Like
0Likes
Like

Posted 15 March 2013 - 09:33 AM

While not directly related to the question, I suggest also you to take a look into std::vector (and other std:: containers). Std::vector is a handy solution for most of the cases where you need array allocation, deallocation (or even resizing). Cleaner / shorter code, less strange memory bugs, less memory leaks, all that a programmer needs.

 

Cheers!



#9 Ludus   Members   -  Reputation: 970

Like
0Likes
Like

Posted 15 March 2013 - 09:53 AM

Here are a couple resources:

 

http://www.cplusplus.com/doc/tutorial/pointers/

 

http://www.learncpp.com/cpp-tutorial/67-introduction-to-pointers/



#10 superman3275   Crossbones+   -  Reputation: 2061

Like
2Likes
Like

Posted 15 March 2013 - 02:06 PM

A pointer is simply a variable which holds a memory address. Because of this, all pointers are the same size on your system. If you have a pointer to an object which is eight bytes and a pointer to a type of object which is four bytes, they both are the same size. Pointers are useful because they allow us to operate on the same data throughout our program. Here's an example:

void add(int op1, int op2, int result) {
  result = op1 + op2;
}

In this, we don't actually change the value of result. The function creates a copy of result whose value is changed to the sum of op1 and op2. What if we wanted to change the actual value of result? If we have the memory address of our original result variable, then we can change the value at the memory address (thus changing the value of result):

void add(int op1, int op2, int * const result) {
  *result = op1 + op2;
}

This changes the actual value of result for us. However, we now have new syntax. Some noticeable changes in syntax here are how we declare a pointer. To declare a pointer, we use the syntax:

type * name;

We specify the type of variable name points to by changing type. You may be wondering why we have the dereference operator (*) in-between the type and name. This tells the compiler that we are creating a pointer. Later on, we will discuss the dereference operator. When we create a pointer and use (*), it is completely unrelated to the actual dereference operator.

 

To assign a pointer a memory address, we use the reference operator (&). This returns the memory address or the variable following it. Examine:

int normalVariable = 5;
int * pointerVariable = &normalVariable;

Here, we create a normal integer variable (normalVariable). We then create a pointer to an integer (pointerVariable) and assign it to the memory address of normalVariable.

 

If we look back at the first pointer function example, we have this line of code:

*result = op1 + op2;

This syntax may seem confusing at first. When we created a pointer, we used the dereference operator (*) to specify that a variable was a pointer. In reality, when we use (*) to create a pointer, it is completely unrelated to the real use of the dereference operator (*): to dereference. We use the reference operator (&) to return the address of a variable, and thus we use the dereference operator (*) to get and set the value of a variable. When we put the dereference operator (*) before a pointer, it means that we're returning the value of the pointer. This can also be used to set the value of the pointer, as seen above.

 

This means that in the code above, we're setting the value of result to the sum of op1 and op2.

 

Pointers also allow us to create memory on the heap (a large area of memory set aside for dynamic allocation). To do this, we use the new and delete operators. This part of pointers is very complicated, so I recommend you read about The Stack and the Heap along with Dynamic Allocation With Pointers.

 

You might now be wondering: When would I ever use pointers? This is a valid question, and many tutorials don't explain it well. So, I'll use an example which I deal with right now: Windows.

 

I use an API called SFML for game development. SFML is very object oriented, so you create a RenderWindow object. Many components of my game have to draw to the window. I can't pass the window by value, because then the components are drawing to a RenderWindow copy, located in separate memory. I use pointers so that they all have access to the same RenderWindow.

 

(You can PM me for the source code of my State Machine, which uses pointers so that every state can draw to the same window.)

 

Cheers :)!


I'm a game programmer and computer science ninja ph34r.png!

Here's my 2D RPG-Ish Platformer Programmed in Python + Pygame, with a Custom Level Editor and Rendering System!

 

Here's my Custom IDE / Debugger Programmed in Pure Python and Designed from the Ground Up for Programming Education!

Want to ask about Python, Flask, wxPython, Pygame, C++, HTML5, CSS3, Javascript, jQuery, C++, Vimscript, SFML 1.6 / 2.0, or anything else? Recruiting for a game development team and need a passionate programmer? Just want to talk about programming? Email me here:

hobohm.business@gmail.com

or Personal-Message me on here smile.png!


#11 rockstar8577   Members   -  Reputation: 259

Like
0Likes
Like

Posted 15 March 2013 - 06:08 PM

I get them somewhat. But what is the difference really with something like this?

int *pnValue = new int;
*pnValue = 7;

and

int nValue = 5;
int *pnValue = new int;
pnValue = &nValue;

 

With the first being fine but the second isnt.



#12 Paradigm Shifter   Crossbones+   -  Reputation: 5432

Like
0Likes
Like

Posted 15 March 2013 - 06:24 PM

Once you overwrite the value in pnValue you got from operator new without storing it somewhere you have no way to delete it, so you have a memory leak.


"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#13 rockstar8577   Members   -  Reputation: 259

Like
0Likes
Like

Posted 15 March 2013 - 06:34 PM

So the first is changing the value at the address while the second is changing the address?



#14 mhagain   Crossbones+   -  Reputation: 8275

Like
0Likes
Like

Posted 15 March 2013 - 06:35 PM

While not directly related to the question, I suggest also you to take a look into std::vector (and other std:: containers). Std::vector is a handy solution for most of the cases where you need array allocation, deallocation (or even resizing). Cleaner / shorter code, less strange memory bugs, less memory leaks, all that a programmer needs.

 

Not always because you still get a raw pointer back from e.g. glMapBuffer(Range).


It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#15 Paradigm Shifter   Crossbones+   -  Reputation: 5432

Like
0Likes
Like

Posted 15 March 2013 - 06:38 PM

Sort of... pointers always store an address, and that's what new returns... but a pointer is just a variable whose value is an address...

 

If you allocate something with new (or new[], or malloc, calloc), it is the programmers responsibility to keep hold of the address returned somewhere and delete it (or delete[], free, and you must use the corresponding deallocation function/operator as well) exactly once, or else that is a bug.


"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#16 rockstar8577   Members   -  Reputation: 259

Like
0Likes
Like

Posted 15 March 2013 - 06:50 PM

Ahh okay. So i read an article about deallocation and whether or not you need to perform it. With the OS just releasing the memory when the program ends. Just wondering about this.



#17 Paradigm Shifter   Crossbones+   -  Reputation: 5432

Like
0Likes
Like

Posted 15 March 2013 - 08:16 PM

That does happen (memory is released by the OS) but people will be having so much fun playing your game they will never quit to the OS. So don't do it ok?

 

If a function leaks memory a bit but you call it a lot it's going to start giving you problems (and more importantly, hard to track down bugs).

 

So the usual answer is: always remember to delete stuff you allocate. If you need to do an emergency exit (e.g. calling abort() or exit()), then you can relax this a little. But you're not going to be calling abort() or exit() very often.


"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#18 Trienco   Crossbones+   -  Reputation: 2224

Like
0Likes
Like

Posted 15 March 2013 - 11:15 PM

Ahh okay. So i read an article about deallocation and whether or not you need to perform it. With the OS just releasing the memory when the program ends. Just wondering about this.

 

To illustrate. I'm sure you have been playing games that started stuttering after playing for an hour or suddenly took forever to load things, showed random bugs or flat out crashed. That's what you get when a programmer is being sloppy and/or, figures "the OS will clean it up in the end anyway". If you don't want to worry about cleaning up what you don't need anymore, don't use C++ (or at the very least make use of smart pointers and standard containers). Though that doesn't mean languages with a garbage collector will magically take care of everything in every situation.

 

I'm a little surprised there are actual articles discussing this. Unless they compare different languages, that's a bit like "filling your tank... is it really necessary?".


f@dzhttp://festini.device-zero.de




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS