Increment a vector adress and assign it to a pointer - c

Why can't I do p=numbers++ or p=++numbers? The compiler shows the message: "lvalue required as increment operand" but isn't the pointer p a left value?
int main(int argc, char *argv[]){
int numbers[] = {1,2,3,4,5,6}, *p;
p=numbers++;
printf("%d ",*p);
return 0;
}

When you declare and define an array, the name of the array is an expression that evaluates to the address of the first element of the array. Think of the name as a constant that holds the address of the first element.
Once memory has been allocated for the array, the address of the array cannot be changed. Consequently, the value of the array identifier (name) cannot be changed either.
In your code, when you have
p = numbers++;
you are asking that numbers, which has the constant value of the address of the first element of the array, be incremented and point to the second element instead. This is not a legal operation. The increment operand requires a modifiable lvalue, and the name of the array is not a modifiable lvalue.
What is an lvalue? It is a locator value: something that identifies an area of memory that can hold another value. So when you declare:
int a = 5;
a signifies an area of memory large enough to hold an int, and the int held in that area of memory is 5. You can change that int by assignment:
a = 7;
but the identifier a still signifies the same area of memory. This means a is a modifiable lvalue.
When you declare and define your array:
int numbers[] = { 1, 2, 3, 4, 5, 6 };
numbers is an lvalue, in that it specifies an area of memory that holds the array of specified integers, but it is not modifiable. You can change the value of the elements in numbers, but you cannot change the value of numbers itself. numbers always evaluates to &numbers[0].
If you want to change where p points so that it points to the second element instead of the first, use:
p = numbers + 1;
This does not change the value of numbers itself, only that of p. numbers is still &numbers[0] and p will be &numbers[1].
Hope this is clear!

numbers++ is the equivalent of numbers = numbers + 1
However, numbers here is an array and you cannot modify the address of an array.
lvalue doesn't mean a "left value"

First I recommend that you read the C FAQ's section on Arrays and Pointers it is one of the better general references.
To directly address your error, if we look at the draft C99 standard we see that in sections 6.5.2.4 Postfix increment and decrement operators and
6.5.3.1 Prefix increment and decrement operators say in paragraph 1:
The operand of the prefix increment or decrement operator shall have qualified or
unqualified real or pointer type and shall be a modifiable lvalue.
section 6.3.2.1 Lvalues, arrays, and function designators paragraph 3 says:
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. [...]
and paragraph 1 says:
[...] A modifiable lvalue is an lvalue that does not have array type, [...]
so even though an array will decay to a pointer to the first element in many circumstances it is not a lvalue.

numbers is NOT a pointer. It is an array with this definition int numbers[] = {1,2,3,4,5,6}, and a rvalue. So the compiler shows the message: "lvalue required as increment operand".
Difference between array and pointer. Pointers - Difference between Array and Pointer

Related

if int A[5] is declared then only A is pointer to the A[0].which means A is just a pointer . then how come sizeof(A) gives answer as 20

Suppose if int A[5] is declared then variable A will be pointer to the A[0]. Which means A is just a pointer and A stores the base address of array A[5] . Then how come sizeof(A) gives answer as 20
A isn't a pointer to the first element. It is an int[5], or a five element array of ints (the size is part of the type). It can decay into a pointer to the first element when you do stuff like pass it to a function taking a pointer.
Contrary to what you might have heard, arrays are not the same as pointers.
In most contexts, the name of an array will decay into a pointer to the first element, such as being passed to a function or as the subject of pointer arithmetic.
One of the cases where this decay does not happen is when the array is the subject of the sizeof operator. In that case the operator returns the full size of the array in bytes.
This is detailed in section 6.3.2.1p3 of the C standard:
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.
Section 6.5.3.4p4, which details the sizeof operator, additionally states:
When sizeof is applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is
1. When applied to an operand that has array type, the result is the total number of bytes in the array. When applied to an operand
that has structure or union type, the result is the total number of
bytes in such an object, including internal and trailing padding.
If you had some something like this:
int A[5];
int *B;
B = A;
printf("sizeof(B)=%zu\n", sizeof(B));
You would get the size of an int * on your system, most likely either 4 or 8.

How is memory allocated in c , and why diffrence between two contiguous is always 4?

#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.

Are these pointer lvalues?

