L Value required as increment operator - C - c

I just got a question from my Friend.
#include<stdio.h>
void fun(int[][3]);
int main(void){
int a[3][3]={1,2,3,4,5,6,7,8,9};
fun(a);
printf("\n%u",a);
a++;//Ques 1
printf("\n%u",a);
printf("%d",a[2][1]-a[1][2]);
return 0;
}
void fun(int a[][3]){
++a;//Ques 2
a[1][1]++;
}
The line Ques 1 will throw an error of L value as 'a' is the name of a two dimensional array. But this is not happening with the case of line Ques 2.
Can any one clear this doubt?

In Ques 1, a is an array and it will be converted to a non-lvalue pointer when used as operand of ++ operator and emit compile error.
In Ques 2, the argument int a[][3] is equivalent to int (*a)[3] and ++a is an increment of pointer variable, which is acceptable.
Quote from N1570 6.7.6.3 Function declarators (including prototypes), pargraph 7:
A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation.

When an array is passed as a function argument, it decays into a pointer to the array's first element.
Quest 1
a is an array, which is a non-modifiable lvalue. So it cannot be incremented.
Quest 2
The argument that is passed int a[][3]. This decays into a pointer to the first element, which is int (*)[3], (and not int *, contrary to common belief). A pointer may be incremented, so this works.
Also, you should be using %p for pointers in printf, and not %u.

Okay, first, "L value" means something you can assign to. a is the name of an array. So what that line is trying to do is the same as if you were doing a = a + 1 on the array itself, which doesn't make sense.
Now, what you are running into here is that C has a somewhat confusing way of treating arrays: they're really just undistinguished chunks of memory, and their name is a limited alias to the address of the beginning of the array. When you pass an array, what C actually passes is the address of the array (or in this case, the address of a particular point in memory inside the array.) So at Ques 2, that's actually a pointer, which is an L value and can be incremented.
This is called "arrays decaying to pointers" (as pointed out in a comment) and yeah, it can be confusing.

Related

How could value of array b[] is filled with another array a[] value from another function?

I found this code in internet.And i am confused from 1 hour.
What i found weird is that array b[] is inside met2() function with local scope. And there is another array a[] which is inside met1() function with it's local scope . But How could value of a[] is transferred to b[] array.
And Most importantly, both function are not returning any values.
This is so confusing. Please Help me out here. I searched online but nobody had asked such questions.
#include <stdio.h>
int main()
{
met2();
return 0;
}
void met1(int a[1])
{
a[0]=199;
}
void met2()
{
int b[1];
met1(b);
printf("%d",b[0]);
}
Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T" and the value of the expression is the address of the first element of the array.
When you call
met1(b);
the expression b is converted from type "1-element array of int" to type “pointer to int", and the value of the expression is the address of b[0].
In the function prototype
void met1(int a[1])
the parameter declaration int a[1] is "adjusted" to int *a - it’s actually being declared as a pointer (which is handy, since that’s what the function actually receives).
So whenmet2 calls met1, it’s passing the address of the first element of b. The [] operator can be used on pointers as well as arrays (it’s actually defined in terms of pointer arithmetic - a[i] is interpreted as *(a + i)).
So writing a[0] = 199; in met1 is equivalent to writing b[0] = 199; in met2.
The key here is to understand that whenever we declare an array as parameter of a function, it gets adjusted to a pointer to its first element. C17 6.7.6.3 emphasis mine:
A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation.
This means that void met1(int a[1]) and void met1(int* a) are 100% equivalent. The former gets silently translated to the latter by the compiler.
This is quite confusing because int a[1] looks like an array declaration and one might easily get idea the idea that the array is passed by value. But passing arrays by value isn't possible in C.
In your case, the local array b gets passed to met1 as a pointer to its first element. With a[0] = ... that pointed-at element is changed.

Head First C: Erratum? Pointer Syntax

