• (2 Pages)
  • +
  • 1
  • 2

Pointers The Mystical Construct Rate Topic: ***** 6 Votes

#1 dorknexus  Icon User is offline

  • or something bad...real bad.
  • member icon

Reputation: 1256
  • View blog
  • Posts: 4,618
  • Joined: 02-May 04

Posted 13 January 2010 - 04:39 PM

*
POPULAR

Pointers, from a beginners standpoint, can be an intimidating feature of c++. However they are also very useful which makes them an important feature to learn.

NOTE: For this entire tutorial, operators will be labled green, keywords labled blue, and variables will be labled red for clarity. Also, a .txt version of the tutoiral is available at the bottom of this post.

Before we analyze any pieces of code, it is important to realize that a pointer does not contain a value as a variable, such as an int or char would. It cannot be emphasized enough that pointers must be viewed as just that, pointers. They simply point to a location in memory which can be modified directly using that pointer.

Let's use an analogy to drive this point: you have two jars, with a piece of paper in each. On one of the pieces of paper you write the number 7, and place it in the jar. You then take this jar and place it somewhere in your home. Now on the second piece of paper, you write the location of the first jar and place it in the second jar. This second jar acts as a pointer to the location of the first jar which contains the number seven.

Syntax
First lets look at the syntax of a basic pointer; this one is of type char:

char* myfirstpointer;


Really the only difference from declaring a variable is the * operator. This operator tells the compiler to create a pointer of type char. In this example the * trailed the datatype (char) however another option to syntax is to place the * before the variable name.

char var,*ptr;


Again, first you state the datatype, then the name of the variable, in this case only ptr would be a pointer, var is still a character because it has no leading *.

So what exactly does this pointer POINT too? Nothing. We have simply created a pointer, ready for pointing, ha! So lets make this pointer POINT to something in our memory.

Value vs. Address - Referencing and De-Referencing
int main()
{
	 int x = 7;
	 int* pointer = &x;
}


First we make a basic variable of type int and assign the value 7 to it. This 7 is now located somewhere in our memory. Again we declare a pointer as described above, this time of type int. This time though we not only declare the pointer but we make it point to something at the same time; just as you can declare a variable and give it a value at the same time. The & operator may look new to some of you. The & operator references the variable x. In other words it gives the address in memory of x. This is important because we only want the ADDRESS of the variable x, not the actual value.

The best way to see the & operator at work is to output the variable, and the same variable referenced:

#include <iostream>

using namespace std;

int main()
{
	 int x = 1337;
	 cout << x << endl; //Output the value of x
	 cout << &x << endl; //Output the reference, or address, of x
}


On the first line you should see the value of x, 1337. On the second line you will see the address of x in memory, which probably looks like 021FF7C. Now that you have seen the & operator at work lets tie this back in with pointers.

Lets try this piece of code:

#include <iostream>
using namespace std;

int main()
{
	 int x = 1337;
	 int* pointer = &x;

	 cout << pointer << endl;
	 cout << &x << endl;
	 cout << *pointer << endl;
}


Here we assign variable x to the value of 1337, and assign pointer to the address of x. Finally, you can see that, indeed, pointers only contain addresses. The first line of output should be the assigned address, in this case, the address of x. Just to prove this, the second line outputs the actual address of x. The first two lines should read the same.

Now the third output is the VALUE at the address stored to the pointer. This, of course, is 1337. But I thought pointers only contain addresses and not values. Indeed they do, but this address points to a value in memory. This value can be viewed by DE-referencing the pointers stored address. Just as we can reference values stored to addresses by using the & operator, we can also DE-reference the addresses to values. This de-referencing is done by the * operator. The * operator in front of pointer states that we want to see the value stored to the address pointer holds.

Modifying variables using pointers
The value of x can also be modified by using pointer:

#include <iostream>
using namespace std;

int main()
{
	 int x = 1337;
	 int* ptr = &x;
	 
	 cout << x << endl;
	 
	 *ptr = 54;

	 cout << x << endl;
}


x is assigned to 1337, we then assign the address of x to pointer. The first output is used to show that the value of x is 1337, but then we change the value of x by using ptr.

*ptr = 54;


The value of the address stored to ptr = 54

Again, it is very important to remember that ptr does not contain the value of x, only the address, and that by de-referencing the address we can set the value of x through ptr. This could be said as a sentence to better understand it.

The value at(*) this address(ptr) = 54;

Finally the second output will display that 54 is now the value of x.

