Recall from earlier lessons that I stated you have to give a pointer a data type so that C knows what you will be pointing to. For example, you have to say char * if you want it to be a pointer to data type char.
Why was that? Because if I told you "Give me what is at memory address 1000" you would not know how many bits to give me. In other words, the data type of a pointer is useful in part because it tells how much we plan to see and work with at once. If we have a pointer of type char, then we expect to see and work with data in increments of one byte at a time.
Recall our code from the last example:
char my_string = "Hello Reddit";
char *my_pointer = &my_string;
// This is different, and *incorrect*. We will see why now.
When you say &my_string, you are saying something rather interesting. You are saying that you want the memory address of the "whole array", not just the memory address of the first element.
How is that possible? The whole array doesn't have a memory address. That is exactly right. However, an integer doesn't really have "a memory address of the whole thing" either, since it contains lets say four bytes.
What happens when you tell C to create a pointer to an integer? Well, it creates a pointer that expects to see a whole integer every time you use it.
In other words, we are effectively telling C "I want to see the entire array with one pointer, not just one character at a time." All this really means is that when we plan to "read" from a memory address, we will not be asking for eight bits - but however large the array itself is.
In our example, "Hello Reddit" (and a NUL character) is exactly 13 bytes. Therefore, by saying &my_string we are telling C "I want a pointer which is pointing to the start of the array my_string" - so far so good. But then you are also saying: "When I use this pointer, I plan to use it to see 13 bytes at once."
This is the key difference. C is a unique and powerful language in large part because of the way you can use slightly different syntaxes to mean different processes and operations. This can also serve to make C more confusing than other languages.
Keep in mind that setting the pointer equal to &my_string is incorrect. Why? Because we did not define our pointer as a pointer to a data type of multiple array elements, but as a pointer to a single character. Therefore, if you try to do this you will almost certainly get a compiler warning saying that you are using a pointer of an "invalid type" in your assignment operation. Now you know why.
Whenever you use just the name of an array, C understands that as the memory address where the array begins. Of course, the memory address where the array begins is also the memory address where its first element is located.
However, whenever you use the name of the array with an & "address of" operator, you are saying "the address of the whole array". What this really means is that you are changing the data type of the pointer itself. Instead of saying "I have a pointer which will point to a single byte of data type char", you are saying instead: "I have a pointer which will point to N bytes, each byte being of data type char".
Now, let's look at other examples using this same syntax so that it will make sense to you:
int height = 5;
int *my_pointer = &height;
Assume int is 4 bytes. What are we saying here? We are saying that we want a pointer that will point to the single memory address where "height" begins, but that it will expect to see four bytes at a time.
char my_string = "Hello";
char *my_pointer = &my_string;
"I want a pointer called my_pointer that will contain the memory address where the array my_string begins in memory. However, I want to use this pointer to see the whole array at once."
Now, to wrap this up, lets put into plain English the three ways to use an array with a pointer that we discussed:
1. my_pointer = my_string Means: Assign the memory address of my_string into my_pointer, and my_pointer will expect to see one element of the array at a time. (In this case, one character at a time)
2. my_pointer = &my_string Means: Assign the memory address of the first element of my_string into my_pointer, and my_pointer will expect to see one element of the array at a time. (In this case, one character at a time) #1 and #2 are the same thing.
3. my_pointer = &my_string Means: Assign the memory address of my_string into my_pointer, and my_pointer will expect to see the entire array each time it is used. This is incorrect usage. Use #1 or #2.
Therefore, do not use &array to get the memory address of an array. Simply using array or &array is sufficient.
At this stage, everything we have covered so far involving pointers should make sense. If anything is unclear, please present your questions. All future lessons will rely on you having mastered this material.