I am teaching myself C programming, using "Head First C", published by O'Reilly. (And a couple of other texts, besides.)
I got very hung-up during the book's introduction to pointers, by the example program on p.58. What threw me was a little call-out in the text, pointing to the line:
int *choice = contestants;
The call-out reads:
“choice” is now the address of the “contestants” array.
And, as far as I can tell, that's wrong. That line assigns *choice to the value stored as the contestants array, is that not so?
Disclaimer: I don't have access to the book / chapter right now.
Considering contestants is of array type, quoting C11, chapter §6.3.2.1 (emphasis mine)
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. [...]
In your case, the array variable is used as the RHS of the assignment operator, so in that case contestants is the same as &(contestants[0]).
This is the exact same type of int * which is the same of the variable to be assigned (LHS).
So you have four answers already, but none of them mention the difference between assignment and initialization syntaxes.
int *choice = contestants; // initialization
The above is equivalent to this:
int *choice; // declaration
choice = contestants; // assignment to pointer
but completely different from this (which can't be done in an initialization):
int *choice; // declaration
*choice = contestants; // assignment to target (not valid unless choice is initialized)
The second version is incorrect as written because it tries to store the value of contestants at the address pointed to by choice -- but choice does not contain an address, unless you initialize it. Dereferencing a possibly-uninitialized pointer is always a mistake.
The book is correct. Pointers work differently from variables, and * works differently in different circumstances.
To start, you probably know that a pointer is just a variable containing the address to the location in memory of another item
When we use
int *choice
we create a pointer to an integer, which stores the address of the integer
In this case, I'm assuming contestants is an array. We'll assume it's an array of ints
int contestants[5] = [0,1,2,3,4];
Collections, such as arrays, are always stored as a pointer to the first element. The second element is therefore addressof_first_item + sizeof(element_stored).
Let's assume the address is 0x12345, it's like this int contestants = 0x12345
And now we store that address in choice:
int *choice = contestants
In other words, it's a pointer to an integer, which happens to be the first element in the contestants array.
As a side note, we could also write it as:
int* choice = &contestants[0];
The other use case for the * operator with regards to pointers, is dereferencing. Dereferencing involves getting the value at the address pointed to by a pointer.
int value = *choice;
will give us an integer with a value of 0, because the address stored points to the first element
What you maybe don't know is that the name of an array is a pointer on the first element of this array. example
int contestants[] = {1, 2, 3};
means that &contestants[0] has the same value as contestants
This is explained earlier in the chapter, in the BULLET POINTS list.
An array variable can be used as a pointer.
The array variable points to the first element in the array.
And also further down in the box labeled POINTER DECAY:
Because array variables are slightly different from pointer variables, you need to be careful when you assign arrays to pointers. If you assign an array to a pointer variable, then the pointer variable will only contain the address of the array.
Strictly speaking, the book is not correct, but your reasoning is also incorrect.
Assuming contestants is an array of int, the initialisation
int *choice = contestants;
is equivalent to
int *choice = &contestants[0];
In other words, the value of choice is the address of the first element of contestants. This conversion of contestants (the name of an array) to &contestants[0] (a pointer) commonly known as an "array to pointer" conversion.
However, this differs from the address of the contestants array, since the type is wrong. The address of the contestants array is &contestants, which has type int (*)[4] (i.e. address of an array of four int).
If you try to initialise
int *choice = &contestants;
the result will be a compilation error (since an int(*)[4] cannot be implicitly converted to an int *).
Your reasoning
And, as far as I can tell, that's wrong. That line assigns *choice to the value stored as the contestants array, is that not so?
is flawed, since the contestants does not have a stored value. It is a set of values.
It is true that &contestants[0] and &contestants have the same value, but they also have different type. So a comparison of &contestant[0] == &contestants will not compile. However, if the values are converted to a common type, such as (void *)(&contestants[0]) == (void *)(&contestants), the code will compile, and the converted values will compare equal.

What does address of a, which is an array, returns?

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.

Array name as variable

I'm going through K&R and it says array name is not a variable and it cannot be used in constructions like a=pa or a++.
Isn't s an array name here?
#include<stdio.h>
main(){
printf("%d", strlen("test"));
}
int strlen(char s[])
{
int n;
for (n = 0; *s!= '\0';s++) // why is s++ valid even though it is declared as an array
n++;
return n;
}
No, in this context it's a pointer to a char. Your function declaration is completely equivalent to:
int strlen(char *s)
As you'll see, it's actually impossible to pass an array to a function: a pointer to the first element is what is actually passed.
Thus, since s is actually a pointer and not an array, you're free to modify it as you please.
From the horse's mouth:
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.
The expression "test" is a string literal, which has type "5-element array of char". When you pass "test" as a parameter of strlen, by the rule above, what actually gets passed is a pointer whose value is the address of the first character in "test".
Which brings us to...
6.7.6.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
So in the prototype for strlen, char s[] is equivalent to char *s; s is declared as a pointer to char, not an array of char.
C's treatment of arrays is a bit baroque compared to other languages. That's due in part to the BCPL and B heritage. If you're curious as to why, you can read dmr's The Development of the C Language for some insights.
No, acctually s is a pointer name.
The declaration int strlen(char s[]) is same as int strlen(char *s)
When Char s[]={...} is declared address is attached to s, which never changes (like constant pointer) and anything try to change this property becomes an illegal operation such as s++.
But In function call int strlen(char s[]) , array is passed as pointer.

Pointer Arithmetic with array of char in c

Why if I increment an array string I get an error while if I pass the value to a function I can make it work? A string array object is not already a pointer to the array elements?
e.g.
void foo(char *a){
printf("%c", *a);
a++; // this works
printf("%c", *a);
}
int main(){
char a[] = "ciao";
a++; // I get the error
foo(a);
return 1;
}
thanks!
Because arrays are not pointers. They may decay into pointers under certain circumstances (such as passing to a function, as you can see in your code) but, while they remain an array, you cannot increment them.
What you can do it create a pointer from the array such as by changing:
foo(a);
to:
foo(&(a[1]));
which will pass an explicit pointer to the second character instead of an implicit pointer to the first character that happens with foo(a);.
Section 6.3.2.1 of C99 ("Lvalues, arrays, and function designators"), paragraph 3 has the definitive reason why you can't do what you're trying to do:
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.
It's that "not an lvalue" that's stopping you. You cannot change it if it's not an lvalue (so named because they typically appear on the left of assignment statements).
The reason you can do in your first function is because of section 6.7.5.3 ("Function declarators"), paragraph 7:
A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type"
In other words, the parameter in the function is an lvalue pointer, which can be changed.
The type of your foo's a is a pointer, which you can increment.
The type of your main's a is an array, which you cannot increment.
When you call foo, the address of your array is passed as a new variable of pointer type. You can increment this without the original a being affected.
You can try defining a like this instead:
char* a = "ciao";

Resources