Related
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
Does anyone have any good articles or explanations (blogs, examples) for pointer arithmetic? Figure the audience is a bunch of Java programmers learning C and C++.
Here is where I learned pointers: http://www.cplusplus.com/doc/tutorial/pointers.html
Once you understand pointers, pointer arithmetic is easy. The only difference between it and regular arithmetic is that the number you are adding to the pointer will be multiplied by the size of the type that the pointer is pointing to. For example, if you have a pointer to an int and an int's size is 4 bytes, (pointer_to_int + 4) will evaluate to a memory address 16 bytes (4 ints) ahead.
So when you write
(a_pointer + a_number)
in pointer arithmetic, what's really happening is
(a_pointer + (a_number * sizeof(*a_pointer)))
in regular arithmetic.
First, the binky video may help. It's a nice video about pointers. For arithmetic, here is an example:
int * pa = NULL;
int * pb = NULL;
pa += 1; // pa++. behind the scenes, add sizeof(int) bytes
assert((pa - pb) == 1);
print_out(pa); // possibly outputs 0x4
print_out(pb); // possibly outputs 0x0 (if NULL is actually bit-wise 0x0)
(Note that incrementing a pointer that contains a null pointer value strictly is undefined behavior. We used NULL because we were only interested in the value of the pointer. Normally, only use increment/decrement when pointing to elements of an array).
The following shows two important concepts
addition/subtraction of a integer to a pointer means move the pointer forward / backward by N elements. So if an int is 4 bytes big, pa could contain 0x4 on our platform after having incremented by 1.
subtraction of a pointer by another pointer means getting their distance, measured by elements. So subtracting pb from pa will yield 1, since they have one element distance.
On a practical example. Suppose you write a function and people provide you with an start and end pointer (very common thing in C++):
void mutate_them(int *begin, int *end) {
// get the amount of elements
ptrdiff_t n = end - begin;
// allocate space for n elements to do something...
// then iterate. increment begin until it hits end
while(begin != end) {
// do something
begin++;
}
}
ptrdiff_t is what is the type of (end - begin). It may be a synonym for "int" for some compiler, but may be another type for another one. One cannot know, so one chooses the generic typedef ptrdiff_t.
applying NLP, call it address arithmetic. 'pointers' are feared and misunderstood mostly because they are taught by the wrong people and/or at the wrong stage with wrong examples in the wrong way. It is no wonder that nobody 'gets' it.
when teaching pointers, the faculty goes on about "p is a pointer to a, the value of p is the address of a" and so on. it just wont work. here is the raw material for you to build with. practice with it and your students will get it.
'int a', a is an integer, it stores integer type values.
'int* p', p is an 'int star', it stores 'int star' type values.
'a' is how you get the 'what' integer stored in a (try not to use 'value of a')
'&a' is how you get the 'where' a itself is stored (try to say 'address')
'b = a' for this to work, both sides must be of the same type. if a is int, b must be capable of storing an int. (so ______ b, the blank is filled with 'int')
'p = &a' for this to work, both sides must be of the same type. if a is an integer, &a is an address, p must be capable of storing addresses of integers. (so ______ p, the blank is filled with 'int *')
now write int *p differently to bring out the type information:
int* | p
what is 'p'? ans: it is 'int *'. so 'p' is an address of an integer.
int | *p
what is '*p'? ans: it is an 'int'. so '*p' is an integer.
now on to the address arithmetic:
int a;
a=1;
a=a+1;
what are we doing in 'a=a+1'? think of it as 'next'. Because a is a number, this is like saying 'next number'. Since a holds 1, saying 'next' will make it 2.
// fallacious example. you have been warned!!!
int *p
int a;
p = &a;
p=p+1;
what are we doing in 'p=p+1'? it is still saying 'next'. This time, p is not a number but an address. So what we are saying is 'next address'. Next address depends on the data type, more specifically on the size of the data type.
printf("%d %d %d", sizeof(char), sizeof(int), sizeof(float));
so 'next' for an address will move forward sizeof(data type).
this has worked for me and all of the people I used to teach.
I consider a good example of pointer arithmetic the following string length function:
int length(char *s)
{
char *str = s;
while(*str++);
return str - s;
}
So, the key thing to remember is that a pointer is just a word-sized variable that's typed for dereferencing. That means that whether it's a void *, int *, long long **, it's still just a word sized variable. The difference between these types is what the compiler considers the dereferenced type. Just to clarify, word sized means width of a virtual address. If you don't know what this means, just remember on a 64-bit machine, pointers are 8 bytes, and on a 32-bit machine, pointers are 4 bytes. The concept of an address is SUPER important in understanding pointers. An address is a number capable of uniquely identifying a certain location in memory. Everything in memory has an address. For our purposes, we can say that every variable has an address. This isn't necessarily always true, but the compiler lets us assume this. The address itself is byte granular, meaning 0x0000000 specifies the beginning of memory, and 0x00000001 is one byte into memory. This means that by adding one to a pointer, we're moving one byte forward into memory. Now, lets take arrays. If you create an array of type quux that's 32 elements big, it will span from the beginning of it's allocation, to the beginning of it's allocation plus 32*sizeof(quux), since each cell of the array is sizeof(quux) big. So, really when we specify an element of an array with array[n], that's just syntactic sugar (shorthand) for *(array+sizeof(quux)*n). Pointer arithmetic is really just changing the address that you're referring to, which is why we can implement strlen with
while(*n++ != '\0'){
len++;
}
since we're just scanning along, byte by byte until we hit a zero. Hope that helps!
There are several ways to tackle it.
The intuitive approach, which is what most C/C++ programmers think of, is that pointers are memory addresses. litb's example takes this approach. If you have a null pointer (which on most machines corresponds to the address 0), and you add the size of an int, you get the address 4. This implies that pointers are basically just fancy integers.
Unfortunately, there are a few problems with this. To begin with, it may not work.
A null pointer is not guaranteed to actually use the address 0. (Although assigning the constant 0 to a pointer yields the null pointer).
Further, you're not allowed to increment the null pointer, or more generally, a pointer must always point to allocated memory (or one element past), or the special null pointer constant 0.
So a more correct way of thinking of it is that pointers are simply iterators allowing you to iterate over allocated memory.
This is really one of the key ideas behind the STL iterators. They're modelled to behave very much as pointers, and to provide specializations that patch up raw pointers to work as proper iterators.
A more elaborate explanation of this is given here, for example.
But this latter view means that you should really explain STL iterators, and then simply say that pointers are a special case of these. You can increment a pointer to point to the next element in the buffer, just like you can a std::vector<int>::iterator. It can point one element past the end of an array, just like the end iterator in any other container. You can subtract two pointers that point into the same buffer to get the number of elements between them, just like you can with iterators, and just like with iterators, if the pointers point into separate buffers, you can not meaningfully compare them. (For a practical example of why not, consider what happens in a segmented memory space. What's the distance between two pointers pointing to separate segments?)
Of course in practice, there's a very close correlation between CPU addresses and C/C++ pointers. But they're not exactly the same thing. Pointers have a few limitations that may not be strictly necessary on your CPU.
Of course, most C++ programmers muddle by on the first understanding, even though it's technically incorrect. It's typically close enough to how your code ends up behaving that people think they get it, and move on.
But for someone coming from Java, and just learning about pointers from scratch, the latter explanation may be just as easily understood, and it's going to spring fewer surprises on them later.
This is one pretty good at link here about Pointer Arithmetic
For example:
Pointer and array
Formula for computing the address of ptr + i where ptr has type T *. then the formula for the address is:
addr( ptr + i ) = addr( ptr ) + [ sizeof( T ) * i ]
For for type of int on 32bit platform, addr(ptr+i) = addr(ptr)+4*i;
Subtraction
We can also compute ptr - i. For example, suppose we have an int array called arr.
int arr[ 10 ] ;
int * p1, * p2 ;
p1 = arr + 3 ; // p1 == & arr[ 3 ]
p2 = p1 - 2 ; // p1 == & arr[ 1 ]
char string1[3][4]={"koo","kid","kav"}; //This is a 2D array
char * string[3]={"koo","kid","kav"}; //This is an array of 3 pointers pointing to 1D array as strings are stored as arrays in memory
char (*string1Ptr)[4]=string1; //This is a pointer to a 1D array of 4 characters
//I want to know differences between string1Ptr(pointer to array mentioned in question) and string(array of pointers mentioned in question). I only typed string1 here to give string1Ptr an address to strings
Besides the fact that string can point to strings of any size and string1Ptr can only point to strings of size 4 only(otherwise pointer arithmetic would go wrong), I don't see any differences between them.
For example,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);
They all seem to perform the same pointer arithmetic.(My reason for assuming string and string1Ptr are almost similar besides for the difference I stated above)
So what are the differences between string and string1Ptr? Any reason to use one over the other?
PS: I'm a newbie so please go easy on me.
Also, I did check C pointer to array/array of pointers disambiguation, it didn't seem to answer my question.
char string1[3][4]={"koo","kid","kav"}; //This is a 2D array
char * string[3]={"koo","kid","kav"}; //This is an array of 3 pointers pointing to 1D array as strings are stored as arrays in memory
char (*string1Ptr)[4]=string1; //This is a pointer to a 1D array of 4 characters
Besides the fact that string can point to strings of any size and
string1Ptr can only point to strings of size 4 only(otherwise
pointer arithmetic would go wrong), I don't any differences between
them.
They are absolutely, fundamentally different, but C goes to some trouble to hide the distinction from you.
string is an array. It identifies a block of contiguous memory wherein its elements are stored. Those elements happen to be of type char * in this example, but that's a relatively minor detail. One can draw an analogy here to a house containing several rooms -- the rooms are physically part of and exist inside the physical boundaries of the house. I can decorate the rooms however I want, but they always remain the rooms of that house.
string1Ptr is a pointer. It identifies a chunk of memory whose contents describe how to access another, different chunk of memory wherein an array of 4 chars resides. In our real estate analogy, this is like a piece of paper on which is written "42 C Street, master bedroom". Using that information, you can find the room and redecorate it as you like, just as in the other case. But you can also replace the paper with a locator for a different room, maybe in a different house, or with random text, or you can even burn the whole envelope, without any of that affecting the room on C Street.
string1, for its part, is an array of arrays. It identifies a block of contiguous memory where its elements are stored. Each of those elements is itself an array of 4 chars, which, incidentally, happens to be just the type of object to which string1Ptr can point.
For example,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);
They all seem to perform the same pointer arithmetic.(My reason for
assuming string and string1Ptr are almost similar besides for the
difference I stated above)
... and that is where C hiding the distinction comes in. One of the essential things to understand about C arrays is that in nearly all expressions,* values of array type are silently and automatically converted to pointers [to the array's first element]. This is sometimes called pointer "decay". The indexing operator is thus an operator on pointers, not on arrays, and indeed it does have similar behavior in your three examples. In fact, the pointer type to which string1 decays is the same as the type of string1Ptr, which is why the initialization you present for the latter is permitted.
But you should understand that the logical sequence of operations is not the same in those three cases. First, consider
printf("%s\n", string1Ptr[2]);
Here, string1Ptr is a pointer, to which the indexing operator is directly applicable. The result is equivalent to *(string1Ptr + 2), which has type char[4]. As a value of array type, that is converted to a pointer to the first element (resulting in a char *).
Now consider
printf("%s\n", string1[2]);
string1 is an array, so first it is converted to a pointer to its first element, resulting in a value of type char(*)[4]. This is the same type as string1Ptr1, and evaluation proceeds accordingly, as described above.
But this one is a bit more different:
printf("%s\n", string[2]);
Here, string is a pointer, so the indexing operation applies directly to it. The result is equivalent to *(string + 2), which has type char *. No automatic conversions are performed.
Any reason to use one over the other?
Many, in both directions, depending on your particular needs at the time. Generally speaking, pointers are more flexible, especially in that they are required for working with dynamically allocated memory. But they suffer from the issues that
a pointer may be in scope, but not point to anything, and
declaring a pointer does not create anything for it to point to. Also,
even if a pointer points to something at one time during an execution of the program, and its value is not subsequently written by the program, it can nevertheless stop pointing to anything. (This most often is a result of the pointer outliving the object to which it points.)
Additionally, it can be be both an advantage and a disadvantage that
a pointer can freely be assigned to point to a new object, any number of times during its lifetime.
Generally speaking, arrays are easier to use for many purposes:
declaring an array allocates space for all its elements. You may optionally specify initial values for them at the point of declaration, or in some (but not all) cases avail yourself of default initialization.
the identifier of an array is valid and refers to the array wherever it is in scope.
Optionally, if an initializer is provided then an array declaration can use it to automatically determine the array dimension(s).
* But only nearly all. There are a few exceptions, with the most important being the operand of a sizeof operator.
The difference between string1 and string is the same as the difference between:
char s1[4] = "foo";
char *s2 = "foo";
s1 is a writable array of 4 characters, s2 is a pointer to a string literal, which is not writable. See Why do I get a segmentation fault when writing to a string initialized with "char *s" but not "char s[]"?.
So in your example, it's OK to do string1[0][0] = 'f'; to change string1[0] to "foo", but string[0][0] = 'f'; causes undefined behavior.
Also, since string is an array of pointers, you can reassign those pointers, e.g. string[0] = "abc";. You can't assign to string1[0] because the elements are arrays, not pointers, just as you can't reassign s1.
The reason that string1Ptr works is because the string1 is a 2D array of char, which is guaranteed to be contiguous. string1Ptr is a pointer to an array of 4 characters, and when you index it you increment by that number of characters, which gets you to the next row of the string1 array.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
Does anyone have any good articles or explanations (blogs, examples) for pointer arithmetic? Figure the audience is a bunch of Java programmers learning C and C++.
Here is where I learned pointers: http://www.cplusplus.com/doc/tutorial/pointers.html
Once you understand pointers, pointer arithmetic is easy. The only difference between it and regular arithmetic is that the number you are adding to the pointer will be multiplied by the size of the type that the pointer is pointing to. For example, if you have a pointer to an int and an int's size is 4 bytes, (pointer_to_int + 4) will evaluate to a memory address 16 bytes (4 ints) ahead.
So when you write
(a_pointer + a_number)
in pointer arithmetic, what's really happening is
(a_pointer + (a_number * sizeof(*a_pointer)))
in regular arithmetic.
First, the binky video may help. It's a nice video about pointers. For arithmetic, here is an example:
int * pa = NULL;
int * pb = NULL;
pa += 1; // pa++. behind the scenes, add sizeof(int) bytes
assert((pa - pb) == 1);
print_out(pa); // possibly outputs 0x4
print_out(pb); // possibly outputs 0x0 (if NULL is actually bit-wise 0x0)
(Note that incrementing a pointer that contains a null pointer value strictly is undefined behavior. We used NULL because we were only interested in the value of the pointer. Normally, only use increment/decrement when pointing to elements of an array).
The following shows two important concepts
addition/subtraction of a integer to a pointer means move the pointer forward / backward by N elements. So if an int is 4 bytes big, pa could contain 0x4 on our platform after having incremented by 1.
subtraction of a pointer by another pointer means getting their distance, measured by elements. So subtracting pb from pa will yield 1, since they have one element distance.
On a practical example. Suppose you write a function and people provide you with an start and end pointer (very common thing in C++):
void mutate_them(int *begin, int *end) {
// get the amount of elements
ptrdiff_t n = end - begin;
// allocate space for n elements to do something...
// then iterate. increment begin until it hits end
while(begin != end) {
// do something
begin++;
}
}
ptrdiff_t is what is the type of (end - begin). It may be a synonym for "int" for some compiler, but may be another type for another one. One cannot know, so one chooses the generic typedef ptrdiff_t.
applying NLP, call it address arithmetic. 'pointers' are feared and misunderstood mostly because they are taught by the wrong people and/or at the wrong stage with wrong examples in the wrong way. It is no wonder that nobody 'gets' it.
when teaching pointers, the faculty goes on about "p is a pointer to a, the value of p is the address of a" and so on. it just wont work. here is the raw material for you to build with. practice with it and your students will get it.
'int a', a is an integer, it stores integer type values.
'int* p', p is an 'int star', it stores 'int star' type values.
'a' is how you get the 'what' integer stored in a (try not to use 'value of a')
'&a' is how you get the 'where' a itself is stored (try to say 'address')
'b = a' for this to work, both sides must be of the same type. if a is int, b must be capable of storing an int. (so ______ b, the blank is filled with 'int')
'p = &a' for this to work, both sides must be of the same type. if a is an integer, &a is an address, p must be capable of storing addresses of integers. (so ______ p, the blank is filled with 'int *')
now write int *p differently to bring out the type information:
int* | p
what is 'p'? ans: it is 'int *'. so 'p' is an address of an integer.
int | *p
what is '*p'? ans: it is an 'int'. so '*p' is an integer.
now on to the address arithmetic:
int a;
a=1;
a=a+1;
what are we doing in 'a=a+1'? think of it as 'next'. Because a is a number, this is like saying 'next number'. Since a holds 1, saying 'next' will make it 2.
// fallacious example. you have been warned!!!
int *p
int a;
p = &a;
p=p+1;
what are we doing in 'p=p+1'? it is still saying 'next'. This time, p is not a number but an address. So what we are saying is 'next address'. Next address depends on the data type, more specifically on the size of the data type.
printf("%d %d %d", sizeof(char), sizeof(int), sizeof(float));
so 'next' for an address will move forward sizeof(data type).
this has worked for me and all of the people I used to teach.
I consider a good example of pointer arithmetic the following string length function:
int length(char *s)
{
char *str = s;
while(*str++);
return str - s;
}
So, the key thing to remember is that a pointer is just a word-sized variable that's typed for dereferencing. That means that whether it's a void *, int *, long long **, it's still just a word sized variable. The difference between these types is what the compiler considers the dereferenced type. Just to clarify, word sized means width of a virtual address. If you don't know what this means, just remember on a 64-bit machine, pointers are 8 bytes, and on a 32-bit machine, pointers are 4 bytes. The concept of an address is SUPER important in understanding pointers. An address is a number capable of uniquely identifying a certain location in memory. Everything in memory has an address. For our purposes, we can say that every variable has an address. This isn't necessarily always true, but the compiler lets us assume this. The address itself is byte granular, meaning 0x0000000 specifies the beginning of memory, and 0x00000001 is one byte into memory. This means that by adding one to a pointer, we're moving one byte forward into memory. Now, lets take arrays. If you create an array of type quux that's 32 elements big, it will span from the beginning of it's allocation, to the beginning of it's allocation plus 32*sizeof(quux), since each cell of the array is sizeof(quux) big. So, really when we specify an element of an array with array[n], that's just syntactic sugar (shorthand) for *(array+sizeof(quux)*n). Pointer arithmetic is really just changing the address that you're referring to, which is why we can implement strlen with
while(*n++ != '\0'){
len++;
}
since we're just scanning along, byte by byte until we hit a zero. Hope that helps!
There are several ways to tackle it.
The intuitive approach, which is what most C/C++ programmers think of, is that pointers are memory addresses. litb's example takes this approach. If you have a null pointer (which on most machines corresponds to the address 0), and you add the size of an int, you get the address 4. This implies that pointers are basically just fancy integers.
Unfortunately, there are a few problems with this. To begin with, it may not work.
A null pointer is not guaranteed to actually use the address 0. (Although assigning the constant 0 to a pointer yields the null pointer).
Further, you're not allowed to increment the null pointer, or more generally, a pointer must always point to allocated memory (or one element past), or the special null pointer constant 0.
So a more correct way of thinking of it is that pointers are simply iterators allowing you to iterate over allocated memory.
This is really one of the key ideas behind the STL iterators. They're modelled to behave very much as pointers, and to provide specializations that patch up raw pointers to work as proper iterators.
A more elaborate explanation of this is given here, for example.
But this latter view means that you should really explain STL iterators, and then simply say that pointers are a special case of these. You can increment a pointer to point to the next element in the buffer, just like you can a std::vector<int>::iterator. It can point one element past the end of an array, just like the end iterator in any other container. You can subtract two pointers that point into the same buffer to get the number of elements between them, just like you can with iterators, and just like with iterators, if the pointers point into separate buffers, you can not meaningfully compare them. (For a practical example of why not, consider what happens in a segmented memory space. What's the distance between two pointers pointing to separate segments?)
Of course in practice, there's a very close correlation between CPU addresses and C/C++ pointers. But they're not exactly the same thing. Pointers have a few limitations that may not be strictly necessary on your CPU.
Of course, most C++ programmers muddle by on the first understanding, even though it's technically incorrect. It's typically close enough to how your code ends up behaving that people think they get it, and move on.
But for someone coming from Java, and just learning about pointers from scratch, the latter explanation may be just as easily understood, and it's going to spring fewer surprises on them later.
This is one pretty good at link here about Pointer Arithmetic
For example:
Pointer and array
Formula for computing the address of ptr + i where ptr has type T *. then the formula for the address is:
addr( ptr + i ) = addr( ptr ) + [ sizeof( T ) * i ]
For for type of int on 32bit platform, addr(ptr+i) = addr(ptr)+4*i;
Subtraction
We can also compute ptr - i. For example, suppose we have an int array called arr.
int arr[ 10 ] ;
int * p1, * p2 ;
p1 = arr + 3 ; // p1 == & arr[ 3 ]
p2 = p1 - 2 ; // p1 == & arr[ 1 ]
#include<stdio.h>
int main(){
char a[6],*p;
a[0]='a';
a[1]='b';
a[2]='c';
a[3]='4';
a[4]='e';
a[5]='p';
a[6]='f';
a[7]='e';
printf("%s\n",a);
printf("printing address of each array element");
p=a;
printf("%u\n",&p[0]);
printf("%u\n",p+1);
printf("%u\n",a+2);
return 0;
}
The output is as follows...
anusha#anusha-laptop:~/Desktop/prep$ ./a.out
abc4epfe
printing address of each array element3216565606
3216565607
3216565608
When I declared the array as char a[6] why is it allowing me to allocate a value at a[7]? Does it not need a null character to be appended for the last element?
Also p=a => p holds the address of first element of char array a. I don’t understand how it is correct to place an '&' in front of an address (p[0]). &p[0] means address of address of first element of a which doesn't make any sense, at least to me.
Why is it printing the correct output?
You have just invoked undefined behaviour. There's little point in reasoning about writing beyond the bounds of an array. Just don't do it.
&p[0] means address of address of first element of a[] which is not sensible
No, that's perfectly sensible. Your description perfectly describes what is going on. &p[0] is the same as p which is the same as a. When you write p[0] you are dereferencing the pointer. When you then write &p[0] you are taking the address of that variable and thus return to what you started from, p.
The highest valid index of a is 5, so you're writing outside the array bounds by two, and yes, it still needs a NULL terminator. The fact that it worked was just a coincidence; writing outside array bounds is undefined behaviour. It could work, it could crash your computer, it could go buy pizza with your credit card, or something entirely different. You have no idea what it will do, so just don't do it.
when i declared the array as char a[6] why is it allowing me to allocate a value at a[7]?
because C and C++ don't care, there is no bounds check on arrays.
Does it not need a null character to be appended for the last element?
no. e.g. when you declare an array say char a[7]; you tell the compiler you want seven bytes nothing more, nothing less. however if you try to access outside the array it is your problem.
I donot understand how it is correct to mark an '&' infront of an
address(marked by p[0]). '&p[0]' means address of address of first
element of a[] which is not sensible right?How come it is printing
correct output?
if you write p[0] you are referencing the value of the array p e.g. if int p[2] = {1,2}; then p[0] is 1
if you write &p[0] you are getting the address of p[0] which is basically the same as p + 0
When I declared the array as char a[6] why is it allowing me to allocate a value at a[7]?
Because you told it to do that. You're the boss. If you tell it to jump off a cliff, it might.
Does it not need a null character to be appended for the last element?
It's not a string, it's an array of characters. It does not need a zero at the end unless you want to treat it as a string. By passing it through a %s specifier to printf, you are treating it as a string, so you need to append a zero at the end, otherwise, you're passing something that's not a string through a format specifier that requires a string.
Also p=a => p holds the address of first element of char array a. I don’t understand how it is correct to place an '&' in front of an address (p[0]). &p[0] means address of address of first element of a which doesn't make any sense, at least to me.
It works like this:
p is a pointer to the first element.
&p is the address of the pointer.
p[0] is the first element in the array the pointer points to.
&p[0] is the address of the first element in the array the pointer points to.
Why is it printing the correct output?
Sheer luck. Most likely, the implementation, being 32-bits (4 bytes) couldn't do anything useful with the two bytes after the 6-byte array. So it rounded it up to 8 bytes so that the next thing after it would start at an even 32-bit boundary. So you used two bytes the implementation wasn't using for anything anyway.
It allows you to allocate a value at a[7] because you're lucky. That's undefined behaviour. See here: http://ideone.com/ntjUn
Segmentation fault!
I hope this helps you a little with understanding the array&pointer relationship:
a[i] == *(a+i) == *(i+a) == i[a]
I'm a bit confused about pointer arrays and I just wanna make sure I'm right.
When I write int *arrit is just a pointer to an int variable, not an array yet. It is only that I initialize it (say with malloc) that it becomes an array. Am I right so far?
Also I have another question: were given (in school) a little function that is supposed to return an array of grades, with the first cell being the average. The function was deliberately wrong: what they did was to set
int *grades = getAllGrades();
And than they have decreased the pointer by one for the average 'cell'
*(grades - 1) = getAverage();
return *(grades - 1)
I know this is wrong because the returned value is not an array, I just don't know how to explain it. When I set a pointer, how does the machine/compiler know if I want just a pointer or an array?
(If I'm not clear its because I'm trying to ask about something that is still vague for me, my apologizes)
how does the machine/compiler know if I want just a pointer or an
array?
It doesn't, and it never will. Suppose you
int *a = malloc(3 * sizeof(int));
You just allsocated 12 bytes (assuming int is 4). But malloc only sees 12. Is that 1 big object or lots of little ones? It doesn't know. The only one who actually knows is you ;)
Now about your particular example,
int *grades = getAllGrades();
At this point, as you said, there's nothing to say whether grades points to an array. But you know it points to an array, and that's what's important. Or, maybe you know it doesn't point to an array. The key is you have to know what getAllGrades does, to know if it's returning an array or a pointer to 1 thing.
*(grades - 1) = getAverage();
return *(grades - 1)
This is not necessarily wrong, but it does look kind of sketch. If it is an array, you would expect grades[0] == *(grade + 0) to be the first element, so grades[-1] == *(grades - 1) looks like it would be before the first element. Again, it's not necessarily wrong; maybe in getAllGrades they did:
int* getAllGrades() {
int *grades = malloc(sizeof(int) * 10);
return grades + 1;
}
ie they scooched the start up by 1. It's been known to happen (look in Numerical Recipes in C) but it's kind of odd.
Arrays are not pointers. Pointers are not arrays.
Perhaps it would be clearer to say that array objects are not pointer objects, and vice versa.
When you declare int *arr, arr is a pointer object. That's all it is; it cannot be, and never will be, an array.
When you execute arr = malloc(10 * sizeof *arr);, (if malloc() doesn't fail, which you should always check), arr now points to an int object. That object happens to be the first element of a 10-element array of int (the one created by the malloc call). Note that there is such a thing as a pointer to an array, but this isn't it.
Arrays, in a very real sense, are not first-class types in C. You can create and manipulate array objects as you can with any other type of objects, but you'll rarely deal with array values directly. Instead, you'll deal with the elements of an array object indirectly, via pointers to those elements. And in the case of the arr declaration above, you can perform arithmetic on the pointer to the first element to obtain pointers to the other elements (and you have to have some other mechanism to remember how many elements there are).
Any expression of array type, in most contexts, is implicitly converted to a pointer to the array's first element (the exceptions are: the operand of a unary & operator, the operand of the sizeof operator, and a string literal in an initializer used to initialize an array (sub)object). That's the rule that makes it seem as if arrays and pointers are interchangeable.
The array indexing operator [] is actually defined to work on pointers, not arrays. a[b] is simply another way of writing *((a)+(b)). If a happens to be the name of an array object, it's first converted to a pointer, as I describe above.
I highly recommend reading section 6 of the comp.lang.c FAQ. (The link is to the front page, not directly to section 6, because I like to encourage people to browse the whole thing.)
I mentioned that there are array pointers. Given int foo[10];, &foo[0] is a pointer to an int, but &foo is a pointer to the entire array. Both point to the same location in memory, but they're of different types, and they behave quite differently under pointer arithmetic.
When I write int *arr it is just a pointer to an int variable, not
an array yet. It is only that I initialize it (say with malloc) that
it becomes an array. Am I right so far?
Well, yes and no :). arr is a pointer to (or the address of) some block of memory. Until arr is initialized it probably points to an invalid, or non-sense memory address. So it may be confusing to think of arr as a pointer to an int variable. For example, before the malloc, you can't store an integer in the location that it is pointing to.
Also, it may be easier to understand if you say that after the malloc, arr points to an array, it does not "become" an array. Before the malloc, arr points to some random non-sense location.
When I set a pointer, how does the machine/compiler know if I want
just a pointer or an array?
If you set a pointer (e.g. arr = <something>) you are just changing where the pointer points. That may be what you want. If don't want to change where arr points but you want to change the values stored in the memory where it is pointing you have to do it one element at a time (e.g. with a for loop that iterates over each element in the array).
You are right, the only difference between arrays and pointers is convention. Here's a picture of what memory must look like when the getAllGrades() function returns:
| secret malloc() stuff |
+-----------------------+
| average value |
+-----------------------+ ----\
grades* points here ---> | grade at index 0 | | by convention
+-----------------------+ | this stuff is
| grade at index 1 | | called grades[]
+-----------------------+ |
| grade at index 2 | |
+-----------------------+ .
| ... | .
Now, there is no difference between an array and a pointer. So, when the compiler sees *(grades - 1) it first subtracts 1 from the grades pointer. This is special pointer arithmetic so it knows to go one whole int block upwards, and points at the average value. Then it can operate on this value, for example to set the average with *(grades - 1) = getAverage().
An aside on array indexing: Array indexing gets compiled exactly like pointer arithmetic. For example, grades[2] gets compiled down to *(grades + 2) which does pointer arithmetic to move down 2 blocks to the memory address marked "grade at index 2" in my picture. This means you could change *(grades - 1) = getAverage() to grades[-1] = getAverage() and it would work exactly the same.
If you wanted to experiment you could do (-1)[grades] which compiles down to *(-1 + grades) and works as well, but that's stupid so don't do that :)