OK, thanks.
It's still not intuitive then.
It rarely is, but once it clicks you'll "get it" for good.
So I guess if I wanted to hard code an address, I'd then need to know the exact representation of an address that a specific compiler/platform uses, and assign that to the pointer variable, and then dereferencing it, whether such a representation is integer, hex, or whatever (?)
You will never hard-code an address while programming C. If you are writing assembly and you have your data laid out at "known" locations, you might, but in C the only way you should get the address to things is via the & operator, or the return from the malloc family of functions (or other functions that return pointers). Think about this: where would you get this address from to hard-code? How do you know the next time you compile things won't have moved about on the stack/heap and that address points somewhere else entirely? What if you compile your code on a platform where sizeof(void *) is different from where you wrote this in the first place?
I'm just bothered that, logically, the * operator acts on a variable, and I should be able to directly adjust that variable, instead of blindly passing an ethereal item that is acquired only through the & operator. I want to know what exactly is that "address thing" that is obtained via &.
It just doesn't make sense that I can't just increment the address to move up the memory (assuming I want to edit something contiguous) if this "address thing" is some mysterious dark matter.
That's what the %p format specifier is for. You can easily print a pointer and see what it is, and add to it, etc.
Code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int pos = 0;
int *myIntList = NULL;
int *middleOfList = NULL;
int *singleIntPtr = NULL;
myIntList = (int *)malloc((size_t)(100*sizeof(int))); //Allocate enough room for 100 ints. Assign the address to the myIntList pointer.
for(pos = 0;pos < 100;pos++) {
myIntList[pos] = pos;
}
middleOfList = (myIntList+50);
for(pos = 0;pos < 100;pos++) {
singleIntPtr = (myIntList+pos);
printf("The value at address %p is: %d\n",singleIntPtr,*singleIntPtr);
}
printf("\n");
for(pos = 0;pos < 50;pos++) {
singleIntPtr = (middleOfList+pos);
printf("The value at address %p is: %d\n",singleIntPtr,*singleIntPtr);
}
printf("\n");
for(pos = 0; pos < 10; pos++) { //Let's print without using an intermediate pointer
printf("The value at address %p is: %d\n",myIntList+pos,*(myIntList+pos));
}
free((void *)myIntList);
}
As you can see, you can see what's in the pointer without issue, it's not some murky, intangible thing. It's an address in memory, but decidedly NOT an int. It is some number of bytes, different per platform, that indicate a position in memory. You can add to it, but pointer addition behaves differently than regular addition. If you add 1 to an int, its result will just be 1 greater than the value stored in the int. If you add 1 to an int *, the resulting value will be sizeof(int), which is often 4, greater than the original pointer stored in that int *. This is the same for every pointer type, so adding 1 to a double * will be sizeof(double) greater, adding one to a int ** will be sizeof(int *) greater, etc. You can apply ++, etc. to iterate through an array if you have a pointer to its base, but using the [] operator is generally much easier and clearer to someone who is reading your code.
Code:
int *myList = NULL;
int x,y;
myList = (int *)malloc((size t)(10*sizeof(int)));
myList[5]=101;
x = myList[5];
y = *(myList+5);
At the end of this code, x and y will both contain the value of 101. But in my mind, myList[5] to get the 6th element of myList is much easier than *(myList+5), but they are equivalent.
I hope you see where I am finding it hard to get my head around the concept....
Don't worry, most people have the same kind of problems. It is not a concept that comes up in other areas, so it's something that's "brand new" when you start programming. Read more examples, ask more questions, and hopefully it will become clear.
-Lee