I know that the unary operator ++ adds one to a number. However, I find that if I do it on an int pointer, it increments by 4 (the sizeof an int on my system). Why does it do this? For example, the following code:
int main(void)
{
int *a = malloc(5 * sizeof(int));
a[0] = 42;
a[1] = 42;
a[2] = 42;
a[3] = 42;
a[4] = 42;
printf("%p\n", a);
printf("%p\n", ++a);
printf("%p\n", ++a);
return 0;
}
will return three numbers with a difference of 4 between each.
It's just the way C is - the full explanation is in the spec, Section 6.5.6 Additive operators, paragraph 8:
When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
To relate that to your use of the prefix ++ operator, you need to also read Section 6.5.3.1 Prefix increment and decrement operators, paragraph 2:
The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++E is equivalent to (E+=1).
And also Section 6.5.16.2 Compound assignment, paragraph 3:
A compound assignment of the form E1 op= E2 differs from the simple assignment expression E1 = E1 op (E2) only in that the lvalue E1 is evaluated only once.
It's incrementing the pointer location by the size of int, the declared type of the pointer.
Remember, an int * is just a pointer to a location in memory, where you are saying an "int" is stored. When you ++ to the pointer, it shifts it one location (by the size of the type), in this case, it will make your value "4" higher, since sizeof(int)==4.
The reason for this is to make the following statement true:
*(ptr + n) == ptr[n]
These can be used interchangeably.
In pointer arithmetic, adding one to a pointer will add the sizeof the type which it points to.
so for a given:
TYPE * p;
Adding to p will actually increment by sizeof(TYPE). In this case the size of the int is 4.
See this related question
Because in "C" pointer arithmetic is always scaled by the size of the object being pointed to. If you think about it a bit, it turns out to be "the right thing to do".
It does this so that you don't start accessing an integer in the middle of it.
Because a pointer is not a reference ;). It's not a value, it's just an address in memory. When you check the pointer's value, it will be a number, possibly big, and unrelated to the actual value that's stored at that memory position. Say, printf("%p\n", a); prints "2000000" - this means your pointer points to the 2000000th byte in your machine's memory. It's pretty much unaware of what value it's stored there.
Now, the pointer knows what type it points to. An integer, in your case. Since an integer is 4 bytes long, when you want to jump to the next "cell" the pointer points to, it needs to be 2000004. That's exatly 1 integer farther, so a++ makes perfect sense.
BTW, if you want to get 42 (from your example), print out the value pointed to: printf("%d\n", *a);
I hope this makes sense ;)
Thats simple, cause when it comes down to pointer, in your case an integer pointer, a unary increment means INCREMENT THE MEMORY LOCATION BY ONE UNIT, where ONE UNIT = SIZE OF INTEGER .
This size of integer depends from compile to compiler, for a 32-bit and 16-bit it is 4bytes, while for a 64-bit compiler it is 8bytes.
Try doing the same program with character datatype, it will give difference of 1 byte as character takes 1 byte.
In Short, the difference of 4's that
you've come across is the difference
of SIZE OF ONE INTEGER in memory.
Hope this helped, if it didn't i'll be glad to help just let me know.
"Why does it do this?" Why would you expect it to do anything else? Incrementing a point makes it point to the next item of the type that it's a pointer to.
Related
If I incrementing NULL pointer in C, then What happens?
#include <stdio.h>
typedef struct
{
int x;
int y;
int z;
}st;
int main(void)
{
st *ptr = NULL;
ptr++; //Incrementing null pointer
printf("%d\n", (int)ptr);
return 0;
}
Output:
12
Is it undefined behavior? If No, then Why?
The behaviour is always undefined. You can never own the memory at NULL.
Pointer arithmetic is only valid within arrays, and you can set a pointer to an index of the array or one location beyond the final element. Note I'm talking about setting a pointer here, not dereferencing it.
You can also set a pointer to a scalar and one past that scalar.
You can't use pointer arithmetic to traverse other memory that you own.
Yes, it causes undefined behavior.
Any operator needs a "valid" operand, a NULL is not one for the post increment operator.
Quoting C11, chapter §6.5.2.4
The result of the postfix ++ operator is the value of the operand. As a side effect, the
value of the operand object is incremented (that is, the value 1 of the appropriate type is
added to it). [....]
and related to additive operators, §6.5.6
For addition, either both operands shall have arithmetic type, or one operand shall be a
pointer to a complete object type and the other shall have integer type. (Incrementing is
equivalent to adding 1.)
then, P7,
[...] a pointer to an object that is not an element of an
array behaves the same as a pointer to the first element of an array of length one with the
type of the object as its element type.
and, P8,
If the pointer operand points to an element of
an array object, and the array is large enough, the result points to an element offset from
the original element such that the difference of the subscripts of the resulting and original
array elements equals the integer expression. In other words, if the expression P points to
the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
(P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of
the array object, provided they exist. [....] If both the pointer
operand and the result point to elements of the same array object, or one past the last
element of the array object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined.
I think ptr will point to the second array member (as if there were) of struct st. Thats what ptr++ does. Initially pointer was at 0 or NULL. Now it is at 12 (3 * sizeof(int) = 3*4 = 12).
In your example you didn't dereferenced the pointer just printed out the address it points to. When you step a pointer, it will be incremented whith the size of it's reference type. Just try:
printf("Test: %lu", sizeof(st));
And you will get Test: 12 as output. If you would dereference it, like *ptr, it will cause an undefined behavior.
#include <stdio.h>
#include <cs50.h>
int main (void)
{
int *x;
x = malloc(sizeof(long long)*3);
scanf("%i %i %i",x, (x+1), (x+2));
printf("%i\t %i\t %i\n",(int)x, (int)(x+1), (int)(x+2));
printf("%i\t %i\t %i\n",*x, *(x+1), *(x+2));
free(x);
}
The output of this program for input 12,2,3 is :
43171856 43171860 43171864
12 2 3
so, my question is why difference between address is 4 in each case ,
and if *x points to 43171856 then *(x+1) should point to 4317185 not 43171860? sizeof(long long) is also 8 bytes , so how allocated memory allocates 8 bytes between those 4 bytes between 43171856 and 43171860.
First of all, in your code
printf("%i\t %i\t %i\n",(int)x, (int)(x+1), (int)(x+2));
invokes implementation defined behaviour, as you're trying to cast a pointer to integer.
If you want to print pointers
use %p format specifier
cast the argument to void *.
That said, pointer arithmetic honors the data type. You had declared x to be a pointer to int, so any pointer arithmetic will be based on sizeof(int), whatever that evaluates to in your platform.
Quoting C11, chapter §6.5.6/P8, (emphasis mine)
When an expression that has integer type is added to or subtracted from a pointer, the
result has the type of the pointer operand. If the pointer operand points to an element of
an array object, and the array is large enough, the result points to an element offset from
the original element such that the difference of the subscripts of the resulting and original
array elements equals the integer expression. In other words, if the expression P points to
the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
(P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of
the array object, provided they exist. [....]
In your code, you wrote
x = malloc(sizeof(long long)*3);
which is erroneous. In this case, you may be on the safer side, as sizeof(long long) is >= sizeof(int), but that is not true for any arbitary type.
Best case: You'll end up wasting memory.
Worst case: You'll end up accessing out of bound (invalid) memory.
A better and preferred way to write this would be
x = malloc(sizeof*x * 3); //sizeof is not a function :)
and then, check for malloc() success. This allocates the exact amount of memory required, no more, no less.
This is one of the really confusing bits of C: x+1, when x has a pointer type, increments the numeric value of x by sizeof(*x), not by 1.
It has to be that way, because, for any pointer type T *x, x+1 is the same as &x[1]. &x[1] is the address of the second T in the pseudo-array pointed to by x. Therefore the numeric value of x+1 must be equal to the numeric value of x plus sizeof(T), which in your case is 4.
malloc, meanwhile, doesn't know that you passed it 3*sizeof(long long). It sees malloc(24) and it gives you 24 bytes, which (on your platform) is six ints. You are using only the first three, which is fine, it just wastes a little memory. You probably meant to write 3*sizeof(int).
You are using an int* which usually is 32 bits and thus 4 bytes.
Try using a long long *x instead?
You have as you stated allocated 8*3 bytes byt are only using 4*3 bytes of them..
Each offeset i.e (x+1) is only offseted the size of an int.
C 2011 Online Draft
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. If the array object has
register storage class, the behavior is undefined.
Under most circumstances, an expression of type "array of T" will be converted ("decay") to an expression of "pointer to T", and the value of the expression will be the address of the first element of the array.
AFAIK, the _Alignof operator clause is a mistake in the online draft that was corrected in the official™, not freely-available standard, which is why it's struck out in the quote above.
6.5.2 Array subscripting
...
2 A postfix expression followed by an expression in square brackets [] is a subscripted
designation of an element of an array object. The definition of the subscript operator []
is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that
apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the
initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th
element of E1 (counting from zero).
Given an array a of type T and an integer i, the expression a[i] is equivalent to (defined as) *(a + i) - given an address a, offset i elements of type T (not bytes) from that address and dereference the result.
If a is an array or pointer expression and i is an integral expression, then a[i] and i[a] will yield the same result.
6.5.6 Additive Operators
...
8 When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to
the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
(P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last
element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
If p is a pointer to an object of type T, then the expression p + 1 yields the address of the next object of that type. If sizeof (T) is 1, then p + 1 adds 1 to the address. If sizeof (T) is 4, then p + 1 adds 4 to the address.
Similarly, the expression ++p and p++ advance p to point to the next object of type T.
Last line yields "invalid operands to binary expression". Trying to understand why. Does it mean that "p2-p1" is an invalid operand to the binary expression "-" that lies to the right of p3? Any rule I can follow here? Confusing to me because "3-2-1" integers are valid.
int array[3] = {1,2,3};
int* p1 = &array[0];
int* p2 = &array[1];
int* p3 = &array[2];
p3-p2-p1;
You are doing address arithmetic. Given operator precedence, it is evaluating p1-p2-p3 as (p1-p2)-p3. p1-p2 yields not an address but an integer. Then you are attempting to subtract an address from an integer, which isn't valid. You could do p1-(p2-p3), then it's taking p2-p3, yielding an integer, and subtracting that as an integer offset from an address (p1), which will compile. However, [Thanks to #EOF for this reference in his comment] such subtraction (of integer from a pointer) would only be valid if it points somewhere within the allocation for p1. It's subject to the C11 standard described specifically in section 6.5.6, excerpted below:
When an expression that has integer type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
pointer operand points to an element of an array object, and the array
is large enough, the result points to an element offset from the
original element such that the difference of the subscripts of the
resulting and original array elements equals the integer expression.
In other words, if the expression P points to the i-th element of an
array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N
(where N has the value n) point to, respectively, the i+n-th and
i−n-th elements of the array object, provided they exist. Moreover, if
the expression P points to the last element of an array object, the
expression (P)+1 points one past the last element of the array object,
and if the expression Q points one past the last element of an array
object, the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to elements
of the same array object, or one past the last element of the array
object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined. If the result points one past the last element
of the array object, it shall not be used as the operand of a unary *
operator that is evaluated.
In your code, p1, p2 and p3 are all pointers to integers, not integers.
To get what you want, you probably want:
*p3 - *p2 - *p1;
where the * operator is the dereference operator. It dereferences pointers, so in this case *p3 etc are of type int. You can think of it as the inverse of the & address-of operator.
There are tons of code like this one:
#include <stdio.h>
int main(void)
{
int a[2][2] = {{0, 1}, {2, -1}};
int *p = &a[0][0];
while (*p != -1) {
printf("%d\n", *p);
p++;
}
return 0;
}
But based on this answer, the behavior is undefined.
N1570. 6.5.6 p8:
When an expression that has integer type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
pointer operand points to an element of an array object, and the array
is large enough, the result points to an element offset from the
original element such that the difference of the subscripts of the
resulting and original array elements equals the integer expression.
In other words, if the expression P points to the i-th element of an
array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N
(where N has the value n) point to, respectively, the i+n-th and
i−n-th elements of the array object, provided they exist. Moreover,
if the expression P points to the last element of an array object, the
expression (P)+1 points one past the last element of the array object,
and if the expression Q points one past the last element of an array
object, the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to elements
of the same array object, or one past the last element of the array
object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined. If the result points one past the last element
of the array object, it shall not be used as the operand of a unary
* operator that is evaluated.
Can someone explain this in detail?
The array who's base address (pointer to first element) p is assigned is of type int[2]. This means the address in p can legally be dereferenced only at locations *p and *(p+1), or if you prefer subscript notation, p[0] and p[1]. Furthermore, p+2 is guaranteed to be a legally evaluated as an address, and comparable to other addresses in that sequence, but can not be dereferenced. This is the one-past address.
The code you posted violates the one-past rule by dereferencing p once it passes the last element in the array in which it is homed. That the array in which it is homed is buttressed up against another array of similar dimension is not relevant to the formal definition cited.
That said, in practice it works, but as is often said. observed behavior is not, and should never be considered, defined behavior. Just because it works doesn't make it right.
The object representation of pointers is opaque, in C. There is no prohibition against pointers having bounds information encoded. That's one possibility to keep in mind.
More practically, implementations are also able to achieve certain optimizations based on assumptions which are asserted by rules like these: Aliasing.
Then there's the protection of programmers from accidents.
Consider the following code, inside a function body:
struct {
char c;
int i;
} foo;
char * cp1 = (char *) &foo;
char * cp2 = &foo.c;
Given this, cp1 and cp2 will compare as equal, but their bounds are nonetheless different. cp1 can point to any byte of foo and even to "one past" foo, but cp2 can only point to "one past" foo.c, at most, if we wish to maintain defined behaviour.
In this example, there might be padding between the foo.c and foo.i members. While the first byte of that padding co-incides with "one past" the foo.c member, cp2 + 2 might point into the other padding. The implementation can notice this during translation and instead of producing a program, it can advise you that you might be doing something you didn't think you were doing.
By contrast, if you read the initializer for the cp1 pointer, it intuitively suggests that it can access any byte of the foo structure, including padding.
In summary, this can produce undefined behaviour during translation (a warning or error) or during program execution (by encoding bounds information); there's no difference, standard-wise: The behaviour is undefined.
You can cast your pointer into a pointer to a pointer to array to ensure the correct array semantics.
This code is indeed not defined but provided as a C extension in every compiler in common usage today.
However the correct way of doing it would be to cast the pointer into a pointer to array as so:
((int (*)[2])p)[0][0]
to get the zeroth element or say:
((int (*)[2])p)[1][1]
to get the last.
To be strict, he reason I think this is illegal is that you are breaking strict aliasing, pointers to different types may not point to the same address (variable).
In this case you are creating a pointer to an array of ints and a pointer to an int and pointing them to the same value, this is not allowed by the standard as the only type that may alias another pointer is a char * and even this is rarely used properly.
Lets say I want to allocate memory for 3 integers:
int *pn = malloc(3 * sizeof(*pn));
Now to assign to them values I do:
pn[0] = 5550;
pn[1] = 11;
pn[2] = 70000;
To access 2nd value I do:
pn[1]
But the [n] operator is just a shortcut for *(a+n). Then it would mean that i access first byte after a index. But int is 4 bytes long so shoudn't i do
*(a+sizeof(*a)*n)
instead? How does it work?
No, the compiler takes care of that. There are special rules in pointer arithmetic, and that is one of them.
If you really only want to increment it by one byte, you have to cast the pointer to a pointer to a type which is one byte long (for example char).
Good question, but C will automatically multiply the offset by the size of the pointed-to type. In other words, when you access
p[n]
for a pointer declared as
T *p;
you will access the address p + (sizeof(T) * n) implicitly.
For instance, we can use C99 standard to find out what is going on. According to C99 standard:
6.5.2.1 Array subscripting
Constraints
- 1
One of the expressions shall have type ‘‘pointer to object type’’, the other expression shall
have integer type, and the result has type ‘‘type’’.
Semantics
- 2 A postfix expression followed by an expression in square brackets [] is a subscripted
designation of an element of an array object. The definition of the subscript operator []
is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that
apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the
initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th
element of E1 (counting from zero).
And from 6.5.5.8 about conversion rules for + operator:
When an expression that has integer type is added to or subtracted from a pointer, the
result has the type of the pointer operand. If the pointer operand points to an element of
an array object, and the array is large enough, the result points to an element offset from
the original element such that the difference of the subscripts of the resulting and original
array elements equals the integer expression. In other words, if the expression P points to
the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
(P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of
the array object, provided they exist. Moreover, if the expression P points to the last
element of an array object, the expression (P)+1 points one past the last element of the
array object, and if the expression Q points one past the last element of an array object,
the expression (Q)-1 points to the last element of the array object. If both the pointer
operand and the result point to elements of the same array object, or one past the last
element of the array object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined. If the result points one past the last element of the array object, it
shall not be used as the operand of a unary * operator that is evaluated.
Thus, all these notes are about your case and it works exactly as you wrote and you don't need special constructions, dereferencing or anything else (pointers arithmetic do that for you):
pn[1] => *((pn)+(1))
Or, in terms of byte pointers (to simplify description what is going on) this operation is similar to :
pn[1] => *(((char*)pn) + (1*sizeof(*pn)))
Moreover you can access this element with 1[pn] and result will be the same.
You should not. The rules what is happening when you add a int to a pointer are not obvious. So better not use your intuition, but read language standards about what is happens in such a cases. For example read more about pointer arithmetics here (C) or here (C++).
Shortly - a non-void pointer are "measured" in units of the type lengths.