8

I see this question a lot on SO. Maybe not in so many words... but time and again there is confusion on how arrays are different from pointers. So I thought I would take a moment to Q&A a few points about this.

For purposes of this Q&A we're going to assume a 32-bit system and the following have been declared:

char * ptr = "hello";
char arr[10] = "hello";
int iarr[10] = {0};

Here's a list of questions that surmise the confusion I see on SO. As I see new ones I'll add to my list of Q&A (others feel free to as well, and correct me if you see any mistakes!)

  1. Isn't a pointer and an array basically the same thing?
  2. Follow up: both *(ptr) and *(arr), or ptr[0] and arr[0] give the same thing, why?
  3. How come arr and &arr is the same value?
  4. Follow up: why do I get a different value printing arr+1 vs &arr+1?
Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
Mike
  • 47,263
  • 29
  • 113
  • 177
  • 2
    @Prætorian - That is absolutely a great link, the only reason why I was considering this to be separate was that is C++ specific. I was targeting this at C (hence the tag) and at the new programmers, I didn't want to confuse things with the templates and differences between C++ and C. – Mike Oct 01 '12 at 16:03
  • Comments on the downvotes please. I'm happy to clean things up but let's discuss what you don't like! Thanks. – Mike Oct 10 '12 at 17:21
  • 1
    You are missing half the picture. The only things you consider are _statically_ declared arrays. There is another kind; _dynamically_ declared arrays. These are the kinds of arrays that are declared with a variable expression as a size parameter, and also the kind that are passed into functions. Dynamically declared arrays also behave like pointers when using the `&` operator and the `sizeof()` function. It is also worth noting that when you pass a static array into a function, it is converted to a dynamic array, or in other words, the address is copied into a pointer. – Zistack Nov 14 '12 at 17:16
  • @Zistack: Dynamic arrays are a conceptual thing, and have no language aspect thought. Dynamic arrays are considered to be pointers at the language level. – Mooing Duck Nov 04 '14 at 20:26

1 Answers1

21

1) Pointers are not arrays. Arrays are not pointers. Don't think of them that way because they are different.
How can I prove this? Think about what they look like in memory:

Our array arr is 10 characters long. It contains "Hello", but wait, that's not all! Because we have a statically declared array longer than our message, we get a bunch of NULL characters ('\0') thrown in for free! Also, note how the name arr is conceptually attached to the contiguous characters, (it's not pointing to anything). enter image description here

Next consider how our pointer would look in memory: enter image description here Note here we're pointing to a character array some place in read only memory.

So while both arr and ptr were initialized the same way, the contents/location of each is actually different.

This is the key point:
ptr is a variable, we can point it to anything, arr is a constant, it will always refer to this block of 10 characters.


2) The [] is an "add and deference" operator that can be used on an address. Meaning that arr[0] is the same as saying *(arr+0). So yes doing this:

printf("%c %c", *(arr+1), *(ptr+1));

Would give you an output of "e e". It's not because arrays are pointers, it's because the name of an array arr and a pointer ptr both happen to give you an address.

Key point to #2: The deference operator * and the add and deference operator [] are not specific to pointers and arrays respectively. These operators simply work on addresses.


3) I don't have an extremely simple answer... so let's forget our character arrays for a second and take a look at it this example for an explanation:

int b;   //this is integer type
&b;      //this is the address of the int b, right?

int c[]; //this is the array of ints
&c;      //this would be the address of the array, right?

So that's pretty understandable how about this:

*c;   //that's the first element in the array

What does that line of code tell you? If I deference c, then I get an int. That means just plain c is an address. Since it's the start of the array it's the address of the array and also the address of the first element in the array, thus from a value standpoint:

c == &c;

4) Let me go off topic for a second here... this last question is part of the confusion of address arithmetic. I saw a question on SO at one point implying that addresses are just integer values... You need to understand that in C addresses have knowledge of type. That is to say:

iarr+1; //We added 1 to the address, so we moved 4 bytes
arr+1;  //we added 1 to the address, so we moved 1 byte

Basically the sizeof(int) is 4 and the sizeof(char) is 1. So "adding 1 to an array" is not as simple as it looks.

So now, back to the question, why is arr+1 different from &arr+1? The first one is adding 1 * sizeof(char)=1 to the address, the second one is adding 1 * sizeof(arr)=10 to the address.

This is why even though they are both "only adding 1" they give different results.

Mike
  • 47,263
  • 29
  • 113
  • 177
  • 1
    How does your answer to Q4 relate to Q4? – David Heffernan Oct 01 '12 at 15:38
  • 1
    "This is why `ptr` is considered an lvalue". No, that's not why `ptr` is considered to be an _lvalue_; after all `arr` is also considered to be an _lvalue_. – CB Bailey Oct 01 '12 at 15:46
  • @DavidHeffernan - I rewrote the Q&A4 a tiny bit. Does that help show how they relate? Just wanted to make it clear that +1 on an address isn't always the same (depending on what type the address is) – Mike Oct 01 '12 at 15:50
  • It's the Q that needs to be changed. Have a read of Q4 again. – David Heffernan Oct 01 '12 at 15:51
  • @CharlesBailey - Thanks for your input. `arr` is indeed a "named region of storage" (definition of an lvalue). But is it not considered a "unmodifiable lvalue" since the location where the first element will be stored can't be changed once `arr` is declared? Is my understanding incorrect, or is it the way I phrased things that you disagree with? – Mike Oct 01 '12 at 16:01
  • 2
    @Mike: I don't understand why you are evening mentioning _lvalue_. `arr` and `ptr` are both _lvalues_ but so is every expression that is an identifier denoting a variable or reference. It just doesn't seem to be relevant to the pointer vs array discussion. – CB Bailey Oct 01 '12 at 16:04
  • @CharlesBailey Many people still believe that *lvalue* means *can stand on the left of an assignment*. – fredoverflow Oct 01 '12 at 16:19
  • @FredOverflow: ...and perpetuating that understanding is not helpful. (IMHO) – CB Bailey Oct 01 '12 at 16:33
  • @CharlesBailey - Your point is taken, I removed the line in question as it doesn't really add value. Thanks! – Mike Oct 01 '12 at 17:09
  • As mentioned alredy, sizeof() gets a bit more tricky when arr is passed into a function. I think the array/pointer thing in C is one of those topics that only experience can turn them into some kind of "muscle memory". So practice, practice, practice :) Btw, in many cases it comes down to length vs size, and a safe rule of thumb is to always pass whichever you need along with the array in a function (or provide a safe alternative, like a sentinel value at the end of the array). – Harry K. May 15 '21 at 12:44