PDA

View Full Version : Learning C, having trouble with pointers....




gimano67
Oct 3, 2010, 01:42 AM
So I'm trying to understand the concept of pointers and why they are used. I have two different pieces of code (one using pointers and one not) and they both seem to do the same thing. The pointer example is from "Learning C on the Mac".

With pointers:

#include <stdio.h>

void SquareIt( int number, int *squarePtr );

int main (int argc, const char * argv[]) {
int square;

SquareIt( 5, &square );

printf( "5 squared is %d.\n", square );

return 0;
}

void SquareIt( int number, int *squarePtr ) {
*squarePtr = number * number;
}


Without pointers:

#include <stdio.h>

int SquareIt( int number);

int main (int argc, const char * argv[]) {


printf( "5 squared is %d.\n", SquareIt(5) );

return 0;
}

int SquareIt( int number) {
return number*number;
}

Can someone explain this??

Thanks!!



(marc)
Oct 3, 2010, 02:41 AM
The two examples are meant to do the same thing. In the first example, you pass a pointer to an int to a function. The function then stores the result in the space the pointer points to (and does not return anything). In the second example, the result is passed as a return value from the function. You are responsible to store that return value (which in the example is not necessary, because you print it out directly).

If you don't understand this right now, I'd suggest you just keep going on in the book. Pointers are a somewhat tricky concept and it can take a while to understand them, so in the meantime, just keep on learning C. Eventually, you'll understand pointers.

Sydde
Oct 3, 2010, 02:42 AM
Yes, they do produce the same result, in a slightly different way. Studying these fragments of code by themselves will not help you understand why or when to choose one technique or the other. Just give a little thought to what is different in main() at the end of this run and how that would affect any code that you might eventually add in.

But do not spend a great deal of time on this. If you grasp the basic idea of how pointers work, move on to the next section. At some point, you will probably understand what was going on here.

AustinZ
Oct 3, 2010, 04:11 AM
If you have a function which needs to output multiple values, you need to use pointers to pass the values back. I think that's the concept the example is preparing you for.

This example isn't too great for showing that, because you only need to pass back one value (the square of the input argument), and you can do that with or without pointers.

HiRez
Oct 3, 2010, 04:35 AM
Another place it can be useful is where you have a large data collection that you need to manipulate, for example an array of strings or numbers that need to be sorted. Without pointers you have to copy the whole collection to send to your function, and send another copy back. This is very wasteful of memory and can slow down your program. With pointers, you just send a pointer to the array (or object, or whatever) and then you can operate on it directly from the function without the need to make copies of it, or allocate more memory.

