Why the array name argv can be assigned? - c

As we know, array name can't be assigned, sentence like:
char * array[], * point;
array = point; /* wrong */
array++; /* wrong */
But in main(int argc, char * argv[]), argv++ is ok and works well.
What do i missing?

In your examples array is a true array, and thus a non-modifiable l-value. In main, since it's declared in the parameter list, argv is actually a char **, i.e. a pointer which is modifiable.
It all boils down to the fact that char *array[] means different things, depending on the context.

In the context of a function parameter declaration, T a[] and T a[N] are both interpreted as T *a; in all three cases, a is declared as a pointer to T, not an array of T. Thus, in int main(int argc, char *argv[]), argv is really declared as char **, or pointer to pointer to char, not array of pointer to char.
(edit -- note that this is true only for function parameter declarations; for a regular variable declaration, T a[N] and T a[] both declare a as an array of T).
Since it's a pointer value, it can be assigned to and it can be incremented.
Beyond that, here's what the language standard has to say:
5.1.2.2.1 Program startup
...
2 If they are declared, the parameters to the main function shall obey the following
constraints:
...
— The parameters argc and argv and the strings pointed to by the argv array shall
be modifiable by the program, and retain their last-stored values between program
startup and program termination.
EDIT
And here's the language for function parameters:
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.
EDIT2
Some examples (assumes a C99 compiler):
void foo(int a[], size_t len)
{
size_t i;
printf("sizeof a = %zu\n", sizeof a);
printf("sizeof (int *) = %zu\n", sizeof (int *));
for (i = 0; i < len; i++)
printf("a[%zu] = %d\n", i, *a++);
}
int main(void)
{
int a1[5] = {0};
int a2[] = {0, 1, 2, 3, 4};
printf("sizeof a1 = %zu\n", sizeof a1);
printf("sizeof a2 = %zu\n", sizeof a2);
foo(a1, sizeof a1 / sizeof a1[0]);
foo(a2, sizeof a2 / sizeof a2[0]);
return 0;
}
One more piece of standardese:
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.
In the function main, a1 and a2 have been declared as 5-element arrays of int; a2 gets its size from the number of elements in the initializer. The expressions a1 and a2 thus have types "5-element array of int" and they may not be targets of an assignment expression, nor may they be operands to the ++ or -- operators. When these expressions appear in the call to foo, their types are converted to "pointer to int" per the rule above. Thus foo receives a pointer value, not an array value, for a (which is covered by the rule that says array parameters are converted to pointer types). So the expression a in foo has type int *, or pointer to int; thus, a may be the target of an assignment, and it may be an operand of ++ and --.
One more difference: per the rule quoted above, the conversion to a pointer type doesn't happen when the array expression is an operand of the sizeof operator; sizeof a1 should evaluate to the number of bytes taken up by the array a1 (5 * sizeof int). However, since a in foo has type int *, not int [5], sizeof a should only evaluate to the number of bytes for an pointer to int (sizeof (int *)).

main(int argc, char * argv[])
or
main(int argc, char **argv)
are same and correct .Because in function arguments array are decayed into pointers
For more read this
But the code you have shown is the actual array . And name of the array gives the address of the first element and it's non modifiable that's why doing this :
array = point;
array++;
is wrong as you have already mentioned it.

Related

Why sizes of an array and a pointer to a first element are different?

