PDA

View Full Version : Pointers in C... can anyone help me understand?




ravenvii
Feb 3, 2013, 04:33 PM
So I don't understand pointers in C.

Why use them instead of the variables themselves?

I understand how to create/use pointers, but don't understand what the point is? From Googling, it seems pointers are crucial to linked lists and other data structures... but why? Couldn't the variables themselves simply be used instead of something pointing to variables?

Or another scenario that I might find easier to understand: if I wrote a function, say, determining if a word is a palindrome -- you pass an char array (a string) to it, and it'll return whether the word is a palindrome or not -- should I be passing a variable to the function, or should I be passing a pointer? Why? What's the difference?

Many thanks for your time!



LPZ
Feb 3, 2013, 04:46 PM
Or another scenario that I might find easier to understand: if I wrote a function, say, determining if a word is a palindrome -- you pass an char array (a string) to it, and it'll return whether the word is a palindrome or not -- should I be passing a variable to the function, or should I be passing a pointer? Why? What's the difference?

Many thanks for your time!

Well, this will likely make things worse. But when you pass the name of an array to a function in C, you are actually passing a pointer to the array, not the values in the array. In contrast, if you pass the name of an int, then you are actually passing the value of the integer variable with that name.

chown33
Feb 3, 2013, 04:51 PM
C FAQs (good info on pointers vs. arrays, Section 6):
http://c-faq.com/

Pointer tutorials in C:
http://boredzo.org/pointers/
http://pweb.netcom.com/~tjensen/ptr/cpoint.htm


If you think you can write linked-list code without pointers, I suggest trying it. A simple singly-linked list of ints in a struct should be enough to illustrate the point. Example struct WITH pointer:
struct linked_int {
struct linked_int * next;
int theIntValue;
};
First, consider how you'd write a function that adds one int to the head of a linked-list using pointer.

Then consider how you'd change the struct to not use a pointer. You can't just remove the *, because a struct can't contain itself. So exactly how would you link structs together?

There is a way to use an array of structs to make an index-linked list. It's pretty rare in the real world, because of its limitations. Index-linking gains you nothing in C, because it only works with arrays of fixed length.

One of the reasons for structures like linked-lists (or their many relatives, such as trees, graphs, etc.) is they can be of arbitrary length. You don't have to know the max length up front, they can just grow as much as free memory allows. And if they overflow to disk, or you use a linked struct on disk (look up B-Trees), they can grow as large as whatever the storage medium is.

balamw
Feb 3, 2013, 04:54 PM
In the broadest of strokes.

You use a pointer when it isn't the value of the variable that matters, but it's location in memory and vice-versa.

In the case of the palindrome or linked-list you want to take a bunch of values that exist in memory and (potentially) re-organize them. For this, using pointers lead to far more effective code.

Another key reason in C is when you want to modify the contents of memory. i.e. you use scanf to fill a buffer, you have to give scanf the location of the memory it's supposed to use....

B

nabwong
Feb 3, 2013, 05:14 PM
Wow. This thread just took me back 15 years. :)

ravenvii
Feb 3, 2013, 06:40 PM
Well, this will likely make things worse. But when you pass the name of an array to a function in C, you are actually passing a pointer to the array, not the values in the array. In contrast, if you pass the name of an int, then you are actually passing the value of the integer variable with that name.

Actually, that makes sense.

But, just out of curiosity, if I pass, say, strArray[2] to a function, is that a pointer, or the value stored?

I didn't realize struct relates to data structures in C (haven't gotten there yet, my only experience with data structures is via Java classes). I should've known -- C isn't a OOP language :) -- which means you couldn't have "Node" objects that contains an object and another Node.

So you'll have to have a structure that contains something and something-that-points-to-the-next-something.

Aha.

Thanks guys!

chown33
Feb 3, 2013, 07:38 PM
But, just out of curiosity, if I pass, say, strArray[2] to a function, is that a pointer, or the value stored?

It depends on how strArray is declared. Show the declaration and we can tell what strArray[2] means. Without knowing the type of the array, one can't determine the type of the array's elements. This applies for all arrays.

An array can hold pointers as elements. That is, one can have an array of pointers. In such a case, strArray[2] is a pointer.

A common example of an array of pointers to strings is the argv parameter passed to main(). Maybe you haven't done anything with those parameters yet. If you have, look at how main()'s args are declared.

firewood
Feb 4, 2013, 01:22 AM
A pointer is just an address. Like the street address to you mom's house, you can write it down in your address book. But your mom's house itself is likely far to big and heavy (and not zoned for) to try to stuff into your pocket (unless you have aircraft hangers for pockets).

lee1210
Feb 4, 2013, 01:29 AM
I didn't realize struct relates to data structures in C (haven't gotten there yet, my only experience with data structures is via Java classes). I should've known -- C isn't a OOP language :) -- which means you couldn't have "Node" objects that contains an object and another Node.

So you'll have to have a structure that contains something and something-that-points-to-the-next-something.

Aha.

Thanks guys!

Java hides the pointers, which may be leading to some of the difficulty here. There are not stack-local objects in Java. Any time you have a variable whose type is an object, it's a pointer to the object that's being stored. new Object() will give you a pointer to the Object that you store in your variable. When you pass an object to a function, it's always passing the pointer. This is all hidden in Java, so going from Java to a language with programmer-visible pointers can be a little confusing. I think this is evident in your confusion about why you can't just "use a variable", because that's what you do in Java. It happens that the variable is a pointer, but that's hidden from you. In Apple's Foundation code, which is C based, they use typedefs to conceal pointers in many cases, calling these refs. A way to think about Java is that you only have these refs, you never have a stack-local object.

This may not help at all, but this realization was major for me long ago.

-Lee

ghellquist
Feb 4, 2013, 01:55 AM
Yet another way of looking at it.

