What exactly is a pointer?

Every time someone tries to explain it, I have no idea what they’re talking about. Could someone try and explain it as simply as possible? Maybe use an easy example/metaphor? So basically just don’t use big words :smiley:

Thanks!

1 Like

A pointer holds an address to different location in memory. A good analogy is a mailing address.

If you hire painters to paint your house, you don’t want then to paint their own building…so they need the address of your house.

Values in memory are stored in boxes, and each box has an address. A pointer holds the address to a different box. This allows you to modify an object that is at a different location from where the code is actually running.

More detailed: each function has a stack, which is a section of memory allocated for all the data needed for that function to run. Once a function is done running, that memory is “deleted”. To be able to continue using data beyond the end of the function, it must be allocated on the heap. To access the data that is located on the heap, we need the address of it…and that is what pointers are used for.

2 Likes

A pointer is a variable which “points” to an address in computer memory. This is a ‘reference’ to an object of some type.

At the hardware level, everything is stored in memory within blocks. Each variable has a memory address. For example, if you create an integer, like so:



int MyVariable = 10;


you will store the value “10”, somewhere in your RAM.

If you want to know exactly where in your RAM this value is stored, you can get the memory address by using the “&” symbol, like so:



&MyVariable


This will give you something like:
0xC0ABCD13

which is a hexadecimal representation of a 32 bit memory address.

Let’s review: Every variable has both a memory address and a data value.

Stored at address 0xC0ABCD13 is the value 10.

A pointer is a variable which stores memory addresses! Since it’s a variable, your pointer be reassigned to point to many different addresses over the course of a program.

Now, here’s where things may get a bit confusing, so read this over until it makes sense…

Since a pointer stores only a memory address, such as 0xC0ABCD13, the computer doesn’t know what kind of data is at that address. When you assign your pointer a variable type, such as ‘int’ or ‘AActor’, you’re giving the computer a hint at the variable type it should expect to find at that address space. You can do something called ‘dereferencing’ a pointer, which means you’re grabbing the data stored at a memory address rather than the memory address itself. Since you gave your pointer a data type, it knows how to grab and handle that data (‘treat it like an integer’ vs. ‘treat it like an AActor’).

The pointer dereferencing syntax uses an asterisk:
int data = *MyVariable;

When you’re pointing to a class which contains its own variables, you can access those variables with a “->” operator. This is much like the “.” dot operator you’d use for structs, but is really just a shorthand syntax.

float CharMoveSpeed = MyChar->MoveSpeed;

The “->” operator is actually doing this:
float CharMoveSpeed = *(&MyChar).MoveSpeed;

So, what happens if you try to dereference a pointer address which is invalid? What if the pointer address is NULL (or 0x00000000) because it was uninitialized?
The computer will try to access the empty pointer and it will try to convert the data it finds at address 0x00000000 to your pointer type. It will fail and you will get a “NULL reference exception”. This is the most common type of error you will get when a program crashes! So, before you dereference a pointer, always make sure that it is valid.

Here’s where things can get interesting:
Let’s suppose you have 5 pointers, all pointing to the same memory address:



int MyData = 10;
int *p1 = MyData;
int *p2 = MyData;
int *p3 = MyData;
int *p4 = MyData;
int *p5 = MyData;


If you read the data value pointed to by all these pointers, they will all return the value “10”. Now, let’s change it!



*p1 = 20;


Now, if you read the data value pointed to by all of these pointers, they will all return the value “20”.

3 Likes

Man, I had the & symbol backwards. I thought it de-referenced. No wonder I’ve found sticking it randomly in places I don’t expect fixes stuff! :slight_smile: So, is & the same as * when it’s inline? eg:

MyType MyThing = new MyType();
return *MyThing;

…is the same as:

MyType * MyThing = new MyType();
return MyThing;

…and is the same as:

MyType MyThing = new MyType();
return &MyThing;

Is that right?

The logic I’d had explained to me is “prefer * but you can resort to & after the fact”. Now that makes sense.

One more thing that catches new people out that I’ve learnt: if your variable is a pointer to an object rather than the object itself, you access members using a dereferencing joiner (->) instead of a period (.) eg:

MyThing->DoStuff() (where MyThing is a pointer)
MyThing.DoStuff() (where MyThing is a local object)

VS tries to convert to -> for you but sometimes it’s wrong and you have to hit backspace to get your period back.

No