Kernighan & Ritchie 2nd ed. says:
The correspondence between indexing and pointer arithmetic is very close. By definition, the value of a variable or expression of type array is the address of element zero of the array. Thus after the assignment
pa = &a[0];
pa and a have identical values. Since the name of an array is a synonym for the location of the initial element, the assignment pa=&a[0] can also be written as
pa = a;
If a and pa are identical, then why this code:
#include <stdio.h>
int main()
{
char a[] = "hello";
char *pa = a;
printf("Array: %ld\n", sizeof(a));
printf("Pointer: %ld\n", sizeof(pa));
}
Outputs this:
Array: 6
Pointer: 8
Reference to an authoritative source would be much appreciated.
Two objects can have the same address but their sizes can be different.
From the C Standard (6.5.3.4 The sizeof and alignof operators)
2 The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand....
Consider the following example
#include <stdio.h>
int main( void )
{
struct A
{
char c;
int x;
} a;
printf( "object a:\taddress - %p size - %zu\n",
&a, sizeof( a ) );
printf( "object a.c:\taddress - %p size - %zu\n",
&a.c, sizeof( a.c ) );
}
The program output is
object a: address - 0x7fff164e16d0 size - 8
object a.c: address - 0x7fff164e16d0 size - 1
As it is seen the object a of type struct A and its data member c of type char have the same address but different sizes.
As for arrays then a pointer is an object that stores an address of other object. To store an address of other object it is enough to allocate for example 4 or 8 bytes of memory for the pointer depending on the used system.
As for arrays then they are named extents of memory. Arrays do not store addresses. They store their own elements (that of course can be pointers).
An array name used in expressions is converted to pointer to its first element.
According to the C 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. If the array object
has register storage class, the behavior is undefined.
In this quote there is listed when an array is not converted to a pointer to its first element. For example when an array is the operand of sizeof operator.
If to return to your program
int main()
{
char a[] = "hello";
char *pa = a;
printf("Array: %ld\n", sizeof(a));
printf("Pointer: %ld\n", sizeof(pa));
}
then in this statement
char a[] = "hello";
string literal "Hello" that has type char[6] is not converted to a pointer.
However in this statement
char *pa = a;
array a is converted to pointer to its first element.
And in this statement
printf("Array: %ld\n", sizeof(a));
array a is not converted to a pointer because it is the operand of the sizeof operator.
However if you used an expression in the sizeof operator for example like this
sizeof( a + 0 )
then you would get a pointer and correspondingly the sizeof would return the size of the pointer instead of the size of the array
They do indeed have identical values. But that doesn't mean they are the same thing.
a is still a fixed-sized array. pa is still a pointer.
sizeof is one operator that recognises this difference.
Your array has 6 elements of size char (sizeof(char) is defined by the standard to be 1). (The 6th element is the string null terminator).
sizeof(char*) is 8 on your system. It's probably 64 bit.
Arrays are not pointers. The array name decays to a pointer to its first element in many cases, but sizeof is one of the few exceptions.
C11 §6.3.2.1 Lvalues, arrays, and function designators
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.
char a[] = "hello";
char *pa = a;
Here sizeof(a) will give size of array a . And sizeof(pa) will give size of pointer pa.Both are different .
Also as in function arguments array decays to pointer but this one is exception along with &.
Also while printing type size_t you should use specifier %zu (as specified in ANSI C99).
a and pa are not identical. Always remember: Arrays are not pointers. When used in an expression arrays are converted to pointer to its first element with some exception including as an operand of sizeof operator.
sizeof(a) will give the size of array while sizeof(pa) will give the size of pointer.

sizeof applied to array types