Think of C as a rather low-level language. It came from the times when programmers still was thinking about how computers actually do things. Other languages, say Java, is higher level. They try to hide how the computer actually does things by adding concepts like object oriented programming. There are even higher level types of languages, say Prolog or F#, where the how things are done are hidden even more. C was also designed in times when computers where slow and had small memorys so efficiently running programs where important.

First, low-level or high-level languages are not really bad or good in themselves. Simply different tools, used for different things.

In c, you simply have to learn what pointers are and how they work. Both on the left side of a an = sign and on the right. You need to understand that every variable has an adress, easily found by the & sign. Pointers are simply one of the basic foundations in c. If you ever want to program in c, you have to have them well under your belt. They crop up just about everywhere, and sometimes in confusing or surprising forms.

In order to learn what and how pointers are, it is good to follow the curriculum of a well-though out course. One way of doing that is going to the actual source, the K&R c programming language book. It is available as free download I believe. It takes a bit of hard thinking to understand what l-values really are, but it places you on a firm foundation as far as the language goes. The book is slightly outdated as there are a few new concepts that has been added since it was written, but these are mainly relevant for quite advanced usages.

//Gunnar

ytk
Feb 4, 2013, 04:23 PM
All of these answers do a good job of explaining what pointers are, but perhaps don't really explain WHY you need to use them.

Here's why: C is only a single step up from assembly language. Granted, it's a big step, but you wouldn't be too far off if you thought of C as sort of a “meta-assembler”, as compared to a higher level language like Python, Ruby, or Java. In those languages, you generally don't need pointers, because the language takes care of managing memory and handling more complex data types such as strings for you. By comparison, C pretty much hands you a chunk of memory and says “Good luck!”

There are some macros and functions built into the language to simplify this task, but by and large you're responsible for handling memory yourself. The first simplification, and the one you're already familiar with, are variables. When you declare a variable, you're essentially delegating management of that tiny chunk of memory to the C compiler. You're saying, “Whenever I talk about the variable ‘foo’, figure out what part of memory you assigned to that variable and grab whatever is in it—I don't care how you do it.” The C compiler responds by allocating this memory on what is called the “stack”, based on the type of variable and how long you need it for (that is what is called the “scope” of the variable). The stack is nice because it is handled automatically, but there are two problems with it: You need to know in advance how much memory you plan to use, and there isn't that much stack memory available.

And then there's the “heap”. You know all of that RAM you have installed in your computer? That's the heap. In the old days, before protected memory, this was literally true, but modern operating systems actually abstract it away from the C compiler and give each process its own virtual heap, so to speak, in order to prevent different programs from trampling all over each other (this was a very common problem under MacOS 9 and below, which is why a single program crashing would often bring down the system).

The heap is good for storing large chunks of data, but you can't declare how much heap you need in advance of running the program. Instead, you request heap memory at runtime by using the malloc() statement, which is so primitive that it doesn't even know or care what type of data you're requesting. Hence, you will see statements like “ptr = malloc(500 * sizeof(int) )”, which requests enough memory to store 500 integers, however large an integer happens to be. How do you reference this memory? The malloc statement returns a pointer to it. Where is this pointer stored? Why, in a stack variable! So you can think about it as using a stack variable, which is your most basic, primitive sort of variable, to store an address to your heap memory. That way, you can decide how much heap memory you need at runtime (and even change how much you need dynamically), but still reference it the same way as if you were using a stack variable.

Okay, so hopefully that's clear, but then if you're not using malloc() to request heap memory, why bother using pointers at all? The answer goes back to the fact that C is such a low-level language. In higher level languages, the entire process described above is taken care of for you, and you can simply throw around more complex data types like strings and arrays as if they were plain old variables. Not so in C. In C, you can only pass a few variables at a time to a function, and each variable can only contain a single number. So what do you do if you need to operate on an array, or a string (both of which are technically the same thing—a list of numbers)? Well, you pass a pointer to the beginning of the list, and tell the program that instead of interpreting the number being passed as a literal number, interpret it as a memory address. The function receiving the pointer can then go to that memory address (called “dereferencing” the pointer), and find the data it's supposed to be working on.

Really, a pointer is just a number, because every variable in C is just a number. The only difference is how that number is interpreted. It's entirely possible (if generally inadvisable) to interpret a pointer as an integer, and print the literal value of the pointer (as opposed to the value it points to), perform math on it, etc. It's likewise possible to dereference a variable declared as a plain old integer, and grab whatever piece of memory happens to be at that location. C is extremely permissive in this regard, and doesn't especially care what type of data is in what variable. Generally, the type is inferred from context, and the compiler will usually let you mix data types with little more than a warning (although doing so is almost always the result of a mistake, and you can avoid the warning by explicitly telling the compiler that you know what you're doing by “casting” the variable to a different type).

To sum up, the real reason you need to use a pointer in C is if you want to operate on any data stored in a range of memory, like an array or a string. C can only work on a single number at a time, so it doesn't really have any concept of ranges of memory. This is why trying to copy a string from one variable to another using the = operator doesn't work in C, for example.

Kebabselector
Feb 4, 2013, 06:12 PM
Wow. This thread just took me back 15 years. :)

