While reading about pointers I found a pointer variable is used to indicate an array like this:
char* chrArray;
int* intArray;
After that I found charArray++ and intArray++ used in code to indicate the next element of charArray and intArray. But so far I know char in C is 1 byte and int in array is 4 byte. So I can not understand how the increment operator behave here. Can anyone please explain it.
This is handled by the compiler that knows the type of the pointer, thus can increment the address it stores by the relevant size, whether it is a char, an int or any other type.
As per the C11 standard document, chapter 6.5.2.5, Postfix increment and decrement operators
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).
So, whenever you're using a postfix increment operator, you're not adding any specific value, rather, you're addding value 1 of the type of the operand on which the operator is used.
Now for your example,
chrArray is of type char *. So, if we do chrArray++, a value of the type char [sizeof(char), which is 1] will be added to chrArray as the result.
OTOH, intArray is of type int *. So, if we do intArray++, a value of the type int [sizeof(int), which is 4 on 32 bit platform, may vary] will be added to intArray as the result.
Basically, a Postfix increment operator on a pointer variable of any type points to the next element (provided, valid access) of that type.
Related
I was recently reading through some source code and read the following at the beginning of a function:
char buffer[ 1000 ];
char *pointer;
pointer = &buffer[0];
I guess I don't understand this. Why not just write:
pointer = buffer;
Is there some secret meaning I am missing here?
Some people may find it easier to understand depending on the occasion.
Someone might say that when you use pointer = buffer; you intend to use the pointer as the buffer,
while if you use pointer = &buffer[0]; you intend to use the pointer as a pointer or an item of the buffer.
It just happens that those 2 cases point to the same address.
Both expressions give the same result value. So in your given case it is mainly a question of preferred style.
But there is a difference if you use the expresions for example in a function call. A static code analysis tool should complain about
memcpy(&buffer[0], src, 2 * sizeof(buffer[0]));
because you state that you are writing two elements into one array element. But the tool should not complain about
memcpy(&buffer, src, 2 * sizeof(buffer[0]));
or
memcpy(buffer, src, 2 * sizeof(buffer[0]));
because you now say that you want to write into the complete array.
Relevant parts in the standard:
6.3.2.1 Lvalues, arrays, and function designators
3 Except when it is the operand of the sizeof 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. [...]
6.5.3.2 Address and indirection operators
Semantics 3 The unary & operator yields the address of its operand. If the operand has type “type”, the result has type “pointer to type”. [...] Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary* that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a+ operator. Otherwise, the result is a pointer to the object or function designated by its operand.
They're absolutely the same. I also prefer the simpler version
pointer = array; // implicit conversion from array to address of its 1st element
pointer = &array[0]; // explicitly set pointer to the address of array's 1st element
In some cases, depending on how you're going to use the pointer, the explicit version may be more self-documented.
From C Standards#6.5.2.1
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))..
So,
&buffer[0]
can be written as
&(*(buffer + 0))
Note that the operator & is used to get the address and the operator * is used for dereferencing. These operators cancel the effect of each other when used one after another. So, it is equivalent to
(buffer + 0)
which is nothing but
buffer
So, &buffer[0] is equivalent to buffer.
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.
To my function i get a void pointer, I would like to point to the next location considering the incoming pointer is of char type.
int doSomething( void * somePtr )
{
((char*)somePtr)++; // Gives Compilation error
}
I get the following compilation error:
Error[Pe137]: expression must be a modifiable lvalue
Is this an issue with the priority of operators?
A cast does not yield an lvalue (see section 6.5.4 footnote 104 of C11 standard), therefore you can't apply post increment ++ operator to its result.
c-faq: 4.5:
In C, a cast operator does not mean "pretend these bits have a different type, and treat them accordingly"; it is a conversion operator, and by definition it yields an rvalue, which cannot be assigned to, or incremented with ++. (It is either an accident or a deliberate but nonstandard extension if a particular compiler accepts expressions such as the above.)
Try this instead
char *charPtr = ((char*)somePtr);
charPtr++;
If you want to move the pointer to next then you can use:
*ptr++;
If you want to Change copy the pointer position to another variable then:
char *abc = (char*)(def + 1);
It really depends on your motive to do things
I thought when you try to get the address of an array, it returns the address of the first element it holds.
int *j;
int a[5]={1,5,4,7,8};
Now j=&a[0]; works perfectly fine.
Even j=a also does the same function.
But when I do j=&a it throws an error saying cannot convertint (*)[5]' to int*' in assignment
Why does it happen? &a should be the first element of the array a, so it should give &a[0].
But instead it throws an error. Can somebody explain why?
The C standard says the following regarding how arrays are used in expressions (taken from C99 6.3.2.1/3 "Lvalues, array, and function designators):
Except when it is the operand of the sizeof 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
This is commonly known as "arrays decay to pointers".
So the sub-expression a in the following larger expressions evaluates to a pointer to int:
j=&a[0]
j=a
In the simpler expression, j=a, that pointer is simply assigned to j.
In the more complex expression, j=&a[0], the 'index' operator [] is applied to the pointer (which is an operation equivalent to *(a + 0)) and the 'address-of' operator is applied to that, resulting in another pointer to int that gets assigned to j.
In the expression j=&a, the address-of operator is applied directly to the array name, and we hit one of the exceptions in the above quoted clause: "Except when it is the operand of ... the unary & operator".
Now when we look at what the standard says about the unary & (address-of) operator (C99 6.5.3.2/3 "Address and indirection operators"):
The unary & operator returns the address of its operand. If the
operand has type "type", the result has type "pointer to type".
Since a has type "array of 5 int" (int [5]), the result of applying & to it directly has type "pointer to array of 5 int" (int (*)[5]), which is not assignable to int*.
The type of a and &a is not the same even though they contain the same value, i.e., base address of the array a.
j = a;
The array name a here gets converted to a pointer to its first element.
Try to see what values you get via these statements to understand where the difference lies:
printf("%p", a+1);
printf("%p", &a+1);
c is a strongly typed language. Assignment such as j=a; is allowed only if j and a are of the same type or the compiler can safely convert a to j. In your case, type of j is int * while the type of &a is int (*)[5]. The compiler does not know how to automatically convert an object of type int (*)[5] to an object of type int *. The compiler is telling you exactly that.
a is an array of 5 ints. The pointer to a is a pointer to an array of five integers, or int (*)[5]. This is not compatible with an int * because of pointer arithmetic: If you increment a variable of type int *, the address in the variable increases by 4 (assuming 4 byte integers), so that it points to the next integer. If you increment a variable that points to an array of 5 integers, the address in the variable increases by 20 (again assuming 4 byte integers), so that it points to the next array of five integers.
Perhaps what's confusing is that the value give by a and &a is the same, as you said. The value is the same but the type is different, and the difference is most obvious when you do arithmetic on the pointers.
I hope that helps.
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.