GorillaPaws
Oct 3, 2010, 11:53 AM
The Memory Section of the Masters of the Void Tutorial (http://masters-of-the-void.com/book5.htm) does an excellent job explaining pointers, and how heap vs. stack memory works.

SidBala
Oct 3, 2010, 01:23 PM
Pointers are extremely useful. Especially, when you get to OOP in C++.

The basic concept is that every variable or function exists in a memory location. You need to store that memory location(not the contents of the location, but the location itself) in some variable in order to access the contents. This variable is the pointer.

You access the contents of this memory location by the * operator.
You can get the memory location of a variable by the & operator.

chrono1081
Oct 3, 2010, 04:42 PM
If you want to get good at pointers fast, learn Objective-C :P

In all honesty though pointers aren't that difficult. Sometimes it clicks instantly for people, other times you just have to work at it then it will click (like MANY things in programming!)

I myself never got stuck on pointers but I remember when I was first learning C++ and learned Classes. WOW I was stuck on the syntax of those for like a week! :(

(Now I'm stuck in detecting touches in Unity since I can't find how to do it anywhere in the documentation :mad: This is all part of the programming experience :D)

Branskins
Oct 4, 2010, 05:38 PM
So I'm trying to understand the concept of pointers and why they are used. I have two different pieces of code (one using pointers and one not) and they both seem to do the same thing. The pointer example is from "Learning C on the Mac".


Thanks!!

Here try this and see what happens:


int main() {
int number = 5;
alterNumber(&number);
printf("number = %d", number);

return 0;
}

void alterNumber(int *value) {
value = value * 2;
}


Compared to this:

int main() {
int number = 5;
alterNumber(number);
printf("number = %d", number);

return 0;
}

void alterNumber(int value) {
value = value * 2;
}


Do you see the subtle difference?
With the pointer, it should print out 10 (5 * 2);
Without the pointer...it should print out 5!

The functions look almost identical but they are not at all! With the pointer, you are passing the ADDRESS of the variable. Because of this, the function plays around with actual contents of the variable. Thus it alters the contents of that variable.

All a pointer does is HOLD the address of something else. Just like an integer variable holds the value (int value = 5 means that value holds 5), a pointer's value is an address. If

int value

has an address of 1234, and you do int *ptr = &value, then the ptr's value is 1234
------- ------
|1234| ---------> | 5 |
------- -------
ptr value

Ptr has its own address but it STORES the address of the variable VALUE as its value.

In the second case, (the one without the pointer), when you pass "value" as a parameter, a copy of the variable is actually made. Thus when you do:

value = value * 2,

You are not actually messing with the parameter. You are messing with a COPY of that variable. Thus when you return to main and printf() the value, it is not changed.

So in your example there is a pretty big difference. In one case (without the pointer), you are returning the value from the function. The function returns an int, thus when you return to main, you are passing the return value of SquareIt(5) to printf() as a parameter. You could also capture this value by doing:

int holdValue = SquareIt(5);

You can only do this because the function returns an integer.

However, in the example of the pointer, you are passing something a variable to the function. But the function doesn't return a value because it is VOID.

But if you look:

void SquareIt( int number, int *squarePtr ) {
*squarePtr = number * number;
}


This works because you are passing two integers:
int number: you are playing with a copy of whatever variable you send to this
int *squarePtr: you are passing the address of an integer. Because of this, the contents that squarePtr points to (whatever parameter you send to it), are ALTERED because you are playing with the actual variable and not a COPY. Like I said before, this is a void function so nothing is returned. However because squarePtr is a pointer, the result of number * number is stored back into the variable that squarePtr points to!

I guess after all of this possibly confusing explanation, when you look at it, your example has two different functions. One returns an "int" while one is a "void" function. That is a pretty big difference when you think about it. The void function only returns the value you want because you are using a pointer. The other one doesn't need to be a pointer because you can assign this return value to something.

If your interested, look up pass-by-reference and pass-by-value.

I hope I didn't make things worse. If I did please say something so I can clarify. This is exactly how I learned a lot about pointers. Try explaining it to someone or try writing it down on paper. You will be surprised at how clear it can become!

gimano67
Oct 4, 2010, 06:33 PM
Thanks for all the replies everybody!! Things are starting to make some sense. One last question...Just to be clear, using the * operator allows us to manipulate the value stored (and gives us the actual value of the variable), printing the variable name gives us access to the current value of the variable stored (but won't allow us to actually change the original version, only the local copy), and using the & operator gives us the actual memory address of the variable.

This sound correct?

lee1210
Oct 4, 2010, 08:44 PM
Thanks for all the replies everybody!! Things are starting to make some sense. One last question...Just to be clear, using the * operator allows us to manipulate the value stored (and gives us the actual value of the variable),
You may "get it" but not know how to describe it. A pointer variable's value is an address in memory. The unary * operator evaluates to the value stored at the memory address stored in the pointer, of the type ("flavor") of the pointer variable. This affects the number of bytes read at the stored address and how it is interpreted. You can also use a unary * expression on the left side of an assignment to set the value in memory on the other end of the pointer.


printing the variable name gives us access to the current value of the variable stored (but won't allow us to actually change the original version, only the local copy),


You might want to phrase this differently, i can't make heads or tails of this. If you actually print a pointer variable using %p without applying the unary *, you will print the value stored in the variable, which will be a memory address. I don't know what you mean by the "value of the variable stored" and "original version" vs. "local copy".


and using the & operator gives us the actual memory address of the variable.

The unary & operator returns the memory address where a variable is stored. If you apply this to a pointer variable, you get the address where the pointer itself is stored. More frequently you'll use the & on, say, an int variable to get its address to store in an int * variable.

-Lee

HiRez
Oct 4, 2010, 08:57 PM
Thanks for all the replies everybody!! Things are starting to make some sense. One last question...Just to be clear, using the * operator allows us to manipulate the value stored (and gives us the actual value of the variable), printing the variable name gives us access to the current value of the variable stored (but won't allow us to actually change the original version, only the local copy)?

You still need to use the * operator to print the value of a pointer, it is used both to set and to get the value of a pointer directly. Without that, it will give you the address.

int *iptr;
*iptr = 10;

printf("%d\n", *iptr); // <-- prints "10"
printf("%d\n", iptr); // <-- prints some number like "20629192" (the memory address of the location the pointer points to)

Whenever you're testing variable values and see a (usually) large, unexpected, random-seeming number, it's often a clue that you're looking at a pointer address instead of the actual value (although that depends on what kind of numbers you expect, of course).

gimano67
Oct 4, 2010, 09:30 PM
So what's the difference between using the variable name and using "&variable"?

When should I use what? I feel like most of the time I'll be using *variable b/c I want access to the variable stored at the address, not the address itself. But often times I see in practice code, a lot of variable names (without a * or &).

robvas
Oct 4, 2010, 09:50 PM
So what's the difference between using the variable name and using "&variable"?

When should I use what? I feel like most of the time I'll be using *variable b/c I want access to the variable stored at the address, not the address itself. But often times I see in practice code, a lot of variable names (without a * or &).

The best way to find that out, is to write some code, and compare what &a gives you compared to a.

#include <stdio.h>

int main (void)
{
int a; // our number
int *p; // our pointer

a = 10;

p = &a;

printf("\n a = %p, &a = %p, p = %p, &p = %p, *p = %p\n", (void*)a, &a, p, &p, (void*)*p);

return 0;
}


Output:

a = 0xa, &a = 0xbfb2d0c4, p = 0xbfb2d0c4, &p = 0xbfb2d0c0, *p = 0xa


You can see 'a' contains '0xa'
p contains the 'address of' &a - 0xbfb2d0c4 (that's the location of a in your computers memory)
Notice even though p contains the same value as a, the address of p is different! (&p) That is because it's a different variable and therefore is in a different location. But the value p points to (*p) contains the value stored in a.

(you can also play with this code online: http://ideone.com/8ZlyE)

It depends on what you want to do with the pointer. Do you want to modify the variable or just see it? It gets tricky quick!

Here's a good pointer tutorial:

http://pw1.netcom.com/~tjensen/ptr/pointers.htm

gimano67
Oct 5, 2010, 12:58 AM
Hey again! So I've been doing a little practice with pointers, however my first program won't run correctly :(.It's supposed to copy the sentence array to the copy array and then print out the copy array. Any ideas?

#include <stdio.h>

char sentence[50] = "Hi, my name is Graham.";
char copy[50];

int main (int argc, const char * argv[]) {
// insert code here...

char *pSentence = sentence;
char *pCopy = copy;


while(*pSentence != '\0')
{
*pCopy = *pSentence;
pCopy++;
pSentence++;

}
*pCopy = '\0';

puts(pCopy);

return 0;
}

chown33
Oct 5, 2010, 01:06 AM
At the point you execute this line of code:
puts(pCopy);

exactly what is pCopy pointing to?

You've just finished a loop and another statement, so you should be able to think it through. If not, use the earlier posted examples of printf() and "%p" to print the values of copy and pCopy, and see what that tells you.

For future reference "won't run correctly" is meaningless. You should provide the following info:
1. What did you expect to see happen?
2. What did happen? Be exact, and post actual output when possible.

AustinZ
Oct 5, 2010, 01:34 AM
Imagine you declare a variable:

int myVar = 5;

Imagine inside your computer there is a warehouse called 'myVar'. That warehouse has contents, and it has an address. Right now, you don't care about the address. You have however put contents inside the warehouse: the value '5'.

We will also say that the address of this warehouse is '9514'. Every time you run the program, the address will be different. You do not need to concern yourself with the exact value of the address for now.

Let's say, though, that you do care about what the address to myVar is. Let's say you want to store the ADDRESS of myVar in another warehouse, 'theVar'. However, we use a special type of warehouse designed to store addresses of other warehouses.

int * theVar = &myVar

The above code does just that. The * in the variable declaration indicates that theVar is intended to store the ADDRESS of another variable- it 'points' to another variable. Likewise, the & tells the computer that you don't want to store the CONTENTS of myVar, you want to store the ADDRESS of myVar. Now the value of theVar is '9514'. (theVar also has its own address, but do not worry about that.)

However, we might not care about the value of a warehouse like theVar. We might actually care about the value of the warehouse whose address is being stored in theVar. So we use the following:

int newVar = *theVar

What this does is create a new variable newVar. It then populates the variable. It goes to the warehouse theVar and retrieves its contents (9514). However, because of the * operator, it knows not to put that value 9514 into newVar. Instead, it goes to the warehouse whose ADDRESS is 9514, in this case myVar, retrieves myVar's contents (5), and then sticks THOSE in newVar.

=======

Let's declare another variable.

int anotherVar;

Now imagine you have a function:

int myFirstFunction(int inputVar) {
return inputVar + 5;
}


In your main function, you make the following call:

anotherVar = myFirstFunction(myVar);

Imagine myFirstFunction is a company. What you are conceptually doing is saying, "myFirstFunction, I want you to fill one of my warehouses, named 'anotherVar', with some contents. I know you need some input to work with, so you should go make a copy the contents of whatever's in the warehouse myVar, store it locally in one of your own warehouses, and work with it there."

Now, say I have another function:


void mySecondFunction(int * inputVar) {
*inputVar = *inputvar + 5;
}


and another call:


mySecondFunction(&myVar);
anotherVar = myVar;


mySecondFunction is another company. What you are saying is, "I'm giving you the ADDRESS of my warehouse named myVar. This is great because you can actually go to that warehouse and change its contents if you need to."

Inside the company (inside mySecondFunction), the company is expecting an ADDRESS to a warehouse, not the contents of a warehouse.

Once we're inside, mySecondFunction wants to go to the warehouse, take its contents, add 5 to them, and put them back into the warehouse. Which is what it does, and so myFirstFunction and mySecondFunction end up doing the same thing (after we stick the value of myVar into anotherVar, of course).

NOW: What happens if we did this? (Note no ampersand.)


mySecondFunction(myVar);
anotherVar = myVar;


What the company mySecondFunction is expecting is an ADDRESS. However, you are giving it the CONTENTS of the warehouse myVar. What mySecondFunction will do is try to use myVar's contents (in this case, 5) as an address to a warehouse, go to that warehouse, and mess with its contents. Maybe the warehouse at address 5 just happens to be myVar. In all likelihood, it will not.

That's obviously a bad thing. You don't know what warehouse is at address 5, or whether there's a warehouse there at all. But mySecondFunction barrels ahead blissfully ignorant of your true intentions, and might end up breaking your program.

NOW: What happens if we did this? (note the lack of *)


void mySecondFunction(int * inputVar) {
inputVar = inputvar + 5;
}


What this function would do would be to expect an address to a warehouse. Inside the function, however, the function would take the ADDRESS and change it by adding five* to it. It would not actually go to the warehouse at the address and do anything to its contents, and would not do much of anything at all.

* There are some subtle intricacies to doing pointer arithmetic that aren't covered right now.

What if the function read like this?


void mySecondFunction(int * inputVar) {
inputVar = inputvar + 5;
*inputVar = 10;
}


Again, the function would take the ADDRESS that it gets, increment it by five. But now it would go to this new address and replace its contents with '10'. Again, this is generally a bad thing. You don't know what warehouse, if any, lives 5 warehouses down the street from the warehouse at the address that you're originally given.

However, when you get to arrays, imagine arrays as a bunch of warehouses located one right after the other, down the street. Now being able to change the address itself and then work with the new address becomes useful.

robvas
Oct 5, 2010, 09:06 AM
Hey again! So I've been doing a little practice with pointers, however my first program won't run correctly :(.It's supposed to copy the sentence array to the copy array and then print out the copy array. Any ideas?

copy -> |H|i|,| |m|y| |n|a|m|e| |i|s| |G|r|a|h|a|m|.|\0| <- pCopy

At the beginning, you assigned pCopy to copy. But, you kept incrementing pCopy in that loop.

You copied the bytes correctly, puts(copy) will show you that. But you will have to reset pCopy to point back at copy for puts(pCopy)' to work. Right now, pCopy just points to '\0'


#include <stdio.h>


char sentence[50] = "Hi, my name is Graham.";
char copy[50];

int main (int argc, const char * argv[])
{
char *pSentence = sentence;
char *pCopy = copy;

printf("\nSentence = '%s'\n\n", sentence);

while(*pSentence != '\0')
{

*pCopy = *pSentence;

printf("%p %p, * = %p %p\n",
pCopy, pSentence, *pCopy, *pSentence);

pCopy++;
pSentence++;
}

*pCopy = '\0';

printf("\nAfter loop: pCopy = %p, %p\n", pCopy, *pCopy);

printf("\n&copy = %p, &pCopy = %p, pCopy = %p\n", &copy, &pCopy, pCopy);

printf("\npCopy = '%s'\n", pCopy);
printf("\ncopy = '%s'\n", copy);

pCopy = copy;

puts("After pCopy = copy...");
printf("\npCopy = %s\n", pCopy);

return 0;
}