Same here, but I was also confused by pointers :(

mfram
Feb 4, 2013, 07:34 PM
Passing structs to functions are another important use of pointers in C. Let's say you create a struct and want to pass the struct to a function. It's generally the best idea to pass a pointer to the struct instead of the struct itself.

typedef struct _s
{
char name[32];
int i;
int a;
} Str;

void func_with_ptr(Str *s)
{
int c = s->a;
(do stuff)
}

void func_with_str(Str s)
{
int c = s.a;
(do_stuff)
}

void main()
{
Str tt = {"aaa", 1, 2};

func_with_ptr(&tt);
func_with_str(tt);
}


Function parameters are always by-value. When calling func_with_ptr(), the compiler puts a pointer value on the stack and then calls the func_with_ptr() function. But when you call func_with_str(), the compiler has to reserve enough space on the stack to hold the entire structure. Then it copies all of the "tt" struct onto the stack, then calls func_with_str with a copy of the structure.

You've added the overhead of extra stack space to make a copy of the tt structure on the stack. And you've added the extra overhead of the compiler needing to make a copy of the structure to pass to the function.

This is a small example, but if the functions need to pass the same structure to other functions or if you increase the size of the structure you'll see that passing without a pointer can rapid increase the memory requirements and slow down your program.

Passing structs with pointers is so common that C has a special syntax for accessing struct members when you have a pointer. You use "s->a" instead of "(*s).a".

kage207
Feb 4, 2013, 07:55 PM
I just want to add one thing. In C, an array is a list of pointers.

GeoffWillis
Feb 4, 2013, 08:00 PM
There is an old book (1990) called Mastering C pointers (ISBM 012697408X) that made it all click for me. I struggled with pointers until a friend turned me onto the book. Or, you could switch to Java...

lee1210
Feb 4, 2013, 09:34 PM
Or, you could switch to Java...
... and have pointers all around that you're not aware of and don't understand.


I just want to add one thing. In C, an array is a list of pointers.

No. Often arrays are accessed using a pointer to the base of the array. The only time an array is a list of pointers is when you have an array of pointers. Otherwise you have the pointer to your base and offsets. The binary [] operator gives you a convenient way to take the base of an array and an offset, and get back the value stored at the memory address represented. a[4] is the same as *(a+4).

-Lee

nabwong
Feb 5, 2013, 08:48 AM
Same here, but I was also confused by pointers :(

Try machine/assembly language then. Makes C look like cake.

ravenvii
Feb 5, 2013, 12:33 PM
Okay, so hopefully that's clear, but then if you're not using malloc() to request heap memory, why bother using pointers at all? The answer goes back to the fact that C is such a low-level language. In higher level languages, the entire process described above is taken care of for you, and you can simply throw around more complex data types like strings and arrays as if they were plain old variables. Not so in C. In C, you can only pass a few variables at a time to a function, and each variable can only contain a single number. So what do you do if you need to operate on an array, or a string (both of which are technically the same thing—a list of numbers)? Well, you pass a pointer to the beginning of the list, and tell the program that instead of interpreting the number being passed as a literal number, interpret it as a memory address. The function receiving the pointer can then go to that memory address (called “dereferencing” the pointer), and find the data it's supposed to be working on.

Regarding passing arrays to functions vs. passing a pointer, are you sure about that? Because the program I wrote, I passed an array to a function and it works perfectly. I understand that if you want to pass an array to a function and have it MODIFIED, a pointer is must, otherwise the modifications gets killed as soon as the compiler exits the function. But in the case of an array as a constant, passing an array works perfectly fine.

Snippets of my code:
int is_palindrome(const char word[]);

main()
{
char input[20];
is_palindrome(input);
}

chown33
Feb 5, 2013, 12:40 PM
All arrays passed to functions are passed as pointers.

See Section 6 of the C FAQs, which I linked to earlier:
http://c-faq.com/

balamw
Feb 5, 2013, 12:42 PM
But in the case of an array as a constant, passing an array works perfectly fine.

You're still passing the array as a location in memory, i.e. a pointer. Whether you allow that chunk of memory to be modified is something else.

B

gnasher729
Feb 5, 2013, 01:25 PM
I just want to add one thing. In C, an array is a list of pointers.

Please don't. It's wrong. It's so wrong, it couldn't possibly be wronger.

1. An array contains elements of identical type, stored in contiguous memory locations.

2. If a function parameter is declared in a way that looks like an array declaration ("array of T") then the function parameter is actually a pointer to T.

3. In many contexts, an array is automatically converted to a pointer to the first array elements. This doesn't happen when the array is the argument of the sizeof operator (so sizeof gives the size of the array, and not the size of a pointer), and when the array is the argument of the address "&" operator (so taking the address of an array gives a pointer to an array, not a pointer to a pointer).


Regarding passing arrays to functions vs. passing a pointer, are you sure about that? Because the program I wrote, I passed an array to a function and it works perfectly. I understand that if you want to pass an array to a function and have it MODIFIED, a pointer is must, otherwise the modifications gets killed as soon as the compiler exits the function. But in the case of an array as a constant, passing an array works perfectly fine.

Snippets of my code:
int is_palindrome(const char word[]);

main()
{
char input[20];
is_palindrome(input);
}

Rule 2: The parameter of the function is_palindrome _looks like_ an array, but it is in fact a pointer to const char.

Rule 3: In the call is_palindrome (input), the array "input" is automatically converted to a pointer to the first element of the array. Which is handy, because that's a pointer to char, which can be passed to a function that accepts a pointer to const char.


Really, a pointer is just a number...

Believing that will just muddle your brain. Very often when someone doesn't understand something about pointers, the cause of the misunderstanding is that they were told that pointers are numbers. A pointer is a pointer, not a number. You can cast a pointer value to an integer value and vice versa, with sometimes interesting results, but they are not the same.

ravenvii
Feb 5, 2013, 01:35 PM
Rule 2: The parameter of the function is_palindrome _looks like_ an array, but it is in fact a pointer to const char.

Rule 3: In the call is_palindrome (input), the array "input" is automatically converted to a pointer to the first element of the array. Which is handy, because that's a pointer to char, which can be passed to a function that accepts a pointer to const char.

So the word[] part of the prototype is just window dressing, like the const part?

And if the argument is automatically converted to a pointer to the first element of the array, why does the 'array' work as expected in the function itself? i.e. I was able to access all elements of the array in the manner one would expect?

ghellquist
Feb 5, 2013, 02:33 PM
So the word[] part of the prototype is just window dressing, like the const part?

Nop. They mean exactly what you say. The function is passed an array of characters, and the function promises to not modify the characters. If your function tries to modify the characters the compiler should flag an error. And inside the function the parameter will behave exactly like an array, with the addition that you have promised not to change the content of the array.


And if the argument is automatically converted to a pointer to the first element of the array, why does the 'array' work as expected in the function itself? i.e. I was able to access all elements of the array in the manner one would expect?
The first part of the answer is that this is what the compiler is required to do with your code. If you pass a const char [] to a function, the code has to behave as if there is an array passed allowing you to index the array. Arrays is one special case which is passed "by reference", in contrast to simple types that are passed "by value" (hint, check this using google).

The second part is that the argument is not really "automatically" converted into a pointer. It might be passed in just about any way. The automatic conversion, if any, is done when you access the elements of the array. This difference might be moot in some environments, but in a highly optimising compiler and in some environments, the difference may actually be quite large.

A lot of programmers assume that what you write in C is exactly what the compiler outputs. This used to be case in old times, but not necessarily anymore. The whole idea of optimising is that you write code in a way, and the compiler may outguess you and create a different program but with exactly the same result. This might include inlining whole functions, meaning that instead of calling a function it might be inserted in the calling code. This may allow the compiler to do even more optimising, removing a lot of intermediate steps.

Example:
... code snippet
int x2 (int x)
{ return x * x ; }

int z = x2(5);

... end code snippet

a smart compiler might remove the full function, changing this into
int z = 25;

Similar things may happen behind the scenes with references to arrays in function calls. Exactly what the compiler does is unimportant as long as the code "behaves" exactly as the specification says. Some compilers will pass the address of the first element, other compilers may do completely different things. The important point is that you as a programmer will not notice the difference in code behaviour.

It is actually a very good idea to add that const word. It tells the compiler that you are not planning to modify the array content, no side effects are intended. A good compiler will check this for you and create an error if you violate this. A good tool for this checking is called lint. In a small program it might not matter, but a software project may contain code in thousands of source code files written by dozens of programmers over many years. Unintended side effects can make the program behave irrationally. Checking by lint is then a very good idea.

//Gunnar

ytk
Feb 5, 2013, 02:54 PM
Believing that will just muddle your brain. Very often when someone doesn't understand something about pointers, the cause of the misunderstanding is that they were told that pointers are numbers. A pointer is a pointer, not a number.

Respectfully, I disagree. I've explained pointers quite a few times over the years, and I've found that the clearest understanding comes once your realize that a pointer IS simply a number. The only difference is what you do with the number.

Think of the computer's memory as a bank of lockers (for simplicity, let's say we only have an 8-bit data type, and an 8-bit address space). So each locker contains a single byte. If I tell you to go to locker X, and interpret the number there as a value, you simply open the locker and get the value. But if I tell you to go to locker X and interpret the number as a pointer to a value, you open that locker and interpret the number there as a location identifying another locker that has the value you really want.

In memory, both an int and a pointer look exactly the same to the computer. There is no special “status bit” attributed to pointers that identifies them as being different from any other value in memory. The only thing that's different about them is the significance they hold to your program, and it's your program's (and the C compiler's) job to keep track of that significance, not the computer's. As far as the computer is concerned, a pointer is just a number. Trying to conceive of some magical difference between pointers and numbers is misleading and confusing.