The c11 standard says that sizeof,
"when applied to an operand that has array type, the result is the
total number of bytes in the array"
(6.5.3.4, bullet 4).
The foot note (103) says:
"When applied to a parameter declared to have array or function type,
the sizeof operator yields the size of the adjusted (pointer) type".
I take from this that when applied to an array type, sizeof gives the size of the array (number of elements x size of elements), but applied to parameters declared to have array type, it gives the size of the pointer.
My question:
How is it possible to have an object of array type that does not produce the size of a pointer, due to the foot note?
I feel like I cannot trust the sizeof operator in some circumstances without knowing this.
Thanks.
EDIT: I guess I should clarify my concern, if "int a[4]" is defined, then I see from the responses that sizeof a==4*sizeof(int), but what about sizeof(a+0)? It seems that sizeof(a+1) must be evaluated as a pointer. I am concerned with circumstances other than function calls where an array decays to a pointer.
In response to your update (being concerned about sizeof(foo+1) type situations:
Yes, sizeof applied to array_name + int is equivalent to sizeof &(array_name[int]);, on the basis that an array, decays into a pointer in those cases. Likewise, to get to the actual value out of the array you don't write arr_name + 1, but rather *(arr_name + 1).
So, taking the footnote into account, when will a sizeof yield the actual array size (in bytes)? For that, look at what the standard says about arrays decaying into pointers:
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.
Meaning:
Using sizeof directly on the array variable (sizeof array_var)
Dereferencing a pointer to an array (sizeof *(&array_var)) Note: This also applies when you pass this pointer to an array to another function, but isn't always the best way to go (see example below)
string literals (like the Rvalue in char foo[] = "foobar"; => sizeof("foobar");)
In all other cases (AFAIK), the array decays into a pointer, and sizeof will yield the size of a pointer:
Arithmetic on array => pointer arithmetic (sizeof (array_var +1 ))
Passing array to function (decays into pointer)
...
passing an array to a function
So using the unary & operator, it is possible to pass a pointer to an array to a function, but it's rarely done. Still, here's an example:
void pointer_to_array(char (*ptr)[]);//pointer to array type
void error_p_to_arr(char (*ptr)[]);
int main ( void )
{
char str[] = "some random string";//array of 18 bytes
printf(
"Sizeof array %zu\n",
sizeof str
);
pointer_to_array(&str);
return 0;
}
//we need to specify the exact type, including size!
//replace 18 with 10, you're fine, but use 20 and you're in trouble
void pointer_to_array(char (*ptr)[18])
{
printf(
"sizeof argument: %zu\nsizeof array %zu",
sizeof ptr,//4 or 8
sizeof *ptr//18!! YaY
);
}
//if we don't specify the array size here
void error_p_to_arr(char (*ptr)[])
{
printf(
"sizeof argument: %zu\nsizeof array %zu",
sizeof ptr,//4 or 8
sizeof *ptr//ERROR!
);
}
The latter sizeof *ptr will cause an error ("invalid application of ‘sizeof’ to incomplete type ‘char[]’"). Because this way of passing an array around is quite error prone (the correct size must be defined everywhere), it's a lot more common common to simply let the array decay, and pass a second argument along with it:
void common_usage(const char *ptr, size_t arr_len);
int main ( void )
{
char str[] = "some random string";
common_usage(str, sizeof str/sizeof *str);
return 0;
}
It looks a lot cleaner, it's a lot more common and just so much easier to maintain.
See examples here
The key point from the quote are "parameter declared to have array type" and "the adjusted (pointer) type". What this is referring to is the fact that a function parameter of "array type" is adjusted to pointer type. Once that adjustment is made, the type is pointer, and its size has to be the size of a pointer. It cannot be anything else. This is how it works:
void foo(int p[42]);
is adjusted to
void foo(int* p);
Those two function declarations are equivalent. So the type of p is int*. and sizeof(int*) is always the size of a pointer.
However, in a different context, there is no type adjustment:
int a[42]; // no adjustment. a is an array of size 42;
sizeof(a); // gives the size of type int[42]
Here, the type of a really is "size 42 array of int". The sizeof operator has access to this (compile-time) information and thus can give the correct size for that type.
Note that this is related to array decay, where an array can "decay" into a pointer to its first element under some circumstances. That decay is what would allow you to call foo with an array argument:
int a[26];
foo(a); // foo(int*): a decays to int*
int* p = a; // same phenomenon
So, adjustment changes the function signature, and decay allows you pass an array to a function that expects a pointer.
Update Concerning your update, the application of binary arithmetic operators is one of the many cases where an array decays to a pointer to its first element. For example
#include <stdio.h>
int main(void)
{
int a[42];
printf("sizeof(a) = %zu\n", sizeof(a));
printf("sizeof(a+1) = %zu\n", sizeof(a+1));
return 0;
}
Output:
sizeof(a) = 168
sizeof(a+1) = 8
The footnote applies to a (function) parameter.
e.g.
void foo(int param_arr[32])
{
int local_arr[32];
}
param_arr is a parameter to the function - and while it looks like an array, it's really a pointer (an int *). So sizeof param_arr yields the size of an int *.
local_arr is not a parameter. So sizeof yields the size of that array.
Having an object of array type that does not produce the size of a pointer is simple: don't do it on a a function argument:
const int foo[32];
printf("hey, foo is %zu bytes\n", sizeof foo);
Will not print sizeof (int *).
This is the normal usage, the text you're quoting is pointing out that when an array is passed to a function, it decays to a pointer, even if the function's prototype specifies an array size.
So this:
static void printsize(int x[100])
{
printf("the argument is %zu bytes\n", sizeof x);
}
int main(void)
{
const int foo[100];
printsize(foo);
return 0;
}
will print sizeof (int *).
Just to clarify your doubt below code might help:
void func(int a[])
{
sizeof(a) is not equal to sizeof(int) * 10 but equal to sizeof(pointer)
Because int a[] is adjusted to int *
}
int main()
{
int a[10];
int *p = a;
//Initialize
//sizeof(a) = sizeof(int) * 10
//sizeof(p) = sizeof(pointer)
func(a);
}
As arrays decay into pointers, when an array is passed to function as a parameter we can illustrate it as declaring parameter as an array as shown below,
void function (char a[])
{ ... }
Now the above declaration is interpreted by compiler differently as a pointer declaration since the function actually receives the pointer to an arrya of type T, as shown below:
void function(char *a)
{ ... }
Therefore, the compiler pretend that the array parameter declared as a pointer (of type char *) and sizeof will give the size of pointer in fact instead of size of array.
Example:
void function (char a[10])
{
int i = sizeof(a);
printf("%d\n", i);
}
Output is acutually 4 and not 10.

meaning of these formal parameters in C

I read these two different types of declaration of multidimensional array in formal parameters of a function in C.
int c[][10];
int (*c)[10];
How these two are same ? I am not getting the feel of it. Can anyone explain this with some example what the second one is trying to do?
Sorry if this has been previously asked..Please redirect me to the duplicate if any.
As a function argument, int* c and int c[] or even int c[7] are identical. See C FAQ.
The [10] part only tells the compiler how to do the arithmetic for accessing an element in the array - e.g. c[3][5]. Both these declarations are for a multidimensional array whose second dimension (as far as the compiler is concerned, inside this function) is of size 10.
Example:
#include <stdio.h>
int sum_all(int c[][2], int len) {
int res = 0, i ,j;
for (i=0; i < len; i++)
for (j=0; j < 2; j++)
res += c[i][j];
return res;
}
int main() {
int a[3][2] = { { 1, 2}, {3, 4}, {5, 6} };
printf("sum is %d\n", sum_all(a, 3));
return 0;
}
Note that the array is not checked to be of size 2, in this example. We could have passed a single dimensional array. The compiler does not care; we only told him how to access the elements in this array.
N1570:
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, within the context of a function parameter declaration, T a[N] and T a[] are both equivalent to T *a; all three declare a as a pointer to T. In this particular case, T is "10-element array of int".
This goes hand-in-hand with the following:
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.
Suppose you have an array declared as
int arr[5][10];
When you pass the array expression arr to a function, such as
foo( arr );
the array expression arr is converted from type "5-element array of 10-element array of int" to type "pointer to 10-element array of int", and that pointer value is what gets passed to the function. So your function prototype for foo would read as
void foo( int (*c)[10] )
or
void foo( int c[][10] )
or even
void foo( int c[5][10] )
but in all three cases, c is a pointer to an array, not a 2D array.
Consider what happens when you define int c[5][10] and then pass c to a routine. The array c will automatically be converted to a pointer to its first element, which is an array of 10 int.
So the language designers arranged it so that when you declare a parameter with c[][10], it is automatically adjusted to match the conversion that will happen. The compiler changes a parameter of type array of array of int to a parameter of type pointer to array of int.

Pointers to arrays problem in C

I have this function that takes a pointer of an array (in order to modify it from within the function)
int func_test(char *arr[]){
return 0;
}
int main(){
char var[3];
func_test(&var);
return 0;
}
When I try to compile this I get :
passing argument 1 of ‘func_test’ from incompatible pointer type
Why is this problem, and how I pass a pointer to that array in this case?
char * arr[] is not a pointer to an array; it is an array of pointers. Declarations in C are read first from the identifier towards the right, then from the identifier towards the left. So:
char * arr[];
// ^ arr is...
// ^ an array of...
// ^ pointers to...
// ^ char
A pointer to an array is a type (*varname)[], in your case, a char (*arr)[].
You are passing the address of a pointer. I think you want this:
int func_test(char arr[]){
arr[0] = 'a';//etc.
return 0;
}
int main(){
char var[3];
func_test(var);
return 0;
}
char var[3] is an array that holds 3 characters, not 3 pointers to characters - char *arr[] denotes an array that holds pointers to characters.
So you can go like this:
char *var[3];
func_test(var);
Note that the ampersand is not needed because array identifiers automatically decay to pointers of the corresponding type, in this case char **.
That's because the name of an array is already a pointer to it, so use func_test(var).
&var will have type char**
This is an array of pointers
char *arr[]
This is an address of a pointer
&var
So you are passing something different to what the function expects
C's treatment of arrays is a little confusing at first.
Except when it's an operand of either the sizeof or unary & operators, or when it's a string literal being used to initialize another array in a declaration, an expression with type "N-element array of T" will be implicitly converted to type "pointer to T", and its value will be the address of the first element in the array.
Assume the following declaration:
int x[10];
The type of the expression x is "10-element array of int". However, when that expression appears as, say, a parameter to a function:
foo(x);
the type of x is implicitly converted ("decays") to type "pointer to int". Thus, the declaration of foo needs to be
void foo(int *p);
foo receives an int *, not an int [10].
Note that this conversion also occurs for something like
i = x[0];
Again, since x isn't an operand of sizeof or &, its type is converted from "10-element array of int" to "pointer to int". This works because array subscripting is defined in terms of pointer arithmetic; the expression a[n] is equivalent to *(a+n).
So for your code, you'd write
int func_test(char *arr) { return (0); }
int main(void)
{
char var[3];
func_test(var); // no & operator
return 0;
}
Postfix operators like [] have higher precedence than unary operators like *, so a declaration like T *a[N] is interpreted as T *(a[N]), which declares an array of pointer to T. To declare a pointer to an array, you have to use parentheses to explicitly group the * operator with the array name, like T (*a)[N].
Here's a handy table of array declarations, expressions, and types:
Declaration: T a[N]; // a is an N-element array of T
Expression Type Decays To
---------- ---- ---------
a T [N] T *
&a T (*)[N]
a[i] T
&a[i] T *
Declaration: T *a[N]; // a is an N-element array of pointer to T
Expression Type Decays To
---------- ---- ---------
a T *[N] T **
&a T *(*)[N]
a[i] T *
*a[i] T
&a[i] T *
Declaration: T (*a)[N] // a is a pointer to an N-element array of T
Expression Type Decays To
---------- ---- ---------
a T (*)[N]
&a T (**)[N]
*a T [N] T *
(*a)[i] T

Multi-dimensional array and pointer to pointers

When you create the multi-dimensional array char a[10][10], according to my book it says you must use a parameter similar to char a[][10] to pass the array to a function.
Why must you specify the length as such? Aren't you just passing a double pointer to being with, and doesn't that double pointer already point to allocated memory? So why couldn't the parameter be char **a? Are you reallocating any new memory by supplying the second 10.
Pointers are not arrays
A dereferenced char ** is an object of type char *.
A dereferenced char (*)[10] is an object of type char [10].
Arrays are not pointers
See the c-faq entry about this very subject.
Assume you have
char **pp;
char (*pa)[10];
and, for the sake of argument, both point to the same place: 0x420000.
pp == 0x420000; /* true */
(pp + 1) == 0x420000 + sizeof(char*); /* true */
pa == 0x420000; /* true */
(pa + 1) == 0x420000 + sizeof(char[10]); /* true */
(pp + 1) != (pa + 1) /* true (very very likely true) */
and this is why the argument cannot be of type char**. Also char** and char (*)[10] are not compatible types, so the types of arguments (the decayed array) must match the parameters (the type in the function prototype)
C language standard, draft n1256:
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. If the array object has register storage class, the
behavior is undefined.
Given a declaration of
char a[10][10];
the type of the array expression a is "10-element array of 10-element array of char". Per the rule above, that gets coverted to type "pointer to 10-element array of char", or char (*)[10].
Remember that in the context of a function parameter declaration, T a[N] and T a[] are identical to T *a; thus, T a[][10] is identical to T (*a)[10].

Resources