Pointers Demystified

download Pointers Demystified

of 20

  • date post

  • Category


  • view

  • download


Embed Size (px)

Transcript of Pointers Demystified

Pointers, demystifiedby John Runchey www.teach-me-c.com

1 IntroductionBeginners at my website, www.teach-me-c.com, are often confused about pointers more than anything else. This is totally understandable, as pointers can be a real challenge to wrap your mind around when you are first exposed to them. I believe part of the confusion is just the name 'pointer'. It isn't exactly very descriptive, is it. Pointer, pointer, what the hell is a pointer? Is it a laser pointer? Is it a hunting dog? Maybe it's my index finger, pointing at some kid riding his bike through my lawn. No, a pointer in C is none of these things. My sincere hope is that by the end of reading and studying this document, when you hear the name 'pointer', you'll have a very clear picture in your head of just what that means. And unless I fail miserably, that picture in your head will not be a hunting dog.

2 Don't let the name scare you it's still just a variableThink about an integer variable, or a floating point, or a character. Pretty easy to understand, right? It's just a place to hold a value an int variable holds an integer, a char holds a character, and so on. This can be grasped pretty quickly, I believe, because you can kind of imagine a holding place, like a box, where you stick an integer or a character. A pointer variable is the same thing it's also just a container that holds a value, just like an int or a char variable holds a value. The only difference is, the value that gets put in that variable box is a memory address, instead of a number in the case of an int, or a character in the case of a char. Let's make a little picture of that. Imagine the memory within your computer, as a bunch of storage boxes all in a row ('address' is the memory address inside your computer):

Now when we do some variable assignments, they get put into these boxes: int x, y, z; x = 5; y = 10; z = 15;

Now keep in mind the 0,1,2,3 I used for addresses are in concept only the actual memory addresses in your PC will not look like this, I know. So please

don't email me correcting me on this I'm just illustrating the principles. Now let's bring a pointer into the mix, a pointer to an int: int * myPointer; // declare our pointer myPointer = &z; // initialize it to point to Z

Notice that the address of Z was put into the myPointer variable location. This is what the & means address of. So now we can say that myPointer points to variable Z:

NOW, when we access the pointer using the * operation, we get what's located in memory 2, because that's what myPointer points to: printf(myPointer is pointing at: %d\n,*myPointer); myPointer is pointing at: 15

3 Why do we use pointers?First off, on the simplest level, pointers are used to allow a function tomodify a variable that is passed into it. Normally, when you pass, say, an int to a function, that int is copied into a local copy that the function operates on. For instance, consider the following: int x; x = 5; someFunction(x); void someFunction( int n ) { n = n + 1; } In the above example, the variable x is passed into the function, but x is unchanged by what happened inside the function. It makes no difference what the variable names are, either: int x; x = 5; someFunction(x); void someFunction( int x ) { x = x + 1; } Exactly same result. The x in the function declaration, void someFunction(int x), is local to the function someFunction. If you were to print the value of x after the function call, it would still be 5. So what do you do if you want to modify the value of the variable x that you are passing to the function? In that case, you pass a pointer to the variable, and the function is declared as receiving a pointer instead of an int: int x; x = 5; someFunction(&x); // notice the & (the address of operator) void someFunction( int * x ) {

*x = *x + 1; } NOW when you return from that function, x is changed to be 6 instead of 5. Because you passed in a pointer to the variable, in other words the address of x, the function was able to operate on the actual variable itself.

Secondly, pointers enable you to do operations with far less overhead, orextra work, involved. What do I mean by this? Let me give you an analogy. Suppose you have a friend who is a very fast reader. You've found a small local library that contains 800 books that you know your friend will want to read. Consider the following 2 options you have in order to get these books to your friend. You could, a. check out all 800 books, load them up in your car, and drive them over to your friends house, or b. call your friend and give him the address of the library Obviously, option b involves less work, less overhead, correct? Of course it does, because you aren't actually physically moving those 800 volumes - you are simply letting your buddy know where they are located. You might say you are pointing him to their location. This is the essence of pointers rather than copying blocks of data and moving them around, you pass around addresses of where these blocks of data are located. Remember, a pointer is just that an address in memory. Applications that do a lot of data manipulation can be made far more efficient by using pointers to refer to data, rather than moving around the data itself.

