When I teach C, I use the Bucket Analogy to introduce pointers. Think of a variable in memory as a bucket. For an Uno, an int is a 2-byte bucket, a char is a 1-byte bucket, a long is a 4-byte bucket, and so on. These different sized buckets can be placed at different memory locations. For example, suppose you have the statement:
int number = 10;
long bigNumber = 30000;
The compiler will find 2 bytes in memory that are not used and reserve them for number. We'll assume that memory address is 2000. If you look inside the bucket the bucket at address 2000, you see the 2-byte value 10. The compiler will also find 4 bytes for bigNumber (assume it's memory address 3000) and place 30000 in its bucket.
Now suppose you do this:
bigNumber = number;
This statement fetches to 2 bytes stored at memory address 2000 and pours the bucket's contents into the bigNumber bucket at memory address 2000. The statement is a "bucket-contents-from-one-place-to-another-bucket-somewhere-else".
Now, what if you did this:
number = bigNumber;
Now you are fetching a 4-byte bucket and trying to pour its contents into a 2-byte bucket. This runs the risk of slopping 2 bytes of data on the floor. The cast operator is used to tell the compiler to make the effort to adjust the bucket contents so they fit into one another. This statement:
number = (int) bigNumber;
says to take the contents of bigNumber and (if it can) squish it down enough to fit into number's 2-byte bucket. The cast operator is a set of parentheses which surround the type of data you need on the left side of the equal sign: or expression1 = (target-data-type) expression2; If you wanted to fit bigNumebr into a floating point variable, you would use:
float x = (float) bigNumber;
A pointer variable is a little different in that instead of holding a value in its bucket, it holds a memory address. For example,
long *ptr; // pointer definition
ptr = &bigNumber; // pointer initialization
C uses the asterisk to tell the compiler that this is a different type of variable called a pointer. All pointer buckets are the same size: big enough to hold a memory address of the host machine, or 2 bytes for an Uno. The contents of all pointer variables is either garbage, or a memory address. The second statement above, because it places the address-of operator (&) in front of bigNumber, tells the compiler to take the memory address of bigNumber (3000) and place it into ptr's bucket. This process initializes ptr to bigNumber's memory address. Note what this means: ptr now knows where bigNumber lives in memory.
Finally, we can use a process call indirection to use ptr to change the value of bigNumber
*ptr = 12345;
The asterisk in front of a pointer variable says to the compiler: "Ok, take the value 12345, go to the memory address I've stored in my bucket (i.e., 3000) and deposit that 4-byte value starting at that memory location." How do the compiler know to use 4 bytes? Because ptr was defined to point to a long data type, so its scalar is 4 bytes. If it were an int pointer, its scalar would be 2 bytes. That's why:
would increase the bucket number for ptr by 4, but if it were an int pointer the same expression would only bump the value up by 2. So, incrementing or decrementing a pointer is always done in terms of its scalar size as determined when it was defined.
Now, read this about 50 times and see if it makes sense.