The function is passed an array of characters

D'oh! The function is passed a pointer to an array. You can't pass an array in C.

ravenvii
Feb 5, 2013, 02:57 PM
Nop. They mean exactly what you say. The function is passed an array of characters, and the function promises to not modify the characters. If your function tries to modify the characters the compiler should flag an error. And inside the function the parameter will behave exactly like an array, with the addition that you have promised not to change the content of the array.

I thought I read somewhere that const is only there to reassure the user that the function doesn't modify what's passed to it, but doesn't actually do anything? Maybe that's just with older compilers?

Anyway, thanks guys -- this has been very educational! :)

ytk
Feb 5, 2013, 03:04 PM
So the word[] part of the prototype is just window dressing, like the const part?

Sorta. The [] notation is just a way of specifying a pointer.

And if the argument is automatically converted to a pointer to the first element of the array, why does the 'array' work as expected in the function itself? i.e. I was able to access all elements of the array in the manner one would expect?

In C, declaring an array creates a pointer which is stored in the variable specified, which points to the head of the array. In fact, the [] operator is effectively a macro, such that “foo[10]” expands to “*(foo + 10)”. The upshot of this is you can also write “10[foo]” and it will compile and run just fine.

So when you say that a function is taking an array as an argument, you're really saying that it's taking a pointer to an array. All array operations involve pointers, though it may not be entirely obvious at first that this is the case.

chown33
Feb 5, 2013, 03:22 PM
I thought I read somewhere that const is only there to reassure the user that the function doesn't modify what's passed to it, but doesn't actually do anything? Maybe that's just with older compilers?
Try writing the function so it modifies the data referenced by the const pointer. The compiler will forbid this (produce an error).

The 'const' is part of the "contract" of the function declaration. For callers that include the declaration, it tells them (and the programmer) that the function won't modify the data pointed at. For the implementation of the function, i.e. its definition, it tells the compiler to enforce read-only access, and doesn't permit the function to modify the data pointed at. Of course, if you recast to non-const, the compiler assumes you know what you're doing. A lot of C is like that: it assumes you know what you're doing.

gnasher729
Feb 5, 2013, 04:29 PM
In C, declaring an array creates a pointer which is stored in the variable specified, which points to the head of the array.

That is totally wrong. No pointer is stored anywhere in any variable when an array is declared. An array consists of its elements, and nothing else.

----------

So the word[] part of the prototype is just window dressing, like the const part?