Arithmetic operators and pointers - Accessing arrays with pointers
Arithmetic operators can be used on pointers to change the address the pointer points to. This can best be shown by making the pointer point to an array, this time of characters.

char str[11] = Dark_Nexus;
char* ptr = str;


Because str is an array, just using the variable name supplies the address to the array so there is no need to reference it with &. The following line would achieve the same goal.

char* ptr = &str[0];


Because str[0] actually contains a value we have to reference it with &. Now ptr, either way, points to the head of the array str. Just as you can move through an array with the [] brackets, you can also move through a pointer in the same way. 0 indicates the head of the array, and in this case 10 would be the end of it.

cout << ptr[0] << endl;
cout << ptr[10] << endl;


These two outputs would display the first and last character of the character array str, because ptr points to the memory used by str. You may be asking why don't you have to dereference ptr[0] or ptr[10]? They are values not addresses. In this case you do not have to de-reference the address as the brackets [] do it for you. The values of the character array can also be modified in this manner.

ptr[0] = ptr[10];


Because we already know 0 is the head of the array, and 10 is the end we can assign position 0 to position 10 in the string. No de-referencing is required as, again, the brackets[] do it for you. If you were to output str now, it would read "sark_Nexus"

Now that we have seen how to use a pointer with an array, we can actually talk about arithmetic operators and pointers now.

cout << ptr + 1 << endl;
;

ptr still points to str, and in this case str has returned to "Dark_Nexus". ptr + 1 indicates a shift (in this case an increment) from the address ptr is pointing to. When arrays are declared, all the memory is allocated at the same time, so each array element will be right next to the other, running from 0 to 10 for this string. ptr only contains the address to the head of the array, so by using ptr + 1, moves to the next address (ptr + 2 would mean move two addresses forward). The output would be ark_Nexus. However ptr still points to the head of the array because we have just added 1 to the address of ptr only for the duration of the statement. Once the statement is over ptr will still point to the head of the array. Now let's say we only want ptr to point to the Nexus portion of the string. This can be achieved by using the += operator.

ptr += 5;


To better understand this operation you could think of the statement as ptr = ptr + 5. "Dark_" is 5 characters long, so we simply have to move 5 characters (or addresses) forward. ptr now points to array slot 5, or N. If you were to output ptr now, it would read Nexus. You guessed it, you can use lots of other arithmetic operators too, here's a list summarizing their effects:

++ (move address forward by one, ptr = ptr + 1)
-- (move address backward by one, ptr = ptr -1)
-= a (move address backward by a, ptr = ptr - a)

These are the basic ways to modify the location in memory a pointer points to, all other arithmetic operators apply. If you were using more than one pointer to point to the same piece of memory, modifying the address one pointer points too will not affect the other pointer's address. However, if the value of the memory was modified, the pointers would reflect that change.

You guessed it again, you can make pointers to objects too!! (along with any sort of datatype). Again, I must stress that a pointer to an object STILL simply points to the address where the object is held in memory. When accessing a member of an object you simply use -> instead of .

struct mystruct
{
	 int var1;
	 int var2;
} myobject;

mystruct* ptr = &myobject;

ptr->var1 = 7;
ptr->var2 = 493;

cout << myobject.var1 << endl << myobject.var2 << endl;
cout << ptr->var1 << endl << ptr->var2;


We make a structure called mystruct and then make an object of type mystruct. Finally we make a pointer to the object of type mystruct and assign ptr to the address of myobject using the & operator.

mystruct* ptr = &myobject;


var1 is set to 7 and var2 is set to 493 by using ptr, however you may have noticed that I never de-refrenced ptr. That's because the -> de-references it for us, just as the []'s do for arrays. Lastly, var1 and var2 are outputted by using both the object and the pointer to prove that we have indeed modified the variable.

You would access a class' members the same way as it is an object also.


Managing heap memory - new and delete keywords
In the previous example, the memory our pointers pointed to were part of the stack. This stack is allocated pre-compile, and is also deleted after the program run.

The difference between the stack and the heap is that the stack is allocated before the program executes, where the heap contains memory allocated DURING the program run.

int x; //Allocates 4 bytes in the stack
char c; //Allocates 1 byte in the stack


The new keyword is used to allocate memory during the program run. Syntax looks like this:

new char;


new signals to allocate new memory in the heap, char indicates what kind and how much. In this case we have made room for a single character. You could just as easily make room for 20 integers.

new int[20];