According to "C - A Reference Manual", an lvalue is an expression that refers to an object in such a way that the object may be examined or altered.
For example,
int ranks[10];
Then are ranks and ranks+3 lvalues? Since ranks(pointer to first element of array) and ranks+3(pointer to fourth element of array) refer to objects, I guess they are lvalues -- or are they not lvalues?
ranks+3 is not an lvalue for the same reason that 1+3 is not an lvalue; the result is simply a numerical (pointer) value, not a reference to an object.
Put another way, if the result of ranks + 3 is 0xdeadbeef, you cannot write
0xdeadbeef = 10;
for the same reason you cannot write
4 = 10;
However, *(ranks+3) is an lvalue, because you are dereferencing that pointer value; it is the 4th element of the ranks array, and is equivalent to ranks[3].
Similarly, ranks is not an lvalue except in the context of sizeof or the unary & operator. Since array expressions "decay" to pointer expressions in most contexts, you again wind up with the situation of
ranks = 10;
being equivalent to
0xdeadbeef = 10;
Again, you'd have to dereference ranks as either *ranks or ranks[0] for it to be an lvalue.
In this context, the names aren't lvalues, but they can be dereferenced with * to form lvalues. For example:
int ranks[10];
// ranks = 42; <--- doesn't compile! error: assignment to expression with array type
*ranks = 42; // OK: same as ranks[0] = 42
//ranks+3 = 42; <--- error: lvalue required as left operand of assignment
*(ranks+3) = 42; //OK: same as ranks[3] = 42
This answer lists the few cases in C when the name of an array doesn't decay to a pointer to the array's first element. On the left-hand side of an assignment isn't one of those cases. Therefore, in ranks = ..., ranks is (decays to, acts as) a pointer to the first element of the array. You have to dereference that pointer (*ranks) to get one of the array elements as an lvalue.
Just don't ask me what an lvalue is. I know it when I see it. :)
Tested on gcc.

Is there a reason why an array name is not an lvalue?

For example,
int x[10];
int i = 0;
x = &i; //error occurs!
According to C - A Reference Manual, an array name cannot be an lvalue. Thus, x cannot be an lvalue. But, what is the reason the array name cannot be an lvalue? For example, why does an error occur in the third line?
Your reference is incorrect. An array can be an lvalue (but not a modifiable lvalue), and an "array name" (identifier) is always an lvalue.
Take your example:
int x[10];
int i = 0;
x = &i; //error occurs!
Apply C11 6.5.1, paragraph 2:
An identifier is a primary expression, provided it has been declared
as designating an object (in which case it is an lvalue) ...
We see that x is a primary expression and is an lvalue, because it has previously been declared as designating an array object.
However, the C language rules state that an array expression in various contexts, including the left-hand-side of an assignment expression, are converted to a pointer which points at the first element of the array and is not an lvalue, even if the array was. Specifically:
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.
(C11 6.3.2.1 paragraph 3).
The pointer which is the result of the conversion specified above is not an lvalue because an lvalue designates an object, and there is no suitable object holding the pointer value; the array object holds the elements of the array, not a pointer to those elements.
The example you use in your question implies that you understand that an array expression decays (is converted to) a pointer value, but I think you are failing to recognize that after the conversion, the pointer value and the array are two different things. The pointer is not an lvalue; the array might be (and in your example, it is). Whether or not arrays are lvalues in fact has no bearing on your example; it is the pointer value that you are trying to assign to.
If you were to ask instead: Why do arrays decay to pointers when they are on the left-hand-side of an assignment operator? - then I suspect that there is no particularly good answer. C just doesn't allow assignment to arrays, historically.
Array names are non-modifiable lvalues in C.:)
Arrays are named extents of memory where their elements are placed. So you may not substitute one extent of memory for another extent of memory. Each extent of memory initially allocated for an array declaration has its own unique name. Each array name is bounded with its own extent of memory.
An array is an lvalue, however it is a non-modifiable lvalue.
It most likely has to do with compatibility of types. For example, you can do this:
struct ss {
char c[10];
};
...
struct ss s1 = { { "hello" } };
struct ss s2 = s1;
But not this:
char s1[10] = "hello";
char s2[10] = s1;
It's true that array names yield pointer values in many contexts. But so does the & operator, and you don't expect that to be assignable.
int i = 42;
int *j = malloc(sizeof *j);
&i = j; /* obviously wrong */
int a[] = {1,2,3};
&a[0] = j; /* also obviously wrong */
a = j; /* same as the previous line! */
So when learning the relationship between arrays and pointers, remember that a is usually the same as &a[0] and then you won't think lvalue-ness is an exception to the rule - it follows the rule perfectly.

