It's an integer that represents an address in memory.
The point is that the C memory model basically says RAM is a huge array of bytes, the integer pointer is an "address" (index) into this array. This is why pointer arithmetic is possible. If you have an array in memory and you want to get to the next value just add one to the pointer and you will be at the next address.
Since a short is 8 bits (1 byte) you could use a short pointer to access bytes in memory:
Example:
int arr[4] = fill with values;
int *iPtr = arr;
short *sPtr = arr;
int i;
for(i = 0; i < 4; ++i){
----iPtr++;
----sPtr++;
}
Assuming that an int is 32 bits (4 bytes). Then after this loop, 'iPtr' will point to the address directly AFTER the last element in 'arr'. On the other hand, 'sPtr' will point to the second element in 'arr' because it only incremented by 8 bits each time so 8*4 = 32 = size of int in bits.
Hopefully this illustrates that pointer arithmetic is dependent on the structure, because adding 1 causes the "actual" address to be incremented by the size of the structure.
Edit:
Pointers in C are used basically in three ways: to access dynamic memory, to modify parameters in functions (usually used to return "multiple" values), or for efficiency in function parameter passing.
1: dynamic memory. Any variable you create that is not malloc'd will be discarded when it's block exits. This is why the following code gives a seg fault if you try to use the returned value:
int* getArr(void){
----int arr[4];
----return arr;
}
After the function returns, the int array you created inside the function is discarded and likely overwritten with the next step in the program.
In contrast you would need something like this:
int* getArr(void){
----int* arr = malloc(4 * sizeof(int));
----return arr;
}
malloc "creates" dynamic memory that is accessible outside of this function and therefor the array you created still exists even after the function returns...in fact now this array exists until you free the memory...hello memory leaks. Memory leaks aren't possible without mallocs because the memory is essentially freed as soon as the block exits.
2: returns multiple values.
Say you want to return an integer and a string from a function. You could create a struct and then return the struct, or you could use pointers:
void getIntString(int* i, char* string){
----*i = some value;
----*string = some value;
}
Since the pointers point to memory, by dereferencing them you can change the value pointed to by them.
3: Efficiency. So you need to understand how parameters are passed in C, which is the same as they are passed in Java, which most people don't realize.
In C, parameter passing is by value. That is, when you call a function whatever parameters you give the function are first copied and then the function works with the copy so for instance:
int main(){
----int i = 0;
----foo(i);
}
void foo(int i){
----i = 1;
}
This code appears to change the value of i from 0 to 1, but it actually has no effect. This is because the value of 0 is copied into the functions "space", then this copy is overwritten to now equal 1. But the original is unchanged: you CANNOT change the value of the parameter you pass to the function.
Here's is what's necessary to change the function:
int main(){
----int i = 0;
----foo(&i);
}
void foo(int * i){
----*i = 1;
}
Now although a copy of the VALUE of the address is sent to the function, the VALUE holds the information necessary to access the value of the original int, so the value of the int can be modified.
Here's one more, more complicated example of how parameters are passed:
Say you want to reallocate some memory (say you need to resize):
int main(){
----struct s *x = malloc(sizeof(struct s));
----resize(x);
}
void resize(struct s *x){
----x = realloc(x, 2 * sizeof(struct s));
}
Now, this will probably work in reality, because realloc will not move the memory unless necessary, so this will likely create another strip of size struct s beside the original. But the point is that if realloc does move the memory, then the original variable you passed to the function doesn't know that it has moved it has the original address not the new one because you modified the pointer's VALUE. If you want to modify where the pointer points to then you have to address the pointer:
int main(){
----struct s *x = malloc(sizeof(struct s));
----resize(&x);
}
void resize(struct s **x){
----*x = realloc(*x, 2 * sizeof(struct));
}
Now the address's value (which is where it points to) has been changed because you passed the address to the value of the address...yeah that's confusing.
So why efficiency?
Say you have a large struct, like say an object that perhaps contains an array of size 1MB.
Then when you pass the struct into a function it has to copy 1MB worth of data:
void foo(struct large x){
----perform some operations that don't modify x
}
So you don't need to pass a pointer because you don't want to modify x, but it will require copying large amounts of data, solution: use a pointer:
void foo(struct large *x){
}
Now if you want to query x, just dereference it (*x). Now you are only copying an integers worth of data. The size of a pointer is constant no matter what data type it points to because, as I have tried to reiterate a pointer is a value (integer value).