14

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

user221458
  • 716
  • 2
  • 7
  • 17
  • [This](http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c) explains all about arrays. If you really want to understand about arrays, help yourself by reading it fully. – legends2k Oct 02 '13 at 05:14
  • 4
    Did you not believe the error message you got when you compiled that code, or did you not bother compiling it before posting here? – Keith Thompson Oct 02 '13 at 06:19
  • @KeithThompson I compiled it before piosting. Wanted to know the reason for error. – user221458 Oct 02 '13 at 07:23
  • @user221458 Question strongly suggests that I have not compiled it before posting but it is not the case. I doubted the behavior of my compiler. – user221458 Oct 02 '13 at 12:31
  • 1
    @user221458 I understand that but the question did not reflect that and how you ask a question on SO is important. – Shafik Yaghmour Oct 02 '13 at 12:35
  • Ok, I will keep that in mind. I don't care about points anyway. I care about knowledge. – user221458 Oct 02 '13 at 13:00
  • 1
    @ShafikYaghmour Thanks for the information. Fortunately none of the two questions I asked till now are poorly rated or closed. I will take care while asking questions in future. – user221458 Oct 02 '13 at 13:15
  • 2
    Next time, please include the exact (copy-and-pasted) error message in your question. In fact, it would be a good idea to update your question to do that now. – Keith Thompson Oct 02 '13 at 14:44
  • I understand that the array name is considered not an l-value and so you can't modified its state. However, why is it that you can use the increment and the decrement operators on the array argv? – karl Dec 08 '16 at 20:31
  • Actually, it just occurred to me that the compiler is passing the argv array as a pointer and so it would be equivalent to char * (*argv)[]. – karl Dec 08 '16 at 20:36

7 Answers7

19

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.

Community
  • 1
  • 1
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • Ok. So a++ will change the initial memory address where a is stored and thus it is not allowed. Right? – user221458 Oct 02 '13 at 05:03
  • @user221458 `a++` try to change but this is compilation time error as I said will be detected in semantic phase. – Grijesh Chauhan Oct 02 '13 at 05:04
  • @user221458 If you know compiler (or computer science) student then you should know that incorrect operand is semantic error. – Grijesh Chauhan Oct 02 '13 at 05:06
  • I know that. It produces error. But is the meaning of a++ what I said? and what will be the output of first printf if second printf is not considered? Will it be 2012? – user221458 Oct 02 '13 at 05:07
  • @user221458 No let me add in my answer. – Grijesh Chauhan Oct 02 '13 at 05:14
  • I know its not an lvalue. I was asking something different. The question was inclined towards why its not a lvalue. You are absolutely correct though. Manoj Kumar has answered my question.. – user221458 Oct 02 '13 at 05:20
  • @user221458 This is what I said and quoted !! – Grijesh Chauhan Oct 02 '13 at 05:21
  • @user221458 See understand as I written in printf expression array names use to access array elements by indexing if you last array address then you will lost complete array so the constraint imposed by compiler (language standard) that array names are unmodified-lvalue. – Grijesh Chauhan Oct 02 '13 at 05:26
  • @user221458 depends on the sizeof int in your system, Suppose it is 4 bytes then `a + 2` gives `2018` if `a` is 2010. – Grijesh Chauhan Oct 02 '13 at 05:43
  • @user221458 Read [10.2 Pointers and Arrays; Pointer Arithmetic](http://www.eskimo.com/~scs/cclass/notes/sx10b.html) and [Pointer Arithmetic](http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html). – Grijesh Chauhan Oct 02 '13 at 05:44
  • 2
    Given that `a` is the name of an array object, `a++` *has no meaning*. – Keith Thompson Oct 02 '13 at 06:20
  • @KeithThompson What I mean to say that `a++` is different then `a + 1` `++` instruction try to modify `a` that causes lvalue error in the phase of semantic analysis (but its syntactically correct) but of-courser it is a compilation time error. – Grijesh Chauhan Oct 02 '13 at 18:00
  • @GrijeshChauhan: If `a` were a scalar (numeric or pointer) object, then both `a + 1` and `a++` would be valid, with different meanings. But if `a` is an array name, then `a + 1` is valid (and equivalent to `&a[1]`), but `a++` has no more meaning than `42++` or the square root of beige. – Keith Thompson Oct 02 '13 at 18:03
  • @KeithThompson That is what exactly I explained. – Grijesh Chauhan Oct 02 '13 at 18:05
4
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.

Gangadhar
  • 10,248
  • 3
  • 31
  • 50
2

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.

userwn
  • 21
  • 1
2

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[...]

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
2

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*/
Outlaw
  • 21
  • 1
1

Array memory addresses remain constant, so you cannot change it. That's what you are doing in a++ statement. So compiler will throw error.

Manoj Kumar
  • 61
  • 3
  • 5
0

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));