And if the argument is automatically converted to a pointer to the first element of the array, why does the 'array' work as expected in the function itself? i.e. I was able to access all elements of the array in the manner one would expect?

The [] is just window dressing.
The "const" is not. It means the pointer that the function receives is a "pointer to const char". That means the compiler won't let you modify the data that the pointer points to through that pointer.

Why does it work? Take both parts together. The caller passes a pointer to the first array element, and the function expects a pointer. So that matches. Once you have a pointer to the first array element, you can access the other elements as well. In your case:

word [0] or *word - The first element of the array
word [1] or * (word + 1) - The second element of the array
word [2] or * (word + 2) - The third element of the array.

----------

Nop. They mean exactly what you say. The function is passed an array of characters...

C11 Standard, 6.7.6.3 sentence 7: "A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. "

You cannot declare a function in C (or C++, or Objective-C, or Objective-C++) that has a parameter of an array type.

----------

Respectfully, I disagree. I've explained pointers quite a few times over the years, and I've found that the clearest understanding comes once your realize that a pointer IS simply a number. The only difference is what you do with the number.

Ok. Now try to explain what a "restrict pointer" is. Try explaining why pointers that point into the same array, and pointers pointing to different arrays, are treated differently. Try explaining aliasing. Going back in history, try explaining what's the difference between a "far pointer" and a "huge pointer". Try explaining why it is ok to write "char* p = 0;" but not "char* p = 1;" and not "int i = 0; char* p = i;". Try explaining what a C++ reference is. Try explaining a pointer cast in C++.

ytk
Feb 5, 2013, 05:35 PM
That is totally wrong. No pointer is stored anywhere in any variable when an array is declared. An array consists of its elements, and nothing else.

int foo[20];

Now, what type is foo? Const pointer to int. I've declared an array, and the pointer to the array is stored in the variable specified. I don't understand what the problem here is. Are you saying that no memory is allocated for the variable that holds the pointer itself? Okay, fine, but I didn't say that. As far as the C compiler, and thus the programmer, is concerned, you can use the variable foo in any context that calls for a pointer as an rvalue—you can assign it to another pointer, for example.

Ok. Now try to explain what a "restrict pointer" is. Try explaining why pointers that point into the same array, and pointers pointing to different arrays, are treated differently. Try explaining aliasing. Going back in history, try explaining what's the difference between a "far pointer" and a "huge pointer". Try explaining why it is ok to write "char* p = 0;" but not "char* p = 1;" and not "int i = 0; char* p = i;". Try explaining what a C++ reference is. Try explaining a pointer cast in C++.


None of the things listed here change anything about the fundamental nature of pointers. Think about what the term “pointer” means for a second: It “points” to an address in memory. What is an address? A number. If you explain it any other way, you're just throwing layer upon layer of abstractions from the actual definition of what a pointer is, in an attempt to “simplify” the explanation for the novice user. Ultimately, all of these simplifications must be un-learned in order to advance—if they are understood at all in the first place—because they are fundamentally wrong. If you imply that there is anything special at all about pointers as far as the computer is concerned, you're doing a disservice to those who are trying to learn from you.

Mac_Max
Feb 5, 2013, 06:03 PM
Sorta. The [] notation is just a way of specifying a pointer.

Perhaps we're going too meta here, but here's a good explanation of whats going on:

http://c-faq.com/decl/spiral.anderson.html

jon3543
Feb 5, 2013, 06:43 PM
int foo[20];

Now, what type is foo? Const pointer to int. I've declared an array, and the pointer to the array is stored in the variable specified

Absolutely wrong. The type is "array of 20 ints". There is no pointer anywhere in that.

All arrays passed to functions are passed as pointers.

See Section 6 of the C FAQs, which I linked to earlier:
http://c-faq.com/

Probably 99.9% of people I've seen who thought they understood arrays and pointers could still benefit significantly from reading that part of the C FAQ, so excellent call on that. ytk - this means you.

It is essential to understand the array-to-pointer standard conversion, which converts an array to a pointer to its first element in most contexts. This is the thing from which all the pointer-like behavior of arrays arises, and it is the explanation for chown33's first sentence. Then it's mainly a matter of understanding how pointers work. For example, array indexing is defined in terms of pointer arithmetic, and the first step from a[2] (where "a" is an array name) to *(a+2) is the array-to-pointer conversion. Then you need to understand pointer arithmetic. Then dereferencing the pointer result.

Arrays and pointers are not the same thing! An array is a region of storage containing elements of a single type one after the other, with no space in between. In contrast, a pointer is a scalar quantity whose defined values include NULL and memory addresses, the latter being the addresses of single objects, including objects within arrays.

An array name is not a pointer! The C FAQ 6.2 explains this. 6.1 could have further illustrated this, but it punts to Koenig's excellent "C Traps And Pitfalls" (1989), which I'm surprised to see is available on Amazon. However, if you understand 6.2 and the fact that your linker may treat the two declarations of "a" as a sort of union, you can explain what happens when you make the mistake in 6.1, and the compiler/linker system doesn't diagnose the problem and produces an executable file, as the present day Visual C++ 2012 continues to do, and probably most if not all others.

gnasher729
Feb 5, 2013, 07:02 PM
None of the things listed here change anything about the fundamental nature of pointers. Think about what the term “pointer” means for a second: It “points” to an address in memory. What is an address? A number. If you explain it any other way, you're just throwing layer upon layer of abstractions from the actual definition of what a pointer is, in an attempt to “simplify” the explanation for the novice user. Ultimately, all of these simplifications must be un-learned in order to advance—if they are understood at all in the first place—because they are fundamentally wrong. If you imply that there is anything special at all about pointers as far as the computer is concerned, you're doing a disservice to those who are trying to learn from you.