Again, new signals to allocate memory in the heap, int indicates of what kind, and [20] defines how much. Remember that all the memory for arrays is allocated at the same time, so they will be placed together in memory. You definitely do not want to just create memory in the heap without being able to manage it though, so how do you manage your newly allocated memory? After the program ends, unlike the stack, the memory in the heap remains, this leads to memory leaks and other nasty things. So never allocate memory in the heap without having a pointer point to it. This can be done when you declare the pointer or later in the program when you wanted to assign another pointer to the same memory, the following illustrates both methods:

int* ptr1 = new int[10]; 

Declare ptr1, allocate memory in the heap, make ptr1 point to the newly allocated memory.

int* ptr2;
ptr2 = ptr1;

Assuming ptr1 still points to the memory allocated in the previous example, you can now assign ptr2 to ptr1, however they are independent of each other, they just both point to the same memory.

I said before that memory placed in the heap is not automatically deleted when the program ends so you have to manually delete memory using the delete keyword.

delete []ptr2;


The delete keyword deletes all memory tied to the pointer. The [] means that you want to delete all of the memory not just the first address (or whatever address) ptr2 is pointing too. If ptr2 did not point to an array, and just a single int, you would not have to use the []'s.

int myint = new int;
delete myint; //No brackets for a single peice of data



We don't have to delete pt1 because they both point to the same memory, however when your pointers are idle or don't point to anything, it is a good idea to set them to NULL so that they don't point to random addresses in memory.

ptr1 = NULL;
ptr2 = NULL;


memcpy(...) - Application of pointers

Whew, now that we have gotten past the enigma of pointers, let's take a look at an application of them. At the same time we will introduce the memcpy() function

The following function searches through a string for a sequence of characters, once it is found, the position of that sequence in the string is returned as an integer, or -1 if the characters were not found.

Let's say the string we are looking for the character sequence in is "Dark_Nexus" and we are looking for "ex".

int FirstInstanceOf(const char* str,const char* control)
{
	 int pos = 0;
	 int len = STRLEN(control);
	 char* buffer = new char[len + 1];
	 do
	 {
		  memcpy(buffer,str + pos,len);
		  buffer[len] = '\0';
		  if (CMPSTR(buffer,control))
		  {
			   delete []buffer;
			   return pos;
		  }
	 } while (str[(len + (++pos)) - 1]);
	 delete []buffer;
	 return -1;
}


Let's look at this line by line...

In this function, the keyword const appears in the parameters. This means I won't be able to change the memory that the pointers point too as we are taking them as a constants. This is just safe programming because this function only needs to look, not touch.

char* str is the string which we want to look through
char* control is the string we are looking for within str, or the control

Next, int pos is set to 0. pos will keep track of where we are at in the string, the head of the string being 0. int len is used to store the length of control, we will need to know how many characters are in the control so that we only compare that many characters at once.

The next line allocates memory in the heap of type char. It will make room for len + 1 characters, or the length of our control string + 1. The + 1 is there so we can append a null-terminating character to the end of the string: \0.

Before we look at what the do loop does, let's have a look at that while statement. Remember you can access the value of a pointer with []'s, which is what we do here. str[(len + (++pos)) - 1] . if len = 2 (because control was "ex") and pos starts at 0, it will make sure there is a value (not \0) at str[1] for the first loop. This looks ahead to make sure we don't start checking the wrong memory.

In the loop, the first line uses memcpy(...). memcpy(), or memory copy, takes 3 parameters: destination, source, and how many characters to copy.

 memcpy(buffer,str + pos,len);


The destination is buffer, and the source is str + pos, for the first loop pos is 0 the source for the copy will start at str + 0, or the head of the string (for the next loop iteration pos would be 1, so the source for the copy of that iteration would start at str + 1, or "arK_Nexus"). Finally, the count parameter is set to len, in this case len is 2 so it will only copy 2 characters fromstr + pos to buffer.

Example:

-First iteration of the loop
pos = 0;
str + pos = Dark_Nexus;
After memcpy() the memory pointed to by buffer would be "Da"

-Second iteration of the loop
pos = 1 (because of ++p at the end)
str + pos = arK_Nexus
After the memcpy() the memory pointed to by buffer would be "ar"

The next line of code appends a null-terminating character to buffer at position len. In this example len is 2: buffer[2] = '\0'. Remember that when we allocated memory for buffer, it was len + 1, or 3

The next line simply compares buffer against control, if they are the same, then we delete the memory tied to buffer, because we no longer need to use it.

delete []buffer;


And finally return pos, or the position of control in str, starting at 0.

Dark_Nexus
0123456789

So control (ex) is found at position 6, which is what the function returns.

