I am currently studying C language.
I wonder what 'array decaying' means, and when it happens.
And I wonder if the two variables below are interpreted in the same way.
char(*zippo)[2] = NULL;
char zippo2[4][2];
zippo = (char(*)[2])malloc(sizeof(char[2]) * 4);
From 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.
The two variables below
char(*zippo)[2] = NULL;
char zippo2[4][2];
have different types. The first one is a pointer to an object of the type char[2]. The second one is a two-dimensional array with four elements of the type char[2].
When the array zippo2 is used in expression except the expressions listed in the quote (as for example using it with the sizeof operator) then its designator is implicitly converted to pointer to its first element and has the same type as the variable zippo.
Related
I was wondering why in C this is possible:
int MATRICE[20][20];
int *p; p = MATRICE[19]; is equal to p = &(MATRICE[19][0]);
I tried to interpretate it in this way: I consider the label "MATRICE" as a constant pointer and like an array of pointers, so when it comes to the 20th pointer (MATRICE[19]) it points at the same thing that MATRICE[19][0] points too.
Is my idea correct?
Arrays used in expressions with rare exceptions are converted to pointers to their first elements.
From 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.
This expression
MATRICE[19]
yields a one-dimensional array of the type int[20] that is implicitly converted to pointer to its first element of the type int * when used as an initializer (as a right side hand expression in the assignment) in this code snippet
int *p; p = MATRICE[19];
i am new to learning C and i have a brief question: i have been told that functions always use representatives of the values passed to them, so it is not possible to change the values from within the function if you do not use a pointer.
We have frequently used functions to change arrays though?
Why can my function change an array if everything passed to the function is just a copy?
i am sorry if this is a stupid question but i did not find it answered anywhere.
From 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.
If you have a function like for example
void f( int a[], size_t n );
then the compiler adjusts the parameter having the array type to pointer to the array element type.
That is the above function declaration is equivalent to
void f( int *a, size_t n );
From the C Standar (6.7.6.3 Function declarators (including prototypes))d
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.
On the other hand, according to the first quote from the C Standard an array used as an argument expression is implicitly converted to a pointer to its first element.
So the function deals with a pointer and using the pointer arithmetic and dereferencing obtained pointers can change elements of the passed array.
That is in fact elements of arrays are passed by reference indirectly through pointers to them.
I am a beginner in programming. It was taught that arrays store address of the first element. While using for loop when I input the Array elements using scanf I should not use & character right
it should be ("%d",Arr[i]) , instead of ("%d",&Arr[i]) .
but why it is showing error?
Array type has a special property, in some of the cases, a variable with type array decays to a type as pointer to the first element of the array.
Quoting C11, chapter §6.3.2.1
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. [...]
However, if the type is not an array type, it does not hold.
From your description, it sounds you have the array defined as
int Arr[16]; // 16 is arbitrary, just for example
In your case, Arr is an array of integers and Arr[i] is not an array type, it's an integer. So, you have to pass the address of this integer to scanf().
The correct statement would be
("%d",&Arr[i]); // passing the address.
To compare, if you have an array defined like
char array [16];
then you can write
scanf("%15s", array); // 'array' is array type, which is same as `&array[0]` in this case
(Self-answered Q&A - this matter keeps popping up)
I assume that the reader is aware of how pointer arithmetic works.
int arr[3] = {1,2,3};
int* ptr = arr;
...
*(ptr + i) = value;
Teachers/C books keep telling me I shouldn't use *(ptr + i) like in the above example, because "pointers support array style indexing" and I should be using ptr[i] = value; instead. No argument there - much easier to read.
But looking through the C standard, I find nothing called "array style indexing". In fact, the operator [] is not expecting either operand to be an array, but instead a pointer or an integer!
6.5.2.1 Array subscripting
Constraints
One of the expressions shall have type ‘‘pointer to complete object type’’, the other expression shall have integer type, and the result has type ‘‘type’’.
Why does the array subscripting operator not expect an array? Is the standard wrong? Is my teacher/C book confused?
You should indeed be using ptr[i] over *(ptr + i) for readability reasons. But apart from that, the [] operator is, strictly speaking, actually never used with an array operand.
Arrays, when used in an expression, always "decay" into a pointer to the first element (with some exceptions). C17 6.3.2.1/3, emphasis mine:
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 that whenever you type arr[i], the operand arr gets replaced by a pointer to the first element inside that array. This is informally referred to as "array decaying". More info here: What is array decaying?
So whenever you use the [] operator, you use it on a pointer. Always.
The C standard says that this operator is guaranteed to be equivalent to the pointer arithmetic (C17 6.5.2.1/2):
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))).
So whenever we type arr[i], it actually gets silently replaced by *(arr+i). Where arr is still a pointer to the first element.
And this is why the description you quoted tells you that either operand could be a pointer and the other an integer. Because obviously it doesn't matter if we type *(arr+i) or *(i+arr) - that's equivalent code.
Which in turn allows us to write obfuscated "joke" code like i[arr], which is actually valid C and fully equivalent to arr[i]. But don't write such code in real applications.
This question already has answers here:
In C, are arrays pointers or used as pointers?
(6 answers)
Closed 9 years ago.
When the array variable is considered as pointer and when it is considered as simple array in C? As example sometimes sizeof(array_variable) operator returns the address size and sometimes it returns the size of the array.
C 2011 (N1570) 6.3.2.1 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.
C 2011 (N1570) 6.7.6.3 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.
In a function argument, an array ([]) or [...]) is equivalent to a pointer (*). So sizeof(myarg) == sizeof(void*) is true for void f(char *myarg);, void f(char myarg[]); and void f(char myarg[42]);.
In global and local variables, an array is different from a pointer. sizeof(...) reflects that difference.
An array can always be converted to a pointer automatically (but not the other way round), and the address of the first element is used, i.e. ary is converted to &ary[0].
Always it is treated as pointer .
when you use array name without index , it will give the base address of the array . When you use the array name with index , it will be treated as *(array name + index) . It gives the indexe-th element from the base address . *array means first element .
name of an array variable is always a pointer. It is the specilization of sizeof() that it returns the size of an array if applied to an array variable.