MyType MyThing = new MyType();
return &MyThing;


is wrong, you don’t use new to allocate on the stack. Look for stack and heap allocation in c++ on google.

The thing you got right is that &MyThing expresses the pointer to MyThing.

You would be using



MyType MyThing;


…and you would not want return a pointer to this MyThing because that object will no longer exists after the function returns (thus would cause severe errors).

The -> vs . thing is about right, but usually VS is right about it when it changes what you type. Where does it fail you? Maybe you think you are right but really VS is :wink: I use the point alot even if Im on pointers just to spare myself keypressing.

I know that, I was just struggling to provide a coherent example.

Trust me, when VS changes . to -> and a compile error results, it’s wrong. It’s well known that intellisense doesn’t handle UE all that well.

You should have a go at actually answering the question, since it sounds like you know the answer. :wink:

I said its wrong to allocate like this, and its wrong to return a pointer to a stack object. Otherwise



MyClass myObject; // stack object

MyClass *myPointer; // pointer, not valid until you assign something to it

myPointer = &myObject; // let it point to myObject, its useable now


is alright. The & before the variable name gets you the memory address of the variables contents. All this has been written about for like since the 80ies or something, so really :smiley: google around a bit. I don’t mean it mean.

Try it out with ints or simple classes, move variables and pointer around (and try returning stuff like in your example, what happes? Compiler error, program failure, nothing?) , use the watch window of VS and look what happens with the variabls. And try to understand when and why to use new and delete, and in case of UE, when and why you dont need to think about delete anymore or when you really still should.

Its just a bit laborous and seems complicated, it will just make ‘click’ once and you’ve got it once and for all (what pointers are, new and delete seem to be a source of errors even for the best programmers around).

1 Like

325a6056c8ef4ab5dab3faebf20f7f81fa5cdd2b.jpeg
The dog is a pointer. “What’s he pointing at?” you say.
A bird. “Where’s the **** bird?”
Over by those brown weeds, the dog seems to indicate.
Ok, you think to yourself. Where ever that dog is pointing, that’s where a bird is.

Anyway. That’s how we do computer stuff out in the country.
Good Luck.

What’s the difference between:

Thing = *ThatThing;

and

Thing = &ThatThing;

I am new to C++ as well, but since I started I’ve been thinking about that and understand it this way up to now:

Pointers (*):

  • Can be null.
  • Have an memory address.
  • Can be changed to point at something else than the previous pointed object.
  • You can’t point to a reference.

References (&):

  • Have no address, thus you can’t assign a pointer to it.
  • Can reference a pointer or the object in memory itself.
  • Once you declare it, you can’t change it to reference to something else.

I may be very wrong though :wink:

That makes sense, thank you! :slight_smile:

What is the purpose of pointers? I am having a hard time understanding when you’d want to use them.

The first is ‘dereferencing’ a pointer, i.e. if ThatThing was a Thing*, you’re turning it into a plain old Thing.

The second is getting the address of ThatThing, which is then a Thing*.

(1. Thing turned into Thing,
2. Thing turned into Thing*)*

For real? I absolutely had that one backwards too. Thanks :slight_smile:

That one’s easy. If you have something big or that is likely to change, instead of passing an unchanging copy of it, you pass a pointer to it, so that anything using it gets the most up to date version, plus doesn’t create another copy of it in memory. The best example is if you have a bunch of objects and want to make a list out of them, the list is just a list of memory address pointers, rather than a new copy of each object.

You will use them all the time, so it’s best to understand them. Heck, I got by with not even understanding the right dereferencing symbol, so they’re not that hard once you know what they are. :slight_smile:

…which all leads to that famous quote of murky origin, “there is no problem in computer science that cannot be solved by adding another layer of indirection”.

(Which is not actually true, but is very amusing nonetheless).

Main use is when you need to access at offset within memory block (given address of 0th element, access 15th element of the array), or when you need optional reference. References cannot point to nothing, pointers can.

…you pass a reference to it. You only need pointers when you need arithmetics, value can be reassigned, or can be null. In other situations you use references.

As exciting as it can be to have this fresh new canvas to learn C++ that is UE4, one must come into programming for UE4 with a foundational understanding of C++. There is no way around it; C++ programming is not an addition to the Unreal Engine, rather the Unreal Engine is an extension of C++. It’s all code written in C++ that makes UE4 work the way it does.