There are no layers at all: A pointer is just that - a pointer. Something that points to another item. That's the essence of a pointer. No layers. No simplification. You on the other hand are introducing an unnecessary and incorrect specialisation by claiming that a pointer is a number. It isn't. It's behaviour is different from a number. You can add numbers. You can't add pointers. You can multiply numbers. You can divide numbers. You can square numbers. You can't multiply, divide, or square pointers. It's nonsense.

Sam Yikin
Feb 5, 2013, 08:15 PM
There are no layers at all: A pointer is just that - a pointer. Something that points to another item. That's the essence of a pointer. No layers. No simplification. You on the other hand are introducing an unnecessary and incorrect specialisation by claiming that a pointer is a number. It isn't. It's behaviour is different from a number. You can add numbers. You can't add pointers. You can multiply numbers. You can divide numbers. You can square numbers. You can't multiply, divide, or square pointers. It's nonsense.

Wouldn't it be correct to say that pointers are STORED as numbers but have a very different implementation and completely different utilities than numbers?

Sam Yikin
Feb 5, 2013, 08:34 PM
I hope you guys don't mind if I add a question: That awesome FAQ linked earlier said that while arrays and pointers are quite different ( I understand the differences), that anytime time an array is used in an expression, a pointer to the first element of the array is used instead? Even though arrays and pointers are separate items, that a pointer actually is used the vast majority of the time an array is used?

ytk
Feb 5, 2013, 10:05 PM
Absolutely wrong. The type is "array of 20 ints". There is no pointer anywhere in that.

An array name is an “address constant”, which means it refers to a specific address in memory directly (as opposed to a pointer variable, which stores an address in modifiable memory, and the pointer must be explicitly dereferenced to access the location pointed to).

The C99 specification (section 6.6) defines an address constant as follows:

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type.

So every address constant, including an array name, is by definition a pointer.

You can add numbers. You can't add pointers.

You absolutely can do arithmetic on pointers. True, pointer arithmetic works a bit differently in C than with regular numbers, but that's just shorthand that the language provides to make pointers of data types larger than a single byte easier to deal with. If you wanted to, you could cast the pointers to integers of the appropriate size, do math on them at the byte level, and cast them back to pointers and it would work just fine (assuming your architecture doesn't have any data alignment issues or anything like that.)

jon3543
Feb 5, 2013, 10:13 PM
I hope you guys don't mind if I add a question: That awesome FAQ linked earlier said that while arrays and pointers are quite different ( I understand the differences), that anytime time an array is used in an expression, a pointer to the first element of the array is used instead? Even though arrays and pointers are separate items, that a pointer actually is used the vast majority of the time an array is used?

As I wrote a couple of messages ago:

It is essential to understand the array-to-pointer standard conversion, which converts an array to a pointer to its first element in most contexts. This is the thing from which all the pointer-like behavior of arrays arises, and it is the explanation for chown33's first sentence. Then it's mainly a matter of understanding how pointers work. For example, array indexing is defined in terms of pointer arithmetic, and the first step from a[2] (where "a" is an array name) to *(a+2) is the array-to-pointer conversion. Then you need to understand pointer arithmetic. Then dereferencing the pointer result.

While the array-to-pointer conversion occurs in array indexing, passing arguments to functions, returning values from functions (that being a big gotcha for a local non-static array), etc, there are contexts in which it does not occur. A couple that come to mind include when an array is the operand of the address-of operator and sizeof. In C++, other examples include when binding to an array reference and when the array is the operand to typeid. In those instances, an array does not undergo the array-to-pointer conversion. There might be one or two more instances I'm not thinking of at the moment. But anytime an array occurs in other expressions, it undergoes the array-to-pointer conversion, e.g.


typedef struct S { int x; } S;
void f(S*);
void g()
{
S s[10];
S* p = s+5;
s[1];
*s;
s->x;
p-s;
f(s);
}


In each of the expressions above involving s, s undergoes the array-to-pointer conversion. And it's not just named arrays that behave like this; it's also subarrays of multidimensional arrays, e.g.


S t[2][10];


The expressions t[0] and t[1] are both arrays with type S[10] and they behave just like s in the first example, to the extent you can substitute (say) t[0] for every occurrence of s. Note, however, that t contains no pointers at all. It's just a region of storage containing 20 S's, one after the other, in row major order.

Sam Yikin
Feb 5, 2013, 11:00 PM
As I wrote a couple of messages ago:

It is essential to understand the array-to-pointer standard conversion, which converts an array to a pointer to its first element in most contexts. This is the thing from which all the pointer-like behavior of arrays arises, and it is the explanation for chown33's first sentence. Then it's mainly a matter of understanding how pointers work. For example, array indexing is defined in terms of pointer arithmetic, and the first step from a[2] (where "a" is an array name) to *(a+2) is the array-to-pointer conversion. Then you need to understand pointer arithmetic. Then dereferencing the pointer result.

While the array-to-pointer conversion occurs in array indexing, passing arguments to functions, returning values from functions (that being a big gotcha for a local non-static array), etc, there are contexts in which it does not occur. A couple that come to mind include when an array is the operand of the address-of operator and sizeof. In C++, other examples include when binding to an array reference and when the array is the operand to typeid. In those instances, an array does not undergo the array-to-pointer conversion. There might be one or two more instances I'm not thinking of at the moment. But anytime an array occurs in other expressions, it undergoes the array-to-pointer conversion, e.g.


typedef struct S { int x; } S;
void f(S*);
void g()
{
S s[10];
S* p = s+5;
s[1];
*s;
s->x;
p-s;
f(s);
}


In each of the expressions above involving s, s undergoes the array-to-pointer conversion. And it's not just named arrays that behave like this; it's also subarrays of multidimensional arrays, e.g.


S t[2][10];


