tags:

views:

555

answers:

14

I am very new to C and I have some problems learning about pointers. I experimented swapping and that's all what I can do with them :) I know that every variable has its own address in memory cells (this is what my lecturer told us) and every variable's value can be obtained by going to its associated address and then fetching the value stored in it. I've seen some function headers such as:

int doSomething(char **hihi);

my head is so confused. I know that pointer is a variable too and it only stores adress information in its memory cell. I read that they are closely related to arrays

arr = &arr[0];

That's all what i know about pointers and I wonder how I can deepen my vision upon pointers. I searched the net and I could not find any useful cheatsheet covering pointers. And I also want to know why they are so important and is there any way to understand actually what is going on without using printf() to print their addresses(p) and values(*p)??

Thank you.

+6  A: 

I think this is where classical books are more useful than most online resources. If you can get a copy, read The C Programming Language (a.k.a K&R) very very carefully. If you want to know more, go for Expert C Programming: Deep Secrets (just google it).

PolyThinker
Expert C Programming: Deep Secrets is a very good book on the topic it has a entire chapter that talks about why pointer and arrays are not the same thing (while still related...)
Johan
Gary Willoughby
+2  A: 

A pointer is a place.

An array is a consecutive group of places.

There's always a value at a place. (It may be leftover junk).

Every variable has a place.

For pointer variables, the value at its place is a place.

It's like a treasure hunt. "Look in mailbox 13 for a note that tells you which mailbox contains your birthday card."