If you insist on using C++ instead of Blueprint (an extension of UE4, not the other way around), I urge you to first pick up a couple of courses of study. First, you must learn the fundamentals of computer science in any programming language. There are many resources such as Coursera or Codecademy that do a fantastic job. Don’t focus on designing your skills around games at this point in the game. Then it’s time to learn the fundamentals of Object-Oriented Programming. Again you can learn this in any object-oriented language, it’s the concepts that matter. Finally, with this new knowledge and intuition, you must undertake learning C++.

But honestly, are you not tired of being enslaved by a constant loop of changing something, breaking everything, having no idea why, and then relying on someone else’s fix that you don’t fully understand? Pointers are fundamental to every object-oriented program written in C++ (yes! That includes your UE4 game!). If pointers make no sense, and it seems like they have no good use case, then you are not capable enough of writing correct C++ code to warrant a proper argument for it over Blueprints. I have seen too many old friends start learning C++ while they are working on a game, and as soon as the passion (and code integrity) erodes from time and time again around the loop I mentioned, hack after hack, they are left with nothing but a battered pile of code and broken dreams.

This is not to say that you should give up. When I was trying to learn to code, I followed this exact same pattern for years until I had the fortune to attend college, which forced me to go back learn the basics of computer science. Never give up on your dreams or aspirations of being a game creator. Keep those fresh and sweet in the background, motivating you along the way. There are even tutorials and courses online that serve as introductory programming courses as well as introduction to game design coursework. However, making your game – your brain-child, that beautiful darling glimmer of an idea – as you learn to code is a path to disaster.

The hard truth of learning how to program is that you must absolutely fail before you can truly become ‘good’ at programming:

  • You must fail to write algorithms that do what you think they’ll do. To have the experience necessary to understand what makes a piece of code work, you must have experience learning what doesn’t.
  • You must fail to organize your code in a way that’s readable and meaningful. A good code-architect knows how horrible it feels to be crushed by the weight of her own work, unable to understand what she did yesterday in an ever-growing library of code.
  • You must fail to create a functional product. Programming is like trying to navigate a maze. One who has never mapped out a maze from the ground in the past will never know how to make sensible twists and turns in the present to complete one.

Thus, this is my case for learning the skill before you try to use it. I would be happy to help anyone who really wants to learn good programming techniques as they go along, but this is a forum for people interested in learning more about programming in C++ specifically for Unreal Engine 4.

I’ll end with my favorite quote:

“Good judgment comes from experience, and experience comes from poor judgment.”

Maybe it would help to see a sample block of memory…



Address         Data
0x0000          0
0x0004          10
0x0008          16
0x000C          0
0x0010          254
0x0014          13


A pointer is a memory address!

In this fictional example, you could have a pointer which contains the value 0x0008.



int * myPtr = 0x0008; //totally fake, setting it to point to address 0x0008


If you print out the pointer, you’ll print its address and get 0x0008.



cout << myPtr;    //output: 0x0008


If you dereference the pointer and print it out, you’ll get the DATA contained at the address 0x0008:



cout << *myPtr;   //output: 16


Your pointer is also a variable in memory with its own address. The memory block looks like this:



Address        Data
0x1234         ???
0x1238         ???
0x123C         0x0008           //myPtr
0x1240         ???
0x1244         ???


myPtr has its own address stored at 0x123C. So, if you printed the address of your pointer…



cout << &myPtr;     //output: 0x123C


You’d get the address of the pointer itself rather than the address of the data its pointing to.

There’s also this neat stuff called “pointer arithmetic”. It’s kinda dangerous if you don’t know what you’re doing, but it can be used for some cool tricks.

Looking back to our data, let’s say that we created an array of integers, starting at memory address 0x0000 and our array length is 6 elements. We know that an integer is 4 bytes long. If our pointer ‘myPtr’ is pointing to address 0x0008 and we wanted to go to the next array element, we could just do the following:



myPtr++;   //0x0008 becomes 0x000C


Notice how we added 4 to the address value the pointer is pointing at? We automatically know to add 4 bytes to the address because that is the byte length of an integer. If our pointer was a pointer to a class which was 12 bytes in length, we’d add 12 instead to the address value.

Now, if we dereference ‘myPtr’ and print out its data… we get the next element in memory!



cout << *myPtr;    //output: 0


The order of operations with pointers matters a lot. What do you think the difference between these two lines of code are?



