Pointer Arithmetic with array of char in c - 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";

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.

how a sizeof works when array name is passed

Why sizeof(array_name) is the size of the array and sizeof(&a[0]) is the size of pointer even though, when an array name is passed to a function, what is passed is the location of the beginning of the array.
In most expressions, when an array is used, it is automatically converted to a pointer to its first element.
There is a special rule for sizeof: When an array is an operand of sizeof, it is not automatically converted to a pointer. Therefore, sizeof array_name gives the size of the array, not the size of a pointer.
This rule also applies to the unary & operator : &array_name is the address of the array, not the address of a pointer.
Also, if an array is a string literal used to initialize an array, it is not converted to a pointer. The string literal is used to initialize the array.
The rule for this is C 2018 6.3.2.1 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. If the array object has register storage class, the behavior is undefined.
Array parameters to functions don't exist. They turn into pointers (the innermost index does, if the array is multidimensional). It's just syntactic sugar inherited from the B language. void f(int *X) == void f(int X[]);
(Same for function params to functions. void g(void X(void)) == void g(void (*X)(void))).

L Value required as increment operator - 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.

How does an unsized array declaration act as a pointer?

How does char s[] act as a pointer while it looks like an array declaration?
#include<stdio.h>
void test(char s[]);
int main()
{
char s[10]="test";
char a[]=s;
test(s);
char p[]=s;
return 0;
}
void test(char s[])
{
printf(s);
}
In the context of a function parameter declaration (and only in that context), T a[N] and T a[] are the same as T *a; they declare a as a pointer to T, not an array of T.
Chapter and verse:
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.
Anywhere else, T a[]; declares a as an array with an as-yet-unspecified size. At this point the declaration is incomplete, and a cannot be used anywhere until a size has been specified, either by specifying it explicitly:
T a[N];
or using an initializer:
T a[] = { /* comma-separated list of initial values */ }
Chapter and verse, again:
6.7.6.2 Array declarators
...
3 If, in the declaration ‘‘T D1’’, D1 has one of the forms: D[ type-qualifier-listopt assignment-expressionopt ]
D[ static type-qualifier-listopt assignment-expression ]
D[ type-qualifier-list static assignment-expression ]
D[ type-qualifier-listopt * ]
and the type specified for ident in the declaration ‘‘T D’’ is ‘‘derived-declarator-type-list
T’’, then the type specified for ident is ‘‘derived-declarator-type-list array of T’’.142)
(See 6.7.6.3 for the meaning of the optional type qualifiers and the keyword static.)
4 If the size is not present, the array type is an incomplete type. If the size is * instead of
being an expression, the array type is a variable length array type of unspecified size,
which can only be used in declarations or type names with function prototype scope;143)
such arrays are nonetheless complete types. If the size is an integer constant expression
and the element type has a known constant size, the array type is not a variable length
array type; otherwise, the array type is a variable length array type. (Variable length
arrays are a conditional feature that implementations need not support; see 6.10.8.3.)
142) When several ‘‘array of’’ specifications are adjacent, a multidimensional array is declared.
143) Thus, * can be used only in function declarations that are not definitions (see 6.7.6.3).
...
6.7.9 Initialization
...
22 If an array of unknown size is initialized, its size is determined by the largest indexed
element with an explicit initializer. The array type is completed at the end of its
initializer list.
So, why are arrays as function parameters treated differently than arrays as regular objects? This is why:
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 "N-element array of T" is converted ("decays") to an expression of type "pointer to T". If you pass an array expression as an argument to a function, like so:
int foo[10];
...
bar( foo );
what the function bar actually receives is a pointer to int, not a 10-element array of int, so the prototype for bar can be written
void bar( int *f );
"But why..." I hear you starting to ask. I'm getting to it, really.
C was derived from an earlier language called B (go figure), and in B the following things were true:
Pointer objects were declared using empty bracket notation - auto p[];. This syntax was kept for pointer function parameter declarations in C.
Array declarations set aside memory not only for the array elements, but also for an explicit pointer to the first element, which was bound to the array variable (i.e., auto v[10] would set aside 11 memory cells, 10 for the array contents, and the remaining one to store an offset to the first element).
The array subscript operation a[i] was defined as *(a + i) -- you'd offset i elements from the base address stored in the variable a and dereference the result (B was a "typeless" language, so all scalar objects were the same size).
For various reasons, Ritchie got rid of the explicit pointer to the first element of the array, but kept the definition of the subscript operation. So in C, when the compiler sees an array expression that isn't the operand of the sizeof or unary & operators, it replaces that expression with a pointer expression that evaluates to the address of the first element of the array; that way the *(a + i) operation still works the way it did in B, without actually setting aside any storage for that pointer value. However, it means arrays lose their "array-ness" in most circumstances, which will bite you in the ass if you aren't careful.
You can't assign to arrays, only copy to them or initialize them with a valid initializer (and another array is not a valid initializer).
And when you declare a function like
void test(char s[]);
it's actually the same as declaring it
void test(char *s);
What happens when you call a function taking an "array" is that the array decays to a pointer to the first element, and it's that pointer that is passed to the function.
So the call
test(s);
is the same as
test(&s[0]);
Regarding the function declaration, declaring a function taking an array of arrays is not the same as declaring a function taking a pointer to a pointer. See e.g. this old answer of mine as an explanation of why.
So if you want a function taking an array of arrays, like
void func2(char a[][X]);
it's not the same as
void func2(char **a);
Instead it's the same as
void func2(char (*a)[X]);
For more "dimensions" it doesn't change anything, e.g.
void func3(char a[][X][Y]);
is the same as
void func3(char (*a)[X][Y]);
char a[] is an array and not a pointer, the inittialization is invalid.
s is an array, too, but in the context of an expression it evaluates to a pointer to its first element.
char a[] is only valid if you have a following initializer list. It has to be an array of characters. As a special case for strings, C allows you to type an array of characters as "str", rather than {'s','t','r','\0'}. Either initializer is fine.
In the code char a[]=s;, s is an array type and not a valid initializer, so the code will not compile.
void test(char s[]) is another special case, because arrays passed as parameters always get replaced by the compiler with a pointer to the first element. Don't confuse this with array initialization, even though the syntax is similar.

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.

Resources