Array increment operator in C

I don't understand the results of following code:
#include <stdio.h>
#include <conio.h>
int main()
{
int a[4]={1, 3, 5, 6};
//suppose a is stored at location 2010
printf("%d\n", a + 2);
printf("%d", a++);
return 0;
}
Why does the second printf function produce following error?
error: lvalue required as increment operand
Part-1:
Array names are constant (not modifiable lvalue), your can add value to array name but can't modify it.
Expression a + 2 doesn't modify a itself but when you do a++ that is equivalent to a = a + 1 try to modify array name --lvalue error. The expression a++ in second printf is wrong - an example of semantic phase error. read following language standards:
6.3.2.1 Lvalues, arrays, and function designators
724 A modifiable lvalue is an lvalue that does not have array type,
does not have an incomplete type, does not have a const-qualified
type, and if it is a structure or union, does not have any member
(including, recursively, any member or element of all contained
aggregates or unions) with a const-qualified type.
729 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.
Part-2:
Note array names in most expressions decays in address of first element (read some exceptions where array name not decaying into a pointer to first element? ably answered by #H2CO3).
When you do a + 2 its result is address of third element (or address of element at index 2) So a + 2 is same as &a[2] It is address not value at index.
To print address use %p instead of %d and typecast address into void* as follows:
printf("address (a + 2) = %p , &a[2] = %p", (void*)(a + 2), (void*)(&a[2]));
To print value you need defence operator * as follows:
printf("address *(a + 2) = %d , a[2] = %d", *(a + 2), a[2]);
Part-3:
suppose a is stored at location 2010, Is the output of first printf function 2012?
No, pointer arithmetic is different then integer arithmetic. As we know array name decays into address of first element's address in most expressions So when you do a + 2 the value is address of third element that is at index 2. So suppose if int size in your system is 4 bytes then a + 2 stat pointing to location 2018 according to your assumption that a address value is 2010.
To understand read 10.2 Pointers and Arrays; Pointer Arithmetic and Pointer Arithmetic.
int a[4]={1,3,5,6};
printf("%d\n",a++); // you should not modify array name
illegal in c
Assume pa is integer pointer
A pointer is a variable, so pa=a and pa++ are legal. But an array name is not a
variable; constructions like a=pa and a++ are illegal.
I think the first output will be depedent on how the integer type is represented in your computer. If a single integer occupies 4-bytes in memory, the output should be 2018, i.e. 2010+2*4. The second printf can cause a compilation error.
First this program invokes undefined behavior and I am little discouraged that with so many answers not one of them mentions this. In both your printf calls your argument is a pointer yet your are specifying the format as %d which expects and int it should be %p. The C99 draft standard in section 7.19.6.1 The fprintf function which printf's section refers back to for the format string paragraph 9 says:
If a conversion specification is invalid, the behavior is undefined.[...]
Back to your question, the a++ expression produces an error because postfix increment requires that it's operand is a modifiable lvalue, the draft standard in section 6.5.2.4 Postfix increment and decrement operators paragraph 1 says(emphasis mine):
The operand of the postfix increment or decrement operator shall have qualified or
unqualified real or pointer type and shall be a modifiable lvalue.
we can see from setion 6.3.2.1 values, arrays, and function designators paragraph 1 says:
[...]A modifiable lvalue is an lvalue that does not have array type[...]
The name of array is a constant pointer and so it will always point to the 0th element of that array. It is not a variable so nor can we assign some other address to it neither can we move it by incrementing or decrementing.
Hence
a = &var; /*Illegal*/
a++; /*Illegal*/
a = a-1; /*Illegal*/
Array memory addresses remain constant, so you cannot change it. That's what you are doing in a++ statement. So compiler will throw error.
a is not a variable of int type, it's a pointer to integer, so to print it you need to dereference it first
printf("%d\n", *(a + 2));

Resources