And if mailbox 13 contains a note that reads "13" your birthday card will be a long time coming! (That's an error caused by a circular pointer reference. ;-)

joel.neely
Nice explanation, but I find the first line questionable -- I think you should use the word "address" instead of "pointer", as the latter word always implies a variable. (Or alternatively just delete that line.)
j_random_hacker
I agree that the first line by itself is a little confusing, but it is accurate. All variables have a place, and pointers are no different in that regard.
Bill the Lizard
A: 

Have you read K&R? If you haven't I'd say that is where you should start.

Matt Davison
A: 

Here is some basic explanation teaching how C pointers work.

Fernando Miguélez
The linked article claims Macs don't have protected memory. This has not been true for nearly a decade and will confuse the few who learn C coding on a Mac.
finnw
For the record, many people use "Mac OS X" to refer to modern Apple computers and "Macs" or "Mac OS" to refer to the older, pre-Darwin Apples. Also, many think of Mac OS X as a Unix, and Leopard (10.5) is fully POSIX-compliant.It didn't confuse me when I learned C (or Perl) on OS X.
Chris Lutz
@finnw: Certainly the article is out of date in that respect, but there's no way that that could confuse anyone trying to learn how pointers work. Whether Macs have protected memory or not is irrelevant to how pointers work.
j_random_hacker
I think that if he is just starting to learn how pointers work it is pointless to add more difficulties talking about endiannes, protected memory, virtual memory and other low level issues. So IMHO the link provided is just didactic enough to start out.
Fernando Miguélez
A: 

http://de.youtube.com/watch?v=UvoHwFvAvQE

Ronny
That video is for C++. C does not have the 'new' keyword to allocate a pointer.
Chris Lutz
A: 

A somewhat unconventional suggestion: http://www.youtube.com/watch?v=Rxvv9krECNw

It's a lecture from Higher Computing 1 at my uni from last year. The first few minutes will be a bit useless (subject admin type stuff), but otherwise it's a really good explanation

Jon
+6  A: 

Printing addresses and values is a reasonable way to look at them. But if you can get a debugger up and running, that's much better, because you can follow pointers faster, watch them change as you step, and so on.

If you're familiar with "shortcuts" in Windows, or soft links in linux filesystems, then it might help, just as you're getting started, to think of a pointer as a shortcut (softlink) to another object (whether that object is a struct, a built-in type, another pointer, etc).

A shortcut is still a file. It takes up its own space on the disk drive, it refers to another file, and it can be modified to refer to a different file file from what it used to. Similarly, a pointer in C is an object which occupies memory, contains the address of another memory location, and can be changed to contain a different address just by assigning to it.

One difference is if you double-click a shortcut, it behaves as if you'd double-clicked the thing it points to. That's not the case with pointers - you always have to explicitly dereference a pointer with "*" or "->" in order to access the thing it points to. Another difference is that it's quite common to have pointers to pointers to something in C.

As for the jargon, you just have to learn it unfortunately. "int doSomething(char **hihi)" means "a function called doSomething, which returns an integer, and takes as a parameter a pointer to pointer a char". The crucial point is that "char ** hihi" means "a pointer-to-pointer-to-char. We will call the pointer-to-pointer-to-char hihi". You say that the "type" of hihi is char**, and that the "type" of *hihi (what you get when you dereference the pointer) is char*, and the type of **hihi is char.

Frequently in C, a pointer to a char means a string (in other words, it's a pointer to the first char in a NUL-terminated array). So often "char *" means "string", but it doesn't have to. It might just mean a pointer to one char. A bit like a shortcut to a 1-byte file in Windows (well, with FAT32 anyway), a pointer to a char in C is actually bigger than the thing it points to :-)

Likewise, a char** often means not just a pointer to one string-pointer, but to an array of string-pointers. It might not, but if it does then the following little picture might help:

hihi
 ____            ____                     ________     _________      _______
|____|   -----> |____|  *hihi       ---> |___A____|   |___B_____|    |___C___|
                |____|  *(hihi+1)   ------------------^              ^
                |____|  *(hihi+2)   ---------------------------------|
                | ...|    etc.

hihi points to the tower-block effort, which is my way of representing an array of pointers. As you already noted, I could have written hihi[0] in place of *hihi, hihi[1] in place of *(hihi+1), and so on.

This is a contiguous block of memory, and each pointer-sized chunk of it contains the address of (that is, it "points to") another block of memory, off goodness-knows-where, containing one or more chars. So, hihi[0] is the address of the first char of string A, hihi[1] is the address of the first char of string B.

If hihi doesn't point to an array, just a single pointer, then the tower block is a bungalow. Likewise if *hihi doesn't point to a string, just one char, then the long thin block is a square. You might ask, "how do I know how many floors the tower block has?". That's a big deal in C programming - usually either the function documentation would tell you (it might say "1", or "12", or "enough for the thing you're telling me to do", or else you would pass the number of floors as an extra parameter, or else the documentation would tell you that the array is "NULL terminated", meaning that it will keep reading until it sees the address/value NULL, and then stop. The main function actually does both the second and third thing - argc contains the number of arguments, and just to be on the safe side argv is NULL-terminated.

So, whenever you see a pointer parameter, you have to look at the documentation for the function to see whether it expecting a pointer to an array, and if so how big the array has to be. If you aren't careful about this, you will create a kind of bug called "buffer overflow", where a function is expecting a pointer to a large array, you give it a pointer to a small array, and it scribbles off the end of what you gave it and starts corrupting memory.

Steve Jessop
Nice explanation, but could you please change (*hihi)+1 etc. in your diagram to *(hihi+1).
j_random_hacker
Good point, well made. If anyone was confused by that, (*hihi)+1 is a pointer to the second character of A. That is, it's one greater than the value of *hihi.
Steve Jessop
A: 

While reading K&R might be the best choice here I'll try to make it a bit clearer:

A pointer itself is a variable. But instead of storing a value it only stores an address. Think of it like an index: like in your address book the index for something you're searching for (say, the phone number to some name) it points to where the information is stored. In your address book it might say "look at page 23 to find the phone number of Joe". In case of the pointer it simply says "look at memory address 1234 to retrieve the information I'm pointing at." As the pointer value itself is only a memory address you can make arithmetics with it -- like adding values (which would be the same as accessing elements of an array: if the pointer is pointing to an array, the address following the one the pointer is pointing to will access the next element in the array). Your example function int doSomething(char *hihi) will have hihi pointing to the memory address you passed it when calling it. This is useful if you want to pass larger amounts of data -- instead of copying the data (which happens in a function like void blah(int a) with the value of a) you only copy its location.

I've left out some details in the above, but I hope it gives you at least some basic understanding. I strongly suggest reading K&R or a similar book on the topic.

bluebrother
I agree with what you're saying, but I think the language is a bit confused. First you say "instead of storing a value it only stores an address", then "he pointer value itself is only a memory address". Pointers *do* have/store values - and those values are addresses.
Steve Jessop
+1  A: 

You can find a good tutorial here (really detailed explanation). PDF Direct link.

xgMz
A: 
/* Given a string of characters like this one: */
char *string = "Hello!\n";

/* Memory will contain something like:
0x00100 'H'
0x00101 'e'
0x00102 'l'
0x00103 'l'
0x00104 'o'
0x00105 '!'
0x00106 '\n'
0x00107 '\0'
*/

/* And the program code will say: */
string=0x00100;

/* C doesn't really have arrays */
char c=string[3];
/* is just syntactic sugar for: */

char c=*((char*)((void*)string + 3 * sizeof(char)));
/* ie. 0x00100 + 3 * 1 */
/* ie. 0x00103 */
/* and * dereferences 0x00103, this means char_in(0x00103) */

/* When you pass a pointer you are actually passing the value
   of the memory position */

int a;          /* allocates space for a random four byte value in
                   0x00108 */
scanf("%d",&a); /* &a = 0x00108 scanf now knows that it has to store
                  the value in 0x0108 */

/* Even if you declare: */
int b[23];
/* b will be just a pointer to the beginning of 23 allocated ints.
   ie. 0x0010C */

/* pointer arithmetic is different from normal types in that: */
b++;
/* is actually: */
b+=4; /* b+=1*sizeof(int); */
/* So pointers in C work more like arrays */
jbcreix
A: 

Davos, are you in college? Are you a Computer Science major? One thing you might consider is taking an assembly language class (MIPS, x86). I was an Electrical Engineering major and I was required to take those kind of low level classes. One thing I observed was that having a clear understanding of the assembly language really helped me when I was started learning C++. In particular, it gave me a much clearer understanding of pointers.

Pointers and dereferencing are fundamental concepts at the assembly language level. If you are learning pointers for the first time, I find that in some ways "C" hides it a little bit too much and it actually becomes clearer at the assembly language level. Then you can take that lower level knowledge and see how the "C" language just puts some syntax on top of it.

Just a thought. Other than that, K&R is a great book as several people have mentioned and also, implementing some abstract data types like linked-lists can be useful, especially if you draw diagrams showing the memory layout, it can help to clarify the idea.

Mo Flanagan
A: 

IMHO the best way to "get" pointers is to do some assembly language programming. Once you're used to thinking in terms of raw register contents (with no real distinction between data and addresses other than from how you use them) and load-store instructions, C's pointer types will make a lot more sense (and your appreciation of what C does for you will be greatly improved).

timday
+1  A: 

If you really want to understand pointers, You need a good college lecture.

The best one I have ever seen is this one.

Nothing else compares.

Also check out the lecture on Turning. It is very well done.

EvilTeach
A: 

Many good answers given above. Some other insight is that a pointer is always an unsigned integer type. The object or variable it points to in memory may be of any type.

In a 32-bit operating system the integer is a 4-byte number and must be in the range

0 < pointer value < (2^^32) -1

In a 64-bit operating system the integer is an 8-byte number and must be in the range

0 < pointer value < (2^^64) -1

A pointer value = 0 is interpreted as a special flag value called NULL, which indicates this pointer does not point to a usable variable.

Pointers are used for indirection. Some registers in a CPU act as pointers, e.g. the program counter (PC) and address registers.

jeffD