I want to write a C function that takes a dynamic 2D array as an input, but doesn't alter the array.
I'm trying to be const correct, not only to make my code clearer, but because my functions are going to be called from within C++ code, and C++ is pretty persnickety about these things.
How do I declare a function to take 'const' pointer to a pointer, i.e. how do I indicate that the function will not alter the contents of the 2d array?
What follows is a specific, super-simple example. I'm using a 2D array of doubles, i.e. double**, to represent a square matrix in C of size n x n, and I want to write a function that computes the trace of one of these matrices:
#include <stdlib.h>
#include <stdio.h>
double **sqr_matrix_new(int n)
{
double **a = calloc(n, sizeof(double*));
int i;
for (i=0; i < n; ++i) a[i] = calloc(n, sizeof(double));
return a;
}
void sqr_matrix_free(double **a, int n)
{
int i;
for (i=0; i < n; ++i) free(a[i]);
free(a);
}
double sqr_matrix_trace(double **a, int n)
{
double trace;
int i;
for (i=0, trace=0.0; i < n; ++i) trace += a[i][i];
return trace;
}
double sqr_matrix_trace_const(const double * const *a, int n)
{
double trace;
int i;
for (i=0, trace=0.0; i < n; ++i) trace += a[i][i];
return trace;
}
int main(int argc, char *argv[])
{
int n = 10;
double **a = sqr_matrix_new(n);
int i, j, k;
for (i=0, k=0; i < n; ++i){
for (j=0; j < n; ++j) a[i][j] = k++;
}
printf("trace is %g\n", sqr_matrix_trace(a, n));
printf("trace is %g\n", sqr_matrix_trace_const(a, n));
printf("trace is %g\n", sqr_matrix_trace_const((const double * const *)a, n));
sqr_matrix_free(a, n);
}
In the above, both versions of the trace function, sqr_matrix_trace() and sqr_matrix_trace_const() compile cleanly (the latter is the one I prefer because it clearly demonstrates that there will be no alteration of the matrix it's given), but the call
sqr_matrix_trace_const(a, n)
produces the following warning:
sqr_matrix.c: In function 'main':
sqr_matrix.c:44: warning: passing argument 1 of 'sqr_matrix_trace_const' from incompatible pointer type
sqr_matrix.c:27: note: expected 'const double * const*' but argument is of type 'double **'
The cast overcomes this:
sqr_matrix_trace_const((const double * const *)a, n)
but it feels wrong to use a cast to use to overcome compiler inconveniences.
Alternatively, I could suppress the compiler warning, but that's a cop-out.
So, I want my code to compile cleanly and I want to convey the const-ness of a dynamic 2D array given to a function without resorting to a cast. It seems like a legitimate aim. Is this possible? If not, what's the standard/accepted practice for doing this?
The C const promotion rules don't allow promotion from T ** to const T const *. Per 6.5.16.1 1 (which applies to function calls as well as assignments per 6.5.2.2 2), conversion of pointers can only add qualifiers to the pointed-to type.
This is to prevent code like (example from 6.5.16.1 6):
const char **cpp;
char *p;
const char c = 'A';
cpp = &p; // constraint violation
*cpp = &c; // valid
*p = 0; // valid
It's correct to observe that const *const *cpp = &p is safe because then *cpp = &c is prevented, but this is a sufficiently obscure case that it's not covered in the standard.
Conclusion: you can and should cast to const double *const * yourself.
Note that it would be more efficient to use a single array of type double * with length n * n and do any necessary array indexing yourself: d[i][j] becomes d[i * n + j].
A C++ compiler would allow that.
As for C, qualified pointer types are not applied recursively.
If your matrix data truly is 2D and rectangular (without a "ragged right edge"), I don't see why you're not representing it as a single double * to the first element, together with integers giving width and height. This would allow you to both cut down on the number of allocations needed to initialize the matrix, but also make it representable as a plain old const double *.
Related
I dynamically allocated memory for 3D array of pointers. My question is how many pointers do I have? I mean, do I have X·Y number of pointers pointing to an array of double or X·Y·Z pointers pointing to a double element or is there another variant?
double*** arr;
arr = (double***)calloc(X, sizeof(double));
for (int i = 0; i < X; ++i) {
*(arr + i) = (double**)calloc(Y, sizeof(double));
for (int k = 0; k < Y; ++k) {
*(*(arr+i) + k) = (double*)calloc(Z, sizeof(double));
}
}
The code you apparently intended to write would start:
double ***arr = calloc(X, sizeof *arr);
Notes:
Here we define one pointer, arr, and set it to point to memory provided by calloc.
Using sizeof (double) with this is wrong; arr is going to point to things of type double **, so we want the size of that. The sizeof operator accepts either types in parentheses or objects. So we can write sizeof *arr to mean “the size of a thing that arr will point to”. This always gets the right size for whatever arr points to; we never have to figure out the type.
There is no need to use calloc if we are going to assign values to all of the elements. We can use just double ***arr = malloc(X * sizeof *arr);.
In C, there is no need to cast the return value of calloc or malloc. Its type is void *, and the compiler will automatically convert that to whatever pointer type we assign it to. If the compiler complains, you are probably using a C++ compiler, not a C compiler, and the rules are different.
You should check the return value from calloc or malloc in case not enough memory was available. For brevity, I omit showing the code for that.
Then the code would continue:
for (ptrdiff_t i = 0; i < X; ++i)
{
arr[i] = calloc(Y, sizeof *arr[i]);
…
}
Notes:
Here we assign values to the X pointers that arr points to.
ptrdiff_t is defined in stddef.h. You should generally use it for array indices, unless there is a reason to use another type.
arr[i] is equivalent to *(arr + i) but is generally easier for humans to read and think about.
As before sizeof *arr[i] automatically gives us the right size for the pointer we are setting, arr[i].
Finally, the … in there is:
for (ptrdiff_t k = 0; k < Y; ++k)
arr[i][k] = calloc(Z, sizeof *arr[i][k]);
Notes:
Here we assign values to the Y pointers that arr[i] points to, and this loop is inside the loop on i that executes X times, so this code assigns XY pointers in total.
So the answer to your question is we have 1 + X + XY pointers.
Nobody producing good commercial code uses this. Using pointers-to-pointers-to-pointers is bad for the hardware (meaning inefficient in performance) because the processor generally cannot predict where a pointer points to until it fetches it. Accessing some member of your array, arr[i][j][k], requires loading three pointers from memory.
In most C implementations, you can simply allocate a three-dimensional array:
double (*arr)[Y][Z] = calloc(X, sizeof *arr);
With this, when you access arr[i][j][k], the compiler will calculate the address (as, in effect, arr + (i*Y + j)*Z + k). Although that involves several multiplications and additions, they are fairly simple for modern processors and are likely as fast or faster than fetching pointers from memory and they leave the processor’s load-store unit free to fetch the actual array data. Also, when you are using the same i and/or j repeatedly, the compiler likely generates code that keeps i*Y and/or (i*Y + j)*Z around for multiple uses without recalculating them.
Well, short answer is: it is not known.
As a classic example, keep in mind the main() prototype
int main( int argc, char** argv);
argc keeps the number of pointers. Without it we do not know how many they are. The system builds the array argv, gently updates argc with the value and then launches the program.
Back to your array
double*** arr;
All you know is that
arr is a pointer.
*arr is double**, also a pointer
**arr is double*, also a pointer
***arr is a double.
What you will get in code depends on how you build this. A common way if you need an array of arrays and things like that is to mimic the system and use a few unsigned and wrap them all with the pointers into a struct like
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
A CSV file for example is char ** **, a sheet workbook is char ** ** ** and it is a bit scary, but works. For each ** a counter is needed, as said above about main()
A C example
The code below uses arr, declared as double***, to
store a pointer to a pointer to a pointer to a double
prints the value using the 3 pointers
then uses arr again to build a cube of X*Y*Z doubles, using a bit of math to set values to 9XY9.Z9
the program uses 2, 3 and 4 for a total of 24 values
lists the full array
list the first and the very last element, arr[0][0][0] and arr[X-1][Y-1][Z-1]
frees the whole thing in reverse order
The code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
int print_array(double***, int, int, int);
int main(void)
{
double sample = 20.21;
double* pDouble = &sample;
double** ppDouble = &pDouble;
double*** arr = &ppDouble;
printf("***arr is %.2ff\n", ***arr);
printf("original double is %.2ff\n", sample);
printf("*pDouble is %.2ff\n", *pDouble);
printf("**ppDouble is %.2ff\n", **ppDouble);
// but we can build a cube of XxYxZ doubles for arr
int X = 2;
int Y = 3;
int Z = 4; // 24 elements
arr = (double***)malloc(X * sizeof(double**));
// now each arr[i] must point to an array of double**
for (int i = 0; i < X; i += 1)
{
arr[i] = (double**)malloc(Y * sizeof(double*));
for (int j = 0; j < Y; j += 1)
{
arr[i][j] = (double*)malloc(Z * sizeof(double));
for (int k = 0; k < Z; k += 1)
{
arr[i][j][k] = (100. * i) + (10. * j) + (.1 * k) + 9009.09;
}
}
}
print_array(arr, X, Y, Z);
printf("\n\
Test: first element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n\
last element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n",
0, 0, 0, arr[0][0][0],
(X-1), (Y-1), (Z-1), arr[X-1][Y-1][Z-1]
);
// now to free this monster
for (int x = 0; x < X; x += 1)
{
for (int y = 0; y < Y; y += 1)
{
free(arr[x][y]); // the Z rows
}
free(arr[x]); // the plane Y
}
free(arr); // the initial pointer;
return 0;
}; // main()
int print_array(double*** block, int I, int J, int K)
{
for (int a = 0; a < I; a += 1)
{
printf("\nPlane %d\n\n", a);
for (int b = 0; b < J; b += 1)
{
for (int c = 0; c < K; c += 1)
{
printf("%6.2f ", block[a][b][c]);
}
printf("\n");
}
}
return 0;
}; // print_array()
The output
***arr is 20.21f
original double is 20.21f
*pDouble is 20.21f
**ppDouble is 20.21f
Plane 0
9009.09 9009.19 9009.29 9009.39
9019.09 9019.19 9019.29 9019.39
9029.09 9029.19 9029.29 9029.39
Plane 1
9109.09 9109.19 9109.29 9109.39
9119.09 9119.19 9119.29 9119.39
9129.09 9129.19 9129.29 9129.39
Test: first element is arr[0][0[0] = 9009.09 (9XY9.Z9)
last element is arr[1][2[3] = 9129.39 (9XY9.Z9)
I am trying to write a user defined function that takes some matrices and variables as inputs and gives a matrix as output. So something like this:
cofactor(int A[100][100], n, r, c){
int B[100][100]
//B becomes the cofactor matrix of A after some operations//
return B;
}
and in my main function I just want to write :
C=cofactor(D, n, r, c);
to turn C into the cofactor matrix of D.
But for some reason c language does not support taking a whole 2D array as output of a function. How can I work around this?
I don't want to keep all the junk in the main function. I want to write a separate function that gives me the matrix as output, and simply call that function in my main function.
Currently in your code B will go out of scope and will be destroyed when control exits cofactor.
Thus use pointer to pointer as below.
int **cofactor(int A[100][100], int n, int r, int c){
int **B = malloc(sizeof(int *)*r);
for (int i =0;i<r;i++)
B[i] = malloc(sizeof(int)*c);
//B becomes the cofactor matrix of A after some operations//
return B;
}
And from main.
int **C=cofactor(D, n, r, c);
Note:: NULL checks are not added and allocated memory needs to be freed once done with the processing.
You are correct in that C doesn't allow us to return arrays from functions. This is one area where C is simply plain bad and you'll find yourself choosing between various evils.
The most obvious alternatives are to return an array pointer, or a void pointer.
void pointers should be avoided since they have non-existent type safety.
// bad code
void* cofactor (int A[100][100], int n, size_t r, size_t c)
The array pointer option is rather ugly-looking, hard to read and enforces fixed-size dimensions:
// bad code
int ( *cofactor (int A[100][100], int n, size_t r, size_t c) )[100][100];
Alternatively, also ugly and bad practice, is to hide the array type behind a typedef:
// bad code
typedef int arr_t [100][100];
arr_t* cofactor(int A[100][100], int n, size_t r, size_t c)
The array pointer versions also have the limit that you can't use variable dimensions. But r and c here seem to be rows and columns, so you probably do want the array to have variable size.
This is where some start to use int** out of confusion. But int** cannot be used to point at a 2D array, nor to the first element of a 2D array. It can be used to point at the first element of a 1D array of int* pointers, and then emulate something that looks like an array, but doesn't behave like one. That's not what you want here either, because it is both slow and dangerous. See Correctly allocating multi-dimensional arrays.
Sigh. So what to use!
If you drop the requirement of "function return ing array" (with emphasis on using return), it turns easier and more flexible. Parameter passing to/from functions in C is most often done through the parameters, and most sound APIs reserve the return value for an error type describing the outcome of the function.
The big advantage here is that when passing an array as parameter, we can use variable dimensions:
void func (size_t r, size_t c, int A[r][c])
Suddenly you can have a function accepting any array size, and somewhat type safe as long as r and c have correct values.
The cleanest is to leave allocation to the caller. Then you get
void func (size_t r, size_t c, int A[r][c], int B[r][c])
Out of all options discussed, this is the only pretty one. But it won't work if the function must do the allocation. Then we must return an array through the parameter. And to that with this syntax, turns a bit ugly too:
void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
But if we can live with this strange-looking "pointer to array pointer to an array of int[r][c]", then it solves all problems. It can return an array of variable size from a function to the caller.
A function making a copy of any array and returning it would look like this:
void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
*B = malloc( sizeof(int[r][c]) );
int (*b)[c] = **B; // pointer to the first row in an array int[r][c]
for(size_t i=0; i<r; i++)
{
for(size_t j=0; j<c; j++)
{
b[i][j] = A[i][j];
}
}
}
Or if you will:
#include <string.h>
void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
*B = malloc( sizeof(int[r][c]) );
memcpy( *B, A, sizeof(int[r][c]) );
}
Full example:
#include <stdlib.h>
#include <stdio.h>
void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
*B = malloc( sizeof(int[r][c]) );
int (*b)[c] = **B; // pointer to the first row in an array int[r][c]
for(size_t i=0; i<r; i++)
{
for(size_t j=0; j<c; j++)
{
b[i][j] = A[i][j];
}
}
}
int main (void)
{
int array1[2][3] = { {1,2,3}, {4,5,6} };
int (*array2)[2][3];
copy(2, 3, &array2, array1);
int (*arr)[3] = *array2;
for(size_t i=0; i<2; i++)
{
for(size_t j=0; j<3; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
free(array2);
}
In my function bodies reduce() and initialize(...) I want to work with the array globalArray as a three-dimensional one, where the dimensions are not known until runtime.
How do I cast the globalArray pointer to a variable-length array (pointer) and use it naturally?
I think the typedef approach helps, but I'm still lost. This current version compiles and seemingly works after my tinkering. Are Cast #1 and Cast #2 as clear and safe as can be achieved?
#include <stdlib.h>
#include <stdio.h>
double * globalArray; /* working from a situation where the array is global, declared elsewhere */
int M, N, P; /*array dimensions not known until runtime */
double reduce();
double reduce()
{
/* Here I want to re-interpret the one-dimensional globalArray into
a multi-dimensional variable-length array so that compiler takes
care of the indexing math for me.*/
typedef double (*arr_t)[N][P];
const arr_t castArray = (arr_t)globalArray; /* Cast #1 */
double sum=0.0;
for (int i=0; i<M; i++)
for (int j=0; j<N; j++)
for (int k=0; k<P; k++)
sum += castArray[i][j][k];
return sum;
}
void initialize(int M, int N, int P, double threedimarray[M][N][P])
{
for (int i=0; i<M; i++)
for (int j=0; j<N; j++)
for (int k=0; k<P; k++)
threedimarray[i][j][k] = (double)(i*N*P + j*P + k);
}
int main(int argc, char **argv)
{
M = 10; N=1000; P=200;
globalArray = malloc( M*N*P* sizeof(double) );
typedef double (*arr_t)[N][P];
initialize(M, N, P, (arr_t)globalArray); /* Cast #2 */
double result = reduce();
printf("Reduced result: %f\n", result );
return 0;
}
https://ideone.com/5Y8Q64
I'm reworking a small section of a large program. There are clearly better design approaches than program scope array pointers. It is what it is.
From a self-documenting point-of-view, it'd be nice if the solution doesn't throw away the fact that we "know" the extent of the leading dimension (M) as well.
The similar SO questions relating to function argument declarations are helpful but I'm not connecting the dots I guess. I decided to ask here hoping the answer will reach more people.
Here's one possible casting solution I've arrived at after some tinkering.
typedef double (*arr_t)[N][P];
arr_t castArray = (arr_t)globalArray;
/* Now castArray can be accessed by multi-dimensional index notation */
castArray[i][j][k] = 3.14;
Downsides:
1) Does not self-document known leading dimension length M.
I am writing a n x n matrix multiplication program in C where a[][] and b[][] are the inputs and x[][] is the output. a, b and x are malloc'd but I am unsure how to pass the pointers to the multiplication function correctly. below is an outline of what i am trying to do
void multiplication(float a, float b, float x, int n);
void main() {
float **a, **b, **x;
int n; // size of arrays (n x n)
multiplication(a, b, x, n);
}
void multiplication(float a, float b, float x, int n) {
// function
}
You want void multiplication(float *a, float *b, float *x, int n);. Note that generally you should use size_t for indexes and array sizes, and double as your preferred floating point type unless you have specific reason to use float.
Each of a, b and x point to contiguous float values, you will want to dereference these using a[n * x + y].
C99 introduces all kinds of interesting optimization possibilities on top of this, all of which you pretty much can't rely upon in any compiler I know of:
Variable Length Arrays in GCC
Arrays in XL C/C++ V7.0 (for AIX)
With those, something like this should be possible:
void multiplication(size_t len; // <- semicolon not a mistake
double a[len][restrict const len],
double b[len][restrict const len],
double c[len][restrict const len]);
This pedantic construction would indicate to the compiler that the length of the arrays are are the same, they're 2D, and the sizes are indicated from the calling code at runtime. Furthermore all the arrays are cacheable as they don't alias one another.
One can only dream that C continues to be advanced, C99 still isn't fully supported, and many other improvements haven't become mainstream.
you have to pass the address of first element of both matrix in multiplication method
actually the thing is that the elements of an array is arranged like queue means one element after another. so if you know the address of first element then you just increase the index number and you easily get all member of that array.
check this
it might be help you
Well, you must understand pointers for doing this kind of things in C. Here's a simple code:
int n = 10;
float * multiply ( float *a, float *b ) {
float *ans;
int i, j, k;
ans = malloc(sizeof(float)*n*n);
for (i=0; i<n; ++i)
for (j=0; j<n; ++j) {
ans[i*n+j] = 0.0;
for (k=0; k<n; ++k)
ans[i*n+j] += a[i*n+k] * b[k*n+j];
}
return ans;
}
int main() {
float *a, *b, *ans;
a = malloc(sizeof(float)*n*n);
input(&a);
b = malloc(sizeof(float)*n*n);
input(&b);
ans = multiply(a,b);
output(ans);
return 0;
}
If you have trouble understanding the code, please try to brush up your pointer skills. And you can always ask us.
Here is a nice easy way to pass dynamically allocated arrays to a function.
#include <stdio.h>
#include <stdlib.h>
void Function(int ***Array);
int main()
{
int i, j, k, n=10;
//Declare array, and allocate memory using malloc. ( Dimensions will be 10 x 10 x 10)
int ***Array=(int***)malloc(n*sizeof(int**));
for (i=0; i<n; i++)
{
Array[i]=(int**)malloc(n*sizeof(int*));
for (j=0; j<n; j++)
{
Array[i][j]=(int*)malloc(n*sizeof(int));
}
}
//Initialize array in a way that allows us to check it easily (i*j+k).
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
{
for (k=0; k<n; k++)
{
Array[i][j][k]=i*j+k;
}
}
}
//Check array is initialized correctly.
printf("%d\n", Array[4][5][6]);
//Pass array to Function.
Function(Array);
//Check that Function has correctly changed the element.
printf("%d\n", Array[4][5][6]);
return 0;
}
void Function(int ***Array)
{
//Check that Function can access values correctly.
printf("%d\n", Array[4][5][6]);
//Change an element.
Array[4][5][6]=1000;
}
I know this is not specific to your matrix multiplication, but it should demonstrate how to pass the array to the function. It is quite likely that your function would need to know the dimensions of the array, so pass those to it as well... void Function(int ***Array, int n) and call the function as Function(Array, n);
I want to create a program in which I can pass a matrix to a function using pointers.
I initialized and scanned 2 matrices in the void main() and then I tried to pass them to a void add function. I think I am going wrong in the syntax of declaration and calling of the function. I assigned a pointer to the base address of my matrix. (for eg: int *x=a[0][0], *y=b[0][0]). What is the right declaration? How can I specify the dimensions?
Given a 2D array of
T a[N][M];
a pointer to that array would look like
T (*ap)[M];
so your add function prototype should look like
void add(int (*a)[COLS], int (*b)[COLS]) {...}
and be called as
int main(void)
{
int a[ROWS][COLS];
int b[ROWS][COLS];
...
add(a, b);
However, this code highlights several problems. First is that your add function is relying on information not passed via the parameter list, but via a global variable or symbolic constant; namely, the number of rows (the number of columns is explicitly provided in the type of the parameters). This tightly couples the add function to this specific program, and makes it hard to reuse elsewhere. For your purposes this may not be a problem, but in general you only want your functions to communicate with their callers through the parameter list and return values.
The second problem is that as written, your function will only work for matrices of ROWS rows and COLS columns; if you want to add matrices of different sizes within the same program, this approach will not work. Ideally you want an add function that can deal with matrices of different sizes, meaning you need to pass the sizes in as separate parameters. It also means we must change the type of the pointer that we pass in.
One possible solution is to treat your matrices as simple pointers to int and manually compute the offsets instead of using subscripts:
void add (int *a, int *b, size_t rows, size_t cols)
{
size_t i;
for (i = 0; i < rows; i++)
{
size_t j;
for (j = 0; j < cols; j++)
{
*(a + cols * i + j) += *(b + cols * i + j);
}
}
}
and call it like so:
int main(void)
{
int a[ROWS][COLS] = {...};
int b[ROWS][COLS] = {...};
int c[ROWS2][COLS2] = {...};
int d[ROWS2][COLS2] = {...};
...
add(a[0], b[0], ROWS, COLS);
add(c[0], d[0], ROWS2, COLS2);
...
}
The types of a[0] and b[0] are "COLS-element arrays of int"; in this context, they'll both be implicitly converted to "pointer to int". Similarly, c[0] and d[0] are also implicitly converted to int *. The offsets in the add() function work because 2D arrays are contiguous.
EDIT I just realized I was responding to caf's example, not the OP, and caf edited his response to show something very similar to my example. C'est la guerre. I'll leave my example as is just to show a slightly different approach. I also think the verbiage about passing information between functions and callers is valuable.
Something like this should do the trick.
#define COLS 3
#define ROWS 2
/* Store sum of matrix a and b in a */
void add(int a[][COLS], int b[][COLS])
{
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
a[i][j] += b[i][j];
}
int main()
{
int a[ROWS][COLS] = { { 5, 10, 5} , { 6, 4, 2 } };
int b[ROWS][COLS] = { { 2, 3, 4} , { 10, 11, 12 } };
add(a, b);
return 0;
}
EDIT: Unless you want to specify the dimensions at runtime, in which case you have to use a flat array and do the 2D array arithmetic yourself:
/* Store sum of matrix a and b in a */
void add(int rows, int cols, int a[], int b[])
{
int i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
a[i * cols + j] += b[i * cols + j];
}
#caf has shown a good code example.
I'd like to point out that:
I assigned a pointer to the base
address of my matrix. (for eg: int
*x=a[0][0],*y=b[0][0]).
You are not assining a pointer to the base of the matrix. What this does is assign to the value pointed by x and y, the base value in a and b respectively.
The right way would be
int (*x)[] = a;
int (*y)[] = b;
or alternatively
int *x = &a[0][0];
int *y = &b[0][0];