Lastly, Pointers are also used to link together chunks of data in your code.For example, at www.teach-me-c.com in the membership section, I cover creating an electronic address book using a data structure called a linked list. I'll cover this in more detail later on in this document.

4 Declaring a pointer variable: pointer to an intAlright so that might have been a bit heavy for an introduction to pointers. Let's cover something simpler how you declare a pointer to an integer. The syntax is pretty straightforward: int * variableName; The * can be separated from the name by a space, as I show above, or it can be connected together with the name itself: int *variableName; Some prefer the former notation, some prefer the latter. Personally I prefer the former, where the * sits on its own, but that's just me. A typical case for using a pointer to an int is as a function parameter, where you want the function to have access to an integer variable that is passed in to it. void squareIt(int * x) { *x = (*x)^2; } Now if we call this function: int y; y = 10; squareIt(&y); When we return, y will have been squared, and will be 100. Since we passed in a pointer to y, the function could modify it directly. // replace *x with the square of *x

5 Declaring a pointer variable: pointer to a doubleAlmost not worth mentioning since it is so similar to the int case: double * variableName;

6 Declaring a pointer variable: pointer to a charAgain very straightforward: char * variableName;

7 Pointers and character arrays (strings)Pointers and strings go together hand-in-hand, because in C a string is simply an array of characters. And since pointers and arrays go hand-in-hand, it follows that pointers and strings get used together a lot. Let's define a string, a pointer to that string, and an additional char pointer, tmp: char testString[] = this is a test; char * ts; char * tmp; ts = testString; Now pictorially we have the following:

The reason I say tmp is pointing at garbage, is because char * tmp only allocates space for the variable tmp; we have not yet assigned tmp to point to anything. Once we assign tmp to a value, then it points somewhere: tmp = &testString[5]; // point to element 5 of the array

Now remember, in C arrays start at 0 (zero). So by setting tmp to the address of element 5, we now have this situation:

Now we can do arithmetic on the pointers to 'move them around' the string. For instance, suppose we want to print each character of the string we could do a loop something like this (remember ts is already pointing to the start of the string): while (*ts != NULL) { printf(%c ,*ts); ts++; } What this does is 'walk the pointer' along until it hits the null at the end of the string (I removed tmp just to make it cleaner):

Or suppose we want to remove the 'space-A-space' and make the string this istest. We could do that as follows: tmp = &testString[7];

while (*tmp != NULL) { *tmp = *(tmp+3); tmp++; } Now think about what that is doing. We are setting tmp to point to the space right before the 'A'. When we do *tmp = *(tmp+3), this takes the 'T' from position 10 and puts it in position 7:

Then we move tmp to the next position, and do it again... and move it, and do it again, and so on, until we've finally moved the '\0' (the null) over as well:

So as tmp marches along, we copy from 3 spaces ahead of it: T overwrites space (char at position 10 copied to position 7)

E overwrites A (position 11 to 8) S overwrites space (position 12 to 9) T overwrites the first T (position 13 to position 10) \0 overwrites E (position 14 to 11) Notice at the end, we still have the S T \0 in position 12, 13 and 14. These are of no consequence, because the string now ends at position 11, since the null is located there. Character manipulation with char pointers might be a bit of a mystery at first, but eventually it will make sense. When in doubt, draw it out! Looking at a bunch of *this and *that and this++ and that++ is confusing; putting it in a picture will quickly clarify what the code is really doing.

8 Pointers to structuresRemember that a structure is a block of variables, brought together into a logical 'structure' (hence the name): struct myRecord { char firstName[80]; char lastName[80]; int employeeID; struct myRecord * nextRecord; }; Now what is going on here we've got a pointer, to a structure of type myRecord, within myRecord itself. Won't this cause a black hole or a quantum singularity or something? No, it won't, it's perfectly normal. You can think of the above