The expressions t[0] and t[1] are both arrays with type S[10] and they behave just like s in the first example, to the extent you can substitute (say) t[0] for every occurrence of s. Note, however, that t contains no pointers at all. It's just a region of storage containing 20 S's, one after the other, in row major order.

Thank you for your reply, that was very helpful and informative. I've always been fuzzy on the differences between arrays and pointers but you've cleared it up nicely.

jon3543
Feb 5, 2013, 11:09 PM
An array name is an “address constant”, which means it refers to a specific address in memory directly (as opposed to a pointer variable, which stores an address in modifiable memory, and the pointer must be explicitly dereferenced to access the location pointed to).

The C99 specification (section 6.6) defines an address constant as follows:
An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type.

So every address constant, including an array name, is by definition a pointer.


ytk: Again, absolutely wrong. You should be learning from basic references, then tackle the C FAQ. You do not have the basic knowledge necessary to understand the C Standard, and that document is not written to be a teaching aid. Read what I wrote about the array-to-pointer conversion and everything else I wrote. It is correct. For example, here is what C99 says about arrays (this is from my 1997 draft copy):

6.1.2.5/17
An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type.

6.2.2.1/3
Except when it is the operand of the sizeof operator or the unary & operator, or is a character string literal used to initialize an array of character type, or is a wide string literal used to initialize an array with element type compatible with wchar_t, an lvalue that has type ‘‘array of type’’ is converted to an expression that has type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.

These agree with the definitions I gave for arrays and for the array-to-pointer conversion. When the irrelevant bit you quoted about "address constants" talks about their production "implicitly by the use of an expression of array type", which is the only thing it says about arrays, this implicit production is due to the array-to-pointer conversion I've been talking about. It does not support your repeated wrong assertions that arrays are constant pointers. Also, the use of the term "expression" further renders the section irrelevant to your claim about array names, because the following is a declaration, not an expression:

int x[10];

These are defined terms the standard uses in precise ways. The section you quoted simply doesn't contribute to what is meant by an "array name", and FWIW, "array names" aren't even the fundamental thing anyway WRT array behavior, as I alluded to at the end of my previous message when I talked about subarrays in multidimensional arrays.

jon3543
Feb 5, 2013, 11:24 PM
Wouldn't it be correct to say that pointers are STORED as numbers but have a very different implementation and completely different utilities than numbers?

Everything in a computer is stored as a "number", ultimately sequences of bits of various lengths that are assigned various meanings. If you want to talk about something, talk about types. That's the fundamental concept. A type is a set of values and operations defined on those values. It's rather redundant to make a point out of those values being "numbers". What else would they be?

ytk
Feb 5, 2013, 11:38 PM
It does not support your repeated wrong assertions that arrays are constant pointers.

I never once asserted that. There's a difference between an array and an array name. Please read my original statement:

In C, declaring an array creates a pointer which is stored in the variable specified, which points to the head of the array.

Does it say an array is a pointer? No. It explicitly says declaring an array creates a pointer (the address constant) which is stored in the variable specified (the array name). Isn't that self-evident? How else would you refer to that location in memory, if not via a pointer? It's not precisely the same as an explicitly defined pointer, in that it's not held in memory at runtime and thus cannot be modified, but it is a pointer nevertheless when used in almost any context.

Also, the use of the term "expression" further renders the section irrelevant to your claim about array names, because the following is a declaration, not an expression:

int x[10];

Yes, but “x” is an expression, which generates an address constant, which is explicitly defined as a pointer. I didn't ask what “int foo[20]”, or “int foo[]” is. I asked about “foo”, which is an expression, not a declaration.

But okay, fine. Let me clarify my original statement for you:

In C, declaring an array defines a memory address which is stored in the name specified, which points to the head of the array. When using that name in very nearly any context, it returns a value that acts exactly like a pointer.

That statement, while technically a more accurate description of what is going on under the hood, provides more information than is necessary for comprehension and is likely far more confusing to a novice. Happy now?

jon3543
Feb 6, 2013, 12:02 AM
I never once asserted that. There's a difference between an array and an array name. Please read my original statement:

In C, declaring an array creates a pointer which is stored in the variable specified, which points to the head of the array.

Does it say an array is a pointer? No. It explicitly says declaring an array creates a pointer (the address constant) which is stored in the variable specified (the array name).

For at least the third time, ALL OF THAT IS ABSOLUTELY WRONG.

Yes, but “x” is an expression, which generates an address constant, which is explicitly defined as a pointer. I didn't ask what foo[20], or foo[] is. I asked about foo, which is an expression, not a declaration.

The things you've said in several posts that I've replied to include:

ytk sez

int foo[20];

Now, what type is foo? Const pointer to int. I've declared an array, and the pointer to the array is stored in the variable specified

-----

An array name is an “address constant”... So every address constant, including an array name, is by definition a pointer.

All of that is just trivially wrong, and besides not understanding much about C, you don't even seem to comprehend what you've written, as you're denying saying those things you plainly said. You're not even making an effort to learn. Judging by your lack of comments and questions, you haven't read the C FAQ recommended to you by several people, which explains why you're wrong. Nor have you asked anything about the array-to-pointer conversion, which is the key to clearing up a big part of your misunderstanding.

P.S. I'm putting your past posts in italics because otherwise they get clipped when I reply, and I can't figure out how to make this board preserve more than one level of quotes. Having to go back and find those statements makes this whole thing even more tedious.

jon3543
Feb 6, 2013, 12:22 AM
But okay, fine. Let me clarify my original statement for you:

In C, declaring an array defines a memory address which is stored in the name specified, which points to the head of the array. When using that name in very nearly any context, it acts exactly like a pointer.

That statement, while technically a more accurate description of what is going on under the hood, provides more information than is necessary for comprehension and is likely far more confusing to a novice. Happy now?

Please stop putting your statements in quote tags. When I quote your message, they do not appear in mine, and I have to go back to yours and copy/paste.

