• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
rockstar8577

Pointers

17 posts in this topic

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

0

Share this post


Link to post
Share on other sites

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.
 

0

Share this post


Link to post
Share on other sites

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
Restored post contents from history.
2

Share this post


Link to post
Share on other sites

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.

2

Share this post


Link to post
Share on other sites

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

0

Share this post


Link to post
Share on other sites

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!

0

Share this post


Link to post
Share on other sites

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 :)!

2

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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).

0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites

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?".

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0