This post has been edited by JackOfAllTrades: 06 July 2011 - 05:22 PM
Reason for edit:: Changed void main() to standard int main()


Is This A Good Question/Topic? 18
  • +

Replies To: Pointers

#2 Renagado  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 117
  • View blog
  • Posts: 388
  • Joined: 14-June 09

Posted 14 January 2010 - 06:09 PM

Very nice writeup, we're covering pointers in my c++ class now, and this certainly helps. Thanks for your efforts :^:
Was This Post Helpful? 0
  • +
  • -

#3 FullMetal  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 7
  • Joined: 05-October 09

Posted 28 March 2010 - 08:32 PM

Thanks Dark_Nexus for the great tutorial on Pointers, it helped a lot with my class this week. The way our textbook explained pointers left me with a lot of questions. This tutorial helped to answered almost all of them.

Information like this is what makes this site so appealing.
Was This Post Helpful? 0
  • +
  • -

#4 Calico  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 105
  • Joined: 08-November 10

Posted 30 November 2010 - 12:01 PM

Thank you for this tutorial, taught me a lot about pointers! 20 minutes ago i had next to no idea about them, now i have some confidence to use them!! :)

Many Thanks
:tup:
Was This Post Helpful? 0
  • +
  • -

#5 shadowstep0705  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 6
  • View blog
  • Posts: 48
  • Joined: 26-May 10

Posted 30 January 2011 - 03:28 AM

Great tutorial! I finally understand everything :)

This post has been edited by shadowstep0705: 30 January 2011 - 03:29 AM

Was This Post Helpful? 0
  • +
  • -

#6 Severy  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 4
  • Joined: 04-November 09

Posted 26 February 2011 - 06:10 AM

Very nice tutorial.. Enlightened the concept of pointers alot.

Thanks
Was This Post Helpful? 0
  • +
  • -

#7 Aphex19  Icon User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 615
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Posted 28 March 2011 - 04:32 PM

Bit of constructive criticism, the use of void main (which doesn't conform to the C++ standard) is especially bad when used in tutorials, int main is correct.

The rest is excellent though, nice one. :^:

MOD EDIT: Fixed!

This post has been edited by JackOfAllTrades: 28 March 2011 - 04:37 PM

Was This Post Helpful? 0
  • +
  • -

#8 JoshAshbey  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 05-April 11

Posted 05 April 2011 - 09:27 AM

what does Int and Char mean?
Was This Post Helpful? 0
  • +
  • -

#9 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6091
  • View blog
  • Posts: 23,606
  • Joined: 23-August 08

Posted 05 April 2011 - 09:32 AM

If you don't know that, you sure as heck aren't ready for pointers! Read this.
Was This Post Helpful? 0
  • +
  • -

#10 JohnS_  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 21-April 11

Posted 22 April 2011 - 03:44 AM

Thank you so much for posting this. You cleared up a lot, however I still don't understand how stack works or even what it is :\.
Was This Post Helpful? 0
  • +
  • -

#11 jvdubn  Icon User is offline

  • D.I.C Head

Reputation: 7
  • View blog
  • Posts: 52
  • Joined: 08-June 11

Posted 06 July 2011 - 05:15 PM

View PostDark_Nexus, on 13 January 2010 - 04:39 PM, said:

-= a (move address backward by a, ptr = ptr + a)


should this be: -= a (move address backward by a, ptr = ptr - a)?

This is a very nice write up. :^:


MOD EDIT: Fixed, thanks!

This post has been edited by JackOfAllTrades: 06 July 2011 - 05:23 PM

Was This Post Helpful? 0
  • +
  • -

#12 glisboajr  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 15-December 11

Posted 15 December 2011 - 06:29 PM

Dark_Nexus you are pretty good. Very Nice write-up. You explain it clearly. Nice job. :^:
Was This Post Helpful? 0
  • +
  • -

#13 curryjl  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 16
  • Joined: 02-March 09

Posted 16 February 2012 - 10:31 AM

I now understand why we use the "->" notation! Thank you!
Was This Post Helpful? 0
  • +
  • -

#14 v0rtex  Icon User is offline

  • Caffeine: db "Never Enough!"
  • member icon

Reputation: 223
  • View blog
  • Posts: 773
  • Joined: 02-June 10

Posted 14 April 2012 - 08:29 AM

Really well done, helped me remember some basics and more!
Was This Post Helpful? 0
  • +
  • -

#15 CyberGate  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 03-September 11

Posted 01 May 2012 - 09:13 PM

Thank you! This has helped me a lot :)
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2