Reputation: 419
I am trying to pass a two-dimensional array to a function. I am not having trouble to pass it to the function. But I am having trouble in understanding the logic behind this. The functions and main definition goes like this:
// Function to print the two-dimensional array
void print(int x, int y, int a[x][y]){
printf("\n");
int i, j;
for(i = 0; i < x; i++){
for(j = 0; j < y; j++)
printf("%d ", a[i][j]);
printf("\n");
}
}
// Function to initialize the two-dimensional array
void init_2d(int *a, int x, int y){
int i, j;
for(i = 0; i < x; i++){
for(j = 0; j < y; j++){
a[i*y + j] = i + j;
}
printf("\n");
}
}
int main(){
int m = 2, n = 3;
int a[m][n]; // a two dimensional whose size has been defined using m and n
init_2d(a, m, n);
print(m, n, a);
}
Ironically everything is working fine. And that is my problem as I am not able to digest the logic of it.
The main problems are:
m
and n
and yet it works fine. Why? init_2d
. But in the print
function I am doing it using a two dimensional array whose size has been defined using variables x
and y
. Is it fine to do so?Can anybody suggest me a good read on this topic which can clear all my concepts?
I am using codeblocks to compile my code and the compiler is GNU GCC Compiler.
Upvotes: 4
Views: 6831
Reputation: 10242
Memory allocation in C arrays is contiguous, that is why expression a[i][j]
(init_2d) can be assimilated to a[i*y + j]
(print).
a
as int**
(2-dim : N x M) can be seen as a int*
one-dimensional array as well (size : N*M)...
See good others answers for 1. 2. and 3.
See : Row-major order (C-style), so 2. is fine.
Note : Apparently, what I'm saying here is only true with recent versions of the C programming language and/or some specific context and is absolutely not generalizable. So better read the several other answers first.
Upvotes: 1
Reputation: 320361
Yes and no. What you read in books is true for the older, original version of C language specification - C89/90. Since C99 version of C language compilers support so called Variable Length Arrays (VLAs), whose size can be specified by run-time values. You inadvertently used that C99-specific feature of the language, which is apparently supported by your compiler in its default mode. If you ask your compiler to switch to the strict C89/90 mode your code will fail to compile specifically because you used non-constants to specify array sizes.
Note that even in C99 VLAs are supported only in certain contexts, like local arrays and function parameter declarations. You will not be able to declare a static VLA or a VLA that is a member of a struct type. In those contexts you are still required to use constant array sizes even in C99.
Whoever told you to decay 2D arrays to 1D arrays was very wrong. The way you use init_2d
in your program is invalid: you are not allowed to "reinterpret" a 2D array as a 1D array by yourself. Any C compiler will immediately complain about your
init_2d(a, m, n);
call, since this call attempts to pass 2D int
array argument for an int *
parameter. This is illegal. To silence the compiler you'd have to do
init_2d((int *) a, m, n);
It is quite possible that your init_2d
will "work as expected", but still there's no good reason to use hacks like that.
What can really be done here is decaying 2D array to a pointer to a 1D array. Believe it or not, this is exactly what you already did in your print
declaration, even if it is not immediately noticeable. Your
void print(int x, int y, int a[x][y])
declaration is actually equivalent to
void print(int x, int y, int (*a)[y])
declaration. I.e. a
is actually a pointer to type int [y]
- a pointer to a 1D int
array of size y
. The above two declarations are just two superficially different ways to say the same thing.
Note also that are not required to pass 2D arrays to functions by "decaying them" to anything. You can pass a 2D array by pointer to the entire 2D array, as in
void print(int x, int y, int (*a)[x][y])
In this case to pass the array you have to use &
operator
print(m, n, &a);
and to access the array inside the function you have to use *
operator
printf("%d ", (*a)[i][j]);
No, in your case it can't be. A built-in 2D array cannot be traversed by pointer-to-pointer. BTW, as you already figured out in your init_2d
implementation (which "works", even though it is illegal), a 2D array is internally implemented as a 1D array with automatic 2D-to-1D index recalculation. Pointer-to-pointer won't help you to traverse such "flat" linear data.
Pointer-to-pointer types (or, more generally, multi-level pointer types) are often used when working with a completely different kind of multi-dimensional arrays: when an N-dimensional array is implemented as an array of pointers to independently allocated (N-1)-dimensional arrays. This kind of multi-dimensional array is also used quite often in C programs, but it has to be implemented and managed manually (you can find quite a few examples here on SO). Meanwhile, as I said above, built-in language arrays are implemented in a completely different fashion and they cannot be traversed by multi-level pointers.
Upvotes: 8
Reputation: 70372
init_2d
takes a int *
, but you have passed it a int (*)[n]
. However, since a
is an array of an array, the address of a[0]
is the same as the address of a[0][0]
, which is why init_2d
"works". Your compiler should have warned you about a type incompatibility when you passed a
to init_2d
. If it did not, you should complain to your compiler vendor.
print
uses VLA for the third parameter.
If you mean "Can I traverse a
with an int **
, the answer is "not in a straightforward manner". The reason is that if you have int **p
, you can only realistically traverse a
if p
is initialized like this:
int a[n][m];
int *ap = &a[0][0];
int **p = ≈
But, then you are just traversing a
via ap
by dereferencing p
. A pointer to a pointer is usually used to represent an array of pointers.
int *x[10];
int **p = x;
But, your a
is not an array of pointers.
Upvotes: 3
Reputation: 757
1) m and n in your main have already a value so your array declaration is just fine.They are used just as numeric constants. 2)An array is a pointer. So
void foo(int array[]);
void foo(int* array);
are exactly the same.
An array int a[2][2] is a 1-dimensional array with 2 pointers to int and those 2 pointers point to 2 integers. So with right playing around your first pointer(in your case a) you can access those integers.
3) look up to wikipedia. There is a good algorithm to understand better.
Upvotes: 0
Reputation: 27802
main
is an example)It looks like the books you are reading conform to the C90 standard. Newer versions of gcc are okay though.
Upvotes: 4
Reputation: 595339
VLAs (variable length arrays) exist in some versions of C. VLAs allow for allocating a fixed-length array on the stack using runtime-assigned variables, versus on the heap via malloc()
or similar function.
I have never seen the array declaration syntax used in print()
before, so I can't answer that. Typically one would leave the brackets empty, or use a decayed pointer.
yes.
Upvotes: 4