Scope Of variable in C - arrays

Look at the code given below, here price,quantity and amount are local to main function we pass them to extend where PRICE,QUANTITY and amount are format argument local to the function. My question is how change in amount which is local to void extend will reflect in main without using pointers.
#include <stdio.h>
void extend(float[], float[], double[]);
int main(void) {
float price[10] = { 10.62, 14.89, 13.21, 16.55, 18.62, 9.47, 6.58, 18.32, 12.15, 3.98 };
float quantity[10] = { 4, 8.5, 6, 8.35, 9, 15.3, 3, 5.4, 2.9, 4.8 };
double amount[10] = { 0 };
extend(price, quantity, amount);
for (int i = 0; i < 10; i++) {
printf("%f ", amount[i]);
}
return 0;
}
void extend(float PRICE[], float QUANTITY[], double amount[]) {
for (int i = 0; i < 10; i++) {
amount[i] = PRICE[i] * QUANTITY[i];
}
}

You are mistaken. Actually the function uses pointers. This function declaration
void extend(float[], float[], double[]);
is adjusted by the compiler to the following declaration
void extend(float *, float *, double *);
From the C Standard (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.
And when the function is called like
extend(price, quantity, amount);
the array designators price, quantity and amount are implicitly converted to pointers to their first elements. So in fact elements of the arrays are passed by reference indirectly through pointers to first elements. Using the pointer arithmetic the elements of the array amount can be changed within the function
amount[i] = PRICE[i] * QUANTITY[i];
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.
Pay attention to that for example this expression amount[i] is equivalent to *( amount + i ).
From the C Standard (6.5.2.1 Array subscripting)
2 A postfix expression followed by an expression in square brackets []
is a subscripted designation of an element of an array object. The
definition of the subscript operator [] is that E1[E2] is identical to
(*((E1)+(E2))). Because of the conversion rules that apply to the
binary + operator, if E1 is an array object (equivalently, a pointer
to the initial element of an array object) and E2 is an integer,
E1[E2] designates the E2-th element of E1 (counting from zero).

Related

Size of an unknown array in C [duplicate]

The following C program:
int doStuff(int afm[]);
int main(){
int afm1[9] = {1,2,3,4,5,6,7,8,9}; //size=9
int afmLength = sizeof(afm1)/sizeof(int);
printf("main: Length Of Array=%d\n", afmLength); //9 OK
int k = doStuff(afm1);
system("PAUSE");
return 0;
}
int doStuff(int afm[]){
int afmLength = sizeof(afm)/sizeof(int);
printf("doStuff: Length Of Array=%d\n", afmLength); //1 WRONG
return 1;
}
produces the following output:
main: Length Of Array=9
doStuff: Length Of Array=1
Why is the array size calculated correctly in main, but is wrong inside the function?
Because in main you have an array and in the function you have a pointer to that array.
int doStuff(int afm[])
is equivalent to
int doStuff(int *afm)
Adding to David Heffernan's answer (which is correct), you should have another parameter which would be the array length passed onto your doStuff method.
From the 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.
Memorize that paragraph, since one of the biggest sources of heartburn in C programming is how C treats array expressions.
When you call doStuff(afm1);, the expression afm1 is implicitly converted from type "9-element array of int" to "pointer to int", and the expression's value is the same as &afm1[0]. So what doStuff receives is a pointer value, not an array.
In the context of a function parameter declaration, T a[] and T a[N] are both interpreted as T *a:
6.7.5.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.
Since doStuff receives a pointer value and not an array, the sizeof trick doesn't work. In general, you have to explicitly tell a function how large of an array you're passing to it; you can't determine that from the pointer value itself.
So, when you call doStuff from main, you'll need to do something like
doStuff(afm1, sizeof afm1/sizeof *afm1);
...
int doStuff(int *afm, size_t afmsize)
{
...
}

Passing an array as a parameter in C

why does this code work?
#include <stdio.h>
void func(int v[]){
v[0] = 1;
}
int main(){
int v[5] = {0};
func(v);
for (int i = 0; i < 5; i++)
{
printf("%d ", v[i]);
}
}
The output I get from this is '1 0 0 0 0' but why? I'm not passing a pointer, why can the function change the array in my main?
Yes, you are passing a pointer.
When you write void func(int v[]) to declare your function signature, it is equivalent to writing void func(int * v).
When you write func(v) to call your function, it is equivalent to func(&v[0]).
This function declaration
void func(int v[]){
v[0] = 1;
}
is adjusted by the compiler to the declaration
void func(int *v){
v[0] = 1;
}
From the C Standard (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
On the other hand, in this call
func(v);
the array designator v is implicitly converted to a pointer to its first element.
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.
That is the function call is equivalent to
func( &v[0] );
So in fact the first element of the array is passed to the function by reference through a pointer to it. Dereferencing the pointer by means of the subscript operator (the expression v[0] is equivalent to the expression *v)
v[0] = 1;
the referenced first element of the array is changed.
It is because array is internally considered as a pointer. It's an identifier for a variable of type array, which has an implicit conversion to pointer of element type.

passing multi-dimensional arrays as function arguments

As we know, when passing arrays as function arguments, only the first dimension's size can be empty, the others must be specified.
void my_function(int arr[5][10][15]); // OKAY!
void my_function(int arr[][10][15]); // OKAY!
void my_function(int arr[][][15]); // WRONG!!!
void my_function(int arr[][][]); // WRONG!!!
What is logic behind this? Could someone explain the main reason?
Passing arrays to a function is an illusion: arrays instantly decay to a pointer when you use them. That is, with this example:
int foo[10];
foo[1];
the way this is interpreted by the compiler, in foo[1], foo is first transformed to a pointer to element 0 of foo, and then subscripting is the same as *(pointer_to_foo + 1).
However, this is only possible with the first dimension of an array. Suppose this:
int foo[5][5];
This puts 25 integer elements contiguously in memory. It is not the same as int** foo, and not convertible to int** foo, because int** foo represents some number of pointers to some number of pointers, and they don't have to be contiguous in memory.
While it's legal to use an array type as a function parameter, the compiler builds it identically to if you had specified a pointer to the array's element type:
int foo(int bar[10]); // identical to `int foo(int* bar)`
But what happens if you pass a multi-dimensional array?
int foo(int bar[5][5]); // identical to what?
Only the first dimension of the array can undergo decay. The equivalent signature for int foo here would be:
int foo(int (*bar)[5]); // identical to `int foo(int bar[5][5])`
where int (*bar)[5] is a pointer to an array of 5 integers. Stacking up more dimensions doesn't change the idea, only the first dimension will decay, and the other dimensions need to have a known size.
In other words, you can skip the first dimension because the compiler doesn't care about its size, as it instantly decays. However, subsequent dimensions do not decay at the call site, so you need to know their size.
Arrays in C and C++ are stored contiguously in memory. In the case of a multidimensional array, this means you have an array of arrays.
When you traverse an array, you don't necessarily need to know how many elements are in the array. You do however need to know the size of each element of the array so you can jump to the correct element.
That's why int arr[][][15] is incorrect. It says that arr is an array of unknown size elements are of type int [][15]. But this means you don't know how big each array element is, so you don't know where each array element it in memory.
Starting with two bits 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.
...
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.
C 2011 online draft
Lovely. What does all that mean?
Let's start with the declaration of an array of some arbitrary type T:
T arr[N];
The type of the expression arr is "N-element array of T" (T [N]). Unless that expression is the operand of the unary &, sizeof, or _Alignof operators as specified in 6.3.2.1/3 above, then the type of the expression is converted ("decays") to "pointer to T" (T *) and the value of the expression is the address of the first element - i.e., &arr[0].
When we pass arr as a parameter to a function, as in
foo( arr );
what foo actually receives is a pointer, not an array, and you would write the function prototype as
void foo( T *arr )
Or...
As a notational convenience, C allows you to declare the formal parameter using array notation:
void foo( T arr[N] )
or
void foo( T arr[] )
In this case, both T arr[N] and T arr[] are "adjusted" to T *arr as per 6.7.6.3/7 above, and all three forms declare arr as a pointer (this is only true for function parameter declarations).
That's easy enough to see for 1D arrays. But what about multidimensional arrays?
Let's replace T with an array type A [M]. Our declaration now becomes
A arr[N][M]; // we're creating N M-element arrays.
The type of the expression arr is "N-element array of M-element arrays of A" (A [M][N]). By the rule above, this "decays" to type pointer to *M-element array* ofA" (A (*)[M]`). So when we call
foo( arr );
the corresponding prototype isvoid foo( A (*arr)[M] )1
which can also be written as
void foo( A arr[N][M] )
or
void foo( A arr[][M] );
Since T arr[N] and T arr[] are adjusted to T *arr, then A arr[N][M] and A arr[][M] are adjusted to A (*arr)[M].
Let's replace A with another array type, R [O]:
R arr[N][M][O];
The type of the expression arr decays to R (*)[M][O], so the prototype of foo can be written as
void foo( R (*arr)[M][O] )
or
void foo( R arr[N][M][O] )
or
void foo( R arr[][M][O] )
Are you starting to see the pattern yet?
When a multi-dimensional array expression "decays" to a pointer expression, only the first (leftmost) dimension is "lost", so in a function prototype declaration, only the leftmost dimension my be left blank.
Since the subscript [] operator has a higher precedence than the unary * operator, A *arr[M] would be interpreted as "M-element array of pointers to A", which is not what we want. We have to explicitly group the * operator with the identifier to properly declare it as a pointer to an array.

Matrix as function parameter

Why when using a matrix as a parameter of a function we must specify the number of columns but we don't have to indicate number of rows?
I assume you're talking about a function definition like
void foo( int matrix[][COLS] ) { ... }
This requires a little background...
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. So, given the declaration
int arr[10];
the expression arr will have type "10-element array of int"; unless this expression is the operand of the sizeof or unary & operators, it will be converted ("decay") to an expression of type "pointer to int". So if we pass that array to a function, like
blurga( arr );
what blurga receives is a pointer to int, not an array of int. So we can define blurga as
void blurga( int *ap )
{
// do something with ap[i]
}
The formal parameter ap has type "pointer to int". Note that you can use the [] operator on pointer expressions as well as array expressions1.
Now, in the context of a formal parameter declaration, T a[N] and T a[] are interpreted as T *a; all three declare a as a pointer to T, not an array of T. So we can rewrite that function definition as
void blurga( int ap[] )
{
// do something with ap[i]
}
Again, int ap[] is interpreted exactly the same as int *ap.
Now let's look at a two-dimensional array:
int blah[10][10];
The expression blah has type "10-element array of 10-element array of int". Going by the conversion rule above, the expression blah will decay to an expression of type "pointer to 10-element array of int", or int (*)[10]. So if we pass blah to a function, what the function receives is a pointer to an array, not an array of arrays:
void bletch( int (*barr)[10] );
As before T a[] is interpreted as T *a, so we can write that declaration as
void blech( int barr[][10] ); // barr[] == (*bar)
Just remember that barr is a pointer type, not an array type.
1. In fact, a[i] is defined as the result of *(a + i); given a pointer value a, we offset i elements from that address and dereference the result. So basically, the conversion rule still applies; the array expression a is being converted to a pointer expression, and that pointer expression is what the [] is being applied to.

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.

Resources