(*myPtr)++;
*(myPtr++);


The first line adds the value 1 to the data pointed to by the pointer.
The second line adds 4 to the address pointed to by the pointer.

You can also assign pointers to each other. This is actually very common!



int * myPtr = 0x0008;
int * myOtherPtr = 0x000C;

cout << *myOtherPtr;        //output: 0
myOtherPtr = myPtr;
cout << *myOtherPtr;       //output: 16


So, why use pointers?

A pointer points to an address in memory. The byte length of a pointer is ALWAYS 4 bytes (on a 32 bit system), regardless of what data type it points to. If you have a pointer pointing to a class which contains dozens of variables of various sizes (strings, ints, floats, etc), the size of the class may be hundreds of bytes in size. If you have a function, you can either pass data in by value or by reference. If you pass in by value, you increase your call stack size by the size of your data passed in. This can both slow things down, and cause data to be copied unnecessarily. If you pass data in by reference, the data size passed in is always 4 bytes.

Another example: Suppose you have a linked list of objects. Every time you use the “new” keyword, you get a pointer to a newly created objects memory address. With linked lists, these memory addresses may be scattered all over memory. A pointer can be used to traverse each element in the list, sequentially, like so:



Node* ptr = MyList.Front;
while(ptr != null)
{
    cout << "Data: " << ptr->Data << endl;
    ptr = ptr->NextNode;
}


I won’t get into this much, but you can also have pointers to pointers:



int **myPtrPtr;


And you can also have function pointers, which UE4 calls “delegates”.

2 Likes

Short answer: a pointer is a memory address.

Metaphor: Your memory is a parking lot, your objects are cars, the number of the parking space is a pointer. Except that when you move your car to a new parking spot you’re building an identical one there instead. Which is essentially why you want pointers. So you can tell somebody where your car is instead of making him a new one, that would also defeat the point of having it painted.

Also there are several other, smaller, parking lots that have copies of some of the cars where you will always search for your car first :stuck_out_tongue:

Longer answer: a pointer contains data that your CPU can use to get data from the memory hierarchy (caches, RAM, etc.). There are several reasons why you would need a pointer. In c/c++, passing the object instead of it’s memory locations as argument or returning it means copying the object around a lot on the stack (the stack is sort of the working memory of the program) and memory read/write operations can be relatively expensive. Additionally, since the stack is limited in size, you probably don’t want to have large objects on it, so you have to reserve some memory somewhere else, i.e. the heap. You will only be able to access this memory through pointers. Why? Because unlike for the stack, we have no way of telling where variables in the heap are going to be when we ‘create’ them, we just ask for a block of memory of a certain size and the memory allocator tells us where the start of our block is (well either that or an error). So why does it work for the stack? The currently running function already has a ‘pointer’ to a position on the stack stored in a register, the variables you declare in it are simply ordered from there, so your program can access them as ‘2 bytes further than the stack pointer’.

You don’t need to have pointers in a programming language in general, functional and logical languages tend not to use them (explicitly), but in C/C++ you pretty much have to for performance reasons.

AFAIK pointers and references differ only in syntax and what the compiler lets you do with them.
References are more restrictive, they cannot be 0-initialized (explicitly) or incremented. This makes it harder to make mistakes with them but also reduces what you can do with them.
For instance, if you have multiple objects ‘next to each other’ in memory, you can add the size of one of those objects to its location to get to the next one. Some other times you actually want things to be 0 initialized.

You should probably take your time to understand pointers and memory allocation and deallocation since they are the source of many bugs.

I would like to point out that this an unreasonable demand.

Foundational understanding of C++ requires at least 5 years of full-time practice. The language simply is THIS difficult.

For example

You should almost never use raw pointer in normal C++ program.

Unreal engine is different because it provides garbage collection and UPROPERTY mechanism. It does not completely obey rules of normal C++.

So the best idea would be to rely on facilities provided by the engine, and avoid looking too deeply in to the language. You don’t need that.

There are facilities written to make peoples’ lives easier, and you should be using that. By default engine is compiled with exceptions disabled, that throws bunch of practices (like RAII) out of the window.

In short, people need to get job done, not to become C++ wizards. So it would be reasonable to learn absolute minimum, instead of trying to achieve the mastery in the language.

Use C++ as if it were scripting language.

Failing that, get help from someone else to do the programming. People work better when they team up and use someone else’s skills, instead of trying to learn everything.