Your revision is not an improvement. When you declare:

int x[10];

The only thing that exists in memory is the array of 10 ints. (For the definition of "array", see my previous posts.) There is no pointer anywhere in it or around it. In particular, x is not a pointer. It is harmful to think of it as a pointer. The identifier x merely is the name for this array, and it is not an object in its own right. Thus, it is ABSOLUTELY WRONG to say that "declaring an array defines a memory address which is stored in the name specified, which points to the head of the array".

ytk
Feb 6, 2013, 01:16 AM
Your revision is not an improvement. When you declare:

int x[10];

The only thing that exists in memory is the array of 10 ints.

Yes, I said that: It's not precisely the same as an explicitly defined pointer, in that it's not held in memory at runtime and thus cannot be modified

I'm tired of arguing with you about this, particularly when you repeatedly tell me I've said things I didn't say, or explicitly said the precise opposite of. I'm not even sure what the argument is about, because I basically agree with everything you're saying conceptually.

Yes, I get it. An array is not a pointer. I've said that numerous times. Referencing an array by name returns a pointer, so you can treat the array name exactly as if it were a pointer to the start of the array. That's really all I'm trying to say here. If you think I ever said anything different, then I was simply unclear. Okay?

gnasher729
Feb 6, 2013, 02:30 AM
Wouldn't it be correct to say that pointers are STORED as numbers but have a very different implementation and completely different utilities than numbers?

How would that help with any understanding? And are they stored as floating point numbers or integer numbers? Signed or unsigned integer numbers? If they are stored as numbers, it could be either, right? So things get more confused immediately.

And once you get to things like multiple inheritance in C++, references in C++, blocks in Objective-C, distributed objects, or more interesting hardware like an AS400, this "pointer = number" thing _really_ makes it hard to understand what's actually going on.


Yes, but “x” is an expression, which generates an address constant, which is explicitly defined as a pointer. I didn't ask what “int foo[20]”, or “int foo[]” is. I asked about “foo”, which is an expression, not a declaration.

void f (int array [20])
{
printf ("Size of array parameter is %d\n", (int) sizeof (array));
}

int main (void)
{
int array [20];
printf ("Size of array is %d\n", (int) sizeof (array));
f (array);
}


Run this code. Explain the results. Then go to my first post, read rules (2) and (3) carefully, and check whether they make the result absolutely predictable.


Everything in a computer is stored as a "number", ultimately sequences of bits of various lengths that are assigned various meanings. If you want to talk about something, talk about types. That's the fundamental concept. A type is a set of values and operations defined on those values. It's rather redundant to make a point out of those values being "numbers". What else would they be?

More precisely, everything in C (but not in C++) has a "representation", which is the sequence of bytes filling the memory occupied by the object. So on a Mac, a pointer will have a "representation" consisting of four or eight bytes. Assuming that this representation means anything can stop you from understanding more difficult concepts.

balamw
Feb 6, 2013, 07:27 AM
Please stop putting your statements in quote tags. When I quote your message, they do not appear in mine, and I have to go back to yours and copy/paste.

MOD NOTE:

This isn't great advice. The quote tags generate quote notifications it's a great way to note that someone is replying to your previous message.

Also the tone of the thread has become a bit personal. Dial it back a bit please or we'll have to put this one down.

B

ghellquist
Feb 6, 2013, 09:10 AM
I think i will leave this discussion.

I guess we can agree that a discussion about pointers in c quickly can become, hmm, sort of complicated. That is why we should recommend any beginning programmer to follow a well-thought curriculum in learning how to use pointers.

Every-one will then go from the simple things into more complicated matters. On the way, the understanding will deepen and maybe even change. The final authority on how a c program should behave is the standard document, but in order to actually understand that you need a firm base in computer science.

And any actual implementation might add further "complications". I remember one version of a c compiler where you could select between small, medium and large memory model, each handling pointers quite differently inside the program. In the small model, pointers could only point to a small memory area of 256 bytes. In this mode the compiler could not follow the full c specification, but you could do decent things within the limits regardless.

jon3543
Feb 6, 2013, 02:10 PM
MOD NOTE:

This isn't great advice. The quote tags generate quote notifications it's a great way to note that someone is replying to your previous message.

That's different than what I'm talking about. In his own messages, ytk has been putting things he said in quote tags (sometimes modifying them) and intending them to be new comments. See the end of this message for an example:

http://forums.macrumors.com/showpost.php?p=16795641&postcount=40

This makes it hard to reply to him, because those parts don't appear when I quote his message. When I quote the above linked message to reply, the end of it appears as follows (I'm using italics and my own pseudo-tagging because this is part of my message, and using quote tags would cause the problem I'm complaining about if someone were to reply to it):

*****ytk {*****
But okay, fine. Let me clarify my original statement for you:

///// part ytk put in quote tags missing here /////

That statement, while technically a more accurate description of what is going on under the hood, provides more information than is necessary for comprehension and is likely far more confusing to a novice. Happy now?
*****} ytk*****

Like I said, I have to go back and copy and paste to restore the missing part. This would not be a problem if the forum were configured to leave nested quote tags alone. I looked for an option to enable this feature, but like I said earlier, I didn't find it.

I can understand the motivation for disabling nested quotes, but most forums don't do it, and it's fairly common to use quote tags as ytk has done rather than using "real quotes", because it sets the quoted text apart better. Moreover, unless a reply to a quoted part includes everything necessary to understand the reply, you have to go back to the original to get the proper context, which can get really tedious when people break a message into multiple quoted parts to respond inline, as they typically don't copy the little link to the antecedent message in each quoted part they separate out. For all these reasons, I think it's best not to have the forum software effectively edit replies by stripping nested quotes and require people to trim quotes themselves, despite all the problem with that policy.