Trying to get difference of 2 2D arrays using pointers - arrays

I am trying to create a subtract function using pointers for 2d array but when I run it I get
expression must have pointer-to-object type but it has type "int"C/C++(142)
Can anybody explain why i'm getting this error and what is a better way around this?
this is my code
Function to read array
int *readMatrix(int *arr)
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
printf("row %d, col %d: ", i + 1, j + 1);
scanf("%d", &arr[i * 4 + j]);
}
}
printf("\n");
return arr;
}
Function to subtract 2 2d arrays
int *subM(int *arrA, int*arrB, int *arrC){
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
&arrC[i][j] = &arrA[i][j] - &arrB[i][j]; //code where I am getting error
}
}
return arrC;
}
Main Function
int main()
{
int arrA[3][4];
int arrB[3][4];
int arrC[3][4];
readMatrix(&arrA[3][4]);
readMatrix(&arrB[3][4]);
subM(&arrA[3][4],&arrB[3][4],&arrC[3][4]);
return 0;
}

I am new to StackOverflow. I'm sorry if I can't express myself that well, but I think I found the solution to your problem.
Let's look at this step-by-step.
When passing an array to a function, you do not need to write the subscripts.
That means that instead of this:
readMatrix(&arrA[3][4]);
Just write this:
readMatrix(arrA);
You can (actually, should) also remove the pointer operator (&) because when only the array name is used, it acts as a pointer automatically.
Let's now take a look at the definition of readMatrix.
int *readMatrix(int *arr)
Using pointers for multi-dimensional arrays is okay, but the compiler would spit out a lot of warnings.
The most standard way is using subscripts in the definition of the function:
int *readMatrixStandard(int arr[3][4])
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
printf("row %d, col %d: ", i + 1, j + 1);
scanf("%d", &arr[i][j]);
}
}
printf("\n");
return arr;
}
The subscripts in subM
For your case, there are two ways to access a multi-dimensional array.
Either tell the compiler that this function takes an multi-dimensional array:
Instead of this:
int *subM(int *arrA, int*arrB, int *arrC)...
Do this:
int *subM(int arrA[3][4], int arrB[3][4], int arrC[3][4])...
The code would then look something like this:
int *subMMultiDimension(int arrA[3][4], int arrB[3][4], int arrC[3][4]){
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
arrC[i][j] = arrA[i][j] - arrB[i][j]; //code where I am getting error
printf("%5d", arrC[i][j]);
}
puts(""); // for newline
}
return arrC;
}
Or use some pointer magic that is exclusive to C/C++ :) (not to be combined with the solution above)
Instead of this:
int *subM(int *arrA, int*arrB, int *arrC){
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
&arrC[i][j] = &arrA[i][j] - &arrB[i][j]; //code where I am getting error
}
}
return arrC;
}
Try this:
int *subM(int *arrA, int *arrB, int *arrC){
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
arrC[i * 4 + j] = arrA[i * 4 + j] - arrB[i * 4 + j]; //code where I am getting error
}
}
return arrC;
}
Use one of the ways, but the first one seems to be more standard because the compiler doesn't throw warnings on the first one.
Return value
You probably see where this is going. I'm just slapping on the code now.
Instead of:
return arr;
return arrC;
I prefer this for less warnings:
return arr[0];
return arrC[0];
The reason is simple. It points pratically to the same address, but it lets the compiler keep the mouth shut.
I think that this was it. The final code would look like this:
#include <stdio.h>
int * readMatrixStandard(int arr[3][4])
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
printf("row %d, col %d: ", i + 1, j + 1);
scanf("%d", &arr[i][j]);
}
}
printf("\n");
return arr[0];
}
int * subMMultiDimension(int arrA[3][4], int arrB[3][4], int arrC[3][4])
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
//printf("row %d, col %d: ", i + 1, j + 1);
arrC[i][j] = arrA[i][j] - arrB[i][j]; //code where I am getting error
printf("%5d", arrC[i][j]);
}
puts(""); // for newline
}
return arrC[0];
}
int main(void) // I recommend to always write void here if you are not using
// an old compiler
{
int arrA[3][4];
int arrB[3][4];
int arrC[3][4];
readMatrixStandard(arrA);
readMatrixStandard(arrB);
subMMultiDimension(arrA,arrB,arrC);
return 0;
}
Compiles nicely without warnings.
These code snippets are just my recommendations. If you want to know the most standard way to do something in C, you will probably have to look it up. A good book is also recommended. For instance, I learnt C with C Primer Plus by Stephen Prata. A great book with a lot of examples and illustrations to help you understand the situation.
Sorry again for my English. Guess there is still a long way to go.
If I missed anything or made a mistake somewhere, please let me know.
Edit: It's Stephen Prata, not Stephan ;)

By definition of the subscript operator [], the expression
A[B]
is equivalent to:
*(A + B)
Therefore,
A[B][C]
is equivalent to:
*( *(A+B) + C )
If you apply this to the line
&arrC[i][j] = &arrA[i][j] - &arrB[i][j];
it is equivalent to:
&*( *(arrC+i) + j ) = &*( *(arrA+i) + j ) - &*( *(arrB+i) + j );
The expression
&*( *(arrC+i) + j ) )
is invalid, for the following reason:
The sub-expression
*(arrC+i)
has type int, because dereferencing an int * yields an int. Therefore, the sub-expression
*(arrC+i) + j
will also evaluate to an int.
After evaluation that sub-expression, you then attempt to dereference that int using the * operator, which is illegal. Only pointer types can be dereferenced.
The sub-expressions
*( *(arrA+i) + j )
and
*( *(arrB+i) + j )
have exactly the same problem. You are also dereferencing an int in both of these expressions.
The actual problem is that you declared the function subM with the following parameters:
int *subM(int *arrA, int *arrB, int *arrC)
In C, arrays are usually passed to functions by passing a (possibly decayed) pointer to the first element of the (outer) array.
The parameter type int * would therefore be correct if you were passing 1D arrays to the function, but it is incorrect for 2D arrays. This is because a pointer to the first element of the outer array of a 2D int array has the type int (*)[4] in your case, i.e. a pointer to a 1D array of 4 int elements. However, you are instead passing a pointer to a single int object (not an array), so you are passing the wrong type of pointer.
Therefore, you should change the parameter types to the following:
int *subM( int (*arrA)[4], int (*arrB)[4], int (*arrC)[4] )
It may be clearer to write this the following way:
int *subM( int arrA[3][4], int arrB[3][4], int arrC[3][4] )
Both lines are equivalent, because arrays decay to pointers when used as function parameters.
Also, you should change the way you are calling the function. You should change the line
subM(&arrA[3][4],&arrB[3][4],&arrC[3][4]);
to:
subM( arrA[3], arrB[3], arrC[3] );
Due to array to pointer decay, this line is equivalent to:
subM( &arrA[3][0], &arrB[3][0], &arrC[3][0] );

Several issues ...
readMatrix uses an int *arr arg [correctly]. But, we want this to be compatible with sumM
sumM uses int * args, but tries to use dereference them using 2D array syntax.
In sumM, using (e.g.) &arr[i][j] is the address of the element and not its value [which is what we want].
In main, we're passing (e.g.) &arr[3][4]. This points past the end of the array, so this is UB (undefined behavior). We want to pass the start address of the array (e.g. arr or &arr[0][0]).
No need to pass back pointers to the resultant arrays because the caller passes in the addresses as args.
Here is the refactored code. It is annotated:
#include <stdio.h>
// Function to read array
#if 0
int *
readMatrix(int *arr)
#else
void
readMatrix(int arr[3][4])
#endif
{
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
printf("row %d, col %d: ", i + 1, j + 1);
#if 0
scanf("%d", &arr[i * 4 + j]);
#else
scanf("%d", &arr[i][j]);
#endif
}
}
printf("\n");
#if 0
return arr;
#endif
}
// Function to subtract 2 2d arrays
#if 0
int *
subM(int *arrA, int *arrB, int *arrC)
#else
void
subM(int arrA[3][4], int arrB[3][4], int arrC[3][4])
#endif
{
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
// printf("row %d, col %d: ", i + 1, j + 1);
// NOTE/BUG: we want to use the _values_ and _not_ the _addresses_ of the
// array elements
#if 0
&arrC[i][j] = &arrA[i][j] - &arrB[i][j];
#else
arrC[i][j] = arrA[i][j] - arrB[i][j];
#endif
}
}
// NOTE/BUG: since caller passed in the array, it knows where it is
#if 0
return arrC;
#endif
}
// Main Function
int
main(void)
{
int arrA[3][4];
int arrB[3][4];
int arrC[3][4];
// NOTE/BUG: doing (e.g.) &arrA[3][4] points past the _end_ of the 2D array
// and, so, is UB (undefined behavior) -- we want to pass the start address
#if 0
readMatrix(&arrA[3][4]);
readMatrix(&arrB[3][4]);
subM(&arrA[3][4], &arrB[3][4], &arrC[3][4]);
#else
readMatrix(arrA);
readMatrix(arrB);
subM(arrA, arrB, arrC);
#endif
return 0;
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k

Related

C - Having trouble with passing NxN array as an argument. I keep getting warning: incompatible pointer type [duplicate]

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 13 days ago.
I wrote this program that is supposed to sort NxN array. It gets compiled but doesn't work because the pointer type is incompatible.
I just need help with the pointers as argument. I get incompatible pointer type warning for both functions swap and dblArraySort. Any idea why is that ?
thanks in advance !
#include <stdio.h>
#include <stdlib.h>
void
swap(int **a, int **b)
{
int temp;
temp = **a;
**a = **b;
**b = temp;
}
void
dblArraySort(int **dblArray, int arrLen)
{
int chkIndex;
int i, j, k;
for (i = 0; i < arrLen; i++) {
if ((i + 1) % 2 == 0) {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex < dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
} else {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex >= dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
}
}
}
int
main()
{
unsigned int arrayLength;
printf("Provide array size: \n");
scanf("%d", &arrayLength);
int doubleArray[arrayLength][arrayLength];
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
scanf("%d", &doubleArray[i][j]);
}
}
dblArraySort(doubleArray, arrayLength);
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
printf("%d ", doubleArray[i][j]);
}
printf("\n");
}
return 0;
}
I tried the code mentioned above
Arrays in C can be confusing. The thing you need to worry about is element type.
The element type of int ** dblArray is int *. In other words, dblArray is an array of int *s.
However, the element type of int doubleArray[arrayLength][arrayLength] is int row_type[arrayLength]. That is not an int *, that is an array, which is a totally different thing.
Moreover, when you use an array⟶pointer conversion, as happens when you say:
dblArraySort(doubleArray, arrayLength); // doubleArray is converted to a pointer
You get a pointer to the array, which in this case is a pointer to the innermost element type, an int — which is also not an int *.
tl;dr: You are trying to pass an array of array of int to a function taking an array of pointer to int. That won’t work.
I would like to comment on your variable naming as well. When you say “double” or “dbl”, as in doubleArray and dblArray the very first thing people will think is that you are handling a linear array of type double, which is also not what the array is.
You have there a two-dimensional array. Not a “double” array. Common naming for such thing would be array2D or matrix.
To make it work you need either C11, which allows you to pass a VLA as:
void sort_array2D( size_t rows, size_t columns, int array[rows][columns] )
{
...
int value = array[i][j];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( Array_Length, Array_Length, array2D );
Or you need to simply assume you must compute the index manually. A little function will help:
size_t index2D( size_t rows, size_t columns, size_t r, size_t c )
{
(void)rows; // (quiet the compiler about not using this argument)
return r * columns + c;
}
Then you can write your function as:
void sort_array2D( int * array, size_t rows, size_t columns )
{
...
int value = array[index2D( rows, columns, i, j )];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( (int *)array2D, Array_Length, Array_Length );
I haven’t bothered to analyze your sort function. It doesn’t look right to me, but honestly, I’ve barely glanced at it. Calling a value from the array chkIndex looks fishy, since the values of the array are not indices per se, at least not in the context of sorting them.
Remember, when messing with arrays in C you need to keep strict care to not mix up the type of the elements. (Or the types of things in general, whether syntactic or conceptual.)

C allocate 'array pointer' inside a function

Related to dynamic allocation inside a function, most questions & answers are based on double pointers.
But I was recommended to avoid using double pointer unless I have to, so I want to allocate a 'array pointer' (not 'array of pointer') and hide it inside a function.
int (*arr1d) = calloc(dim1, sizeof(*arr1d));
int (*arr2d)[dim2] = calloc(dim1, sizeof(*arr2d));
Since the above lines are the typical dynamic-allocation of pointer of array, I tried the following.
#include <stdio.h>
#include <stdlib.h>
int allocateArray1D(int n, int **arr) {
*arr = calloc(n, sizeof(*arr));
for (int i = 0; i < n; i++) {
(*arr)[i] = i;
}
return 0;
}
int allocateArray2D(int nx, int ny, int *(*arr)[ny]) {
*arr[ny] = calloc(nx, sizeof(*arr));
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return 0;
}
int main() {
int nx = 3;
int ny = 2;
int *arr1d = NULL; // (1)
allocateArray1D(nx, &arr1d);
int(*arr2d)[ny] = NULL; // (2)
allocateArray2D(nx, ny, &arr2d);
for (int i = 0; i < nx; i++) {
printf("arr1d[%d] = %d \n", i, arr1d[i]);
}
printf("\n");
printf("arr2d \n");
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
printf(" %d ", arr2d[i][j]);
}
printf("\n");
}
return 0;
}
And the error message already comes during the compilation.
03.c(32): warning #167: argument of type "int (**)[ny]" is incompatible with parameter of type "int *(*)[*]"
allocateArray2D(nx, ny, &arr2d);
^
It is evident from the error message that it has been messed up with the argument types (that I wrote as int *(*arr)[ny]) but what should I have to put there? I tried some variants like int *((*arr)[ny]), but didn't work).
And if I remove the 2D parts, then the code well compiles, and run as expected. But I wonder if this is the right practice, at least for 1D case since there are many examples where the code behaves as expected, but in fact there were wrong or un-standard lines.
Also, the above code is not satisfactory in the first place. I want to even remove the lines in main() that I marked as (1) and (2).
So in the end I want a code something like this, but all with the 'array pointers'.
int **arr2d;
allocateArray2D(nx, ny, arr2d);
How could this be done?
You need to pass the array pointer by reference (not pass an array pointer to an array of int*):
int *(*arr)[ny] -> int (**arr)[ny]
The function becomes:
int allocateArray2D(int nx, int ny, int (**arr)[ny]) {
*arr = calloc(nx, sizeof(int[ny])); // or sizeof(**arr)
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return 0;
}
For details, check out Correctly allocating multi-dimensional arrays
Best practices with malloc family is to always check if allocation succeeded and always free() at the end of the program.
As a micro-optimization, I'd rather recommend to use *arr = malloc( sizeof(int[nx][ny]) );, since calloc just creates pointless overhead bloat in the form of zero initialization. There's no use of it here since every item is assigned explicitly anyway.
Wrong parameter type
Strange allocation
Wrong size type
I would return the array as void * too (at least to check if allocation did not fail).
void *allocateArray2D(size_t nx, size_t ny, int (**arr)[ny]) {
//*arr = calloc(nx, sizeof(**arr)); calloc is not needed here as you assign values to the array
*arr = malloc(nx * sizeof(**arr));
for (size_t i = 0; i < nx; i++) {
for (size_t j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return *arr;
}

Dynamic Allocation of 2d Array, pointers. filling, printing

i am trying to dynamically allocate and manipulate a 2D array, using pointers. I am new to pointers, so when i run this program it gives "Segmentation fault". What is the problem here ?
I used also (grid + i*c + j) with one asterisk , still doesn't work
#include <stdio.h>
#include <stdlib.h>
float* DynamicAll(int row,int col){
float *arr = (float *)malloc(row*col*sizeof(float));
return arr;
}
void fillIn(float **grid, int r, int c){
for(int i = 0 ; i < r ; i++){
for(int j = 0 ; j < c; i++){
**(grid + i*c + j) = i+j;
}
}
}
void print(float **grid, int r, int c){
for(int i = 0 ; i < r ; i++){
for(int j = 0 ; j < c; i++){
printf("%f ", **(grid + i*c + j));
}
}
}
int main() {
int row = 3, col = 3;
float *arr;
arr = DynamicAll(row,col);
fillIn(&arr,row,col);
print(&arr,row,col);
free(arr);
return 0;
}
The problem is the double-pointer (pointer to pointer) that you pass to and us in the fillIn and print functions. That's wrong, totally wrong.
Or well, it could be used, but then you need to dereference the pointer grid in those function first, before you do pointer arithmetic on it.
But I don't see any reason to do that, so just pass the pointer arr as-is to the function (and modify it accordingly:
// Note only single pointer here
// v
void fillIn(float *grid, int r, int c){
for(int i = 0 ; i < r ; i++){
for(int j = 0 ; j < c; i++){
// Only single dereference here
*(grid + i*c + j) = i+j;
}
}
}
...
// Not using the address-of operator here
fillIn(arr, row, col);
If, for some unknown reason, you insist on keeping the pointer to pointer then you must dereference the pointer first:
*(*grid + i*c + j) = i+j;
Notice the placement of the two asterisks, and how one is used to dereference the pointer grid and the other dereference the calculated pointer.
Also note that for any pointer or array p and index i, the expression *(p + i) is exactly equal to p[i]. That means the expression is equal to:
(*grid)[i*c + j] = i+j;
Now it might also be easier to see what was wrong with your original expression.
Just for clarity, your original expression was equal to this:
grid[i*c + j][0] = i+j;

2D arrays using arrays of pointers or pointers to pointers in C?

I'm writing a C for which I need to create a 2D array. I've found a solution to my problem using double pointers (pointers to pointers) in the following way:
#include <stdio.h>
#include <stdlib.h>
int d = 3;
#define DIM_MAX 9
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int **array = malloc(d*sizeof(int *));
for(int count = 0; count < d; count++)
{
array[count] = malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
The code above works pretty well (it seems), but I've read in the web that using pointer to pointer is not the correct way to create 2D arrays. So I've come up with the following code, which also works:
#include <stdio.h>
#include <stdlib.h>
#define DIM_MAX 9
int d = 3;
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int *array[DIM_MAX] = {0};
for(int count = 0; count < d; count++)
{
array[count] = (int *)malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
What is the difference in using any of the two ways above to write this code?
[Not an answer, but an alternative approach to achieve the desired result, namely defining a user-defined 2D array.]
Assuming the compiler in use supports VLAs you could do this:
#include <stddef.h> /* for size_t */
void init_a(size_t x, size_t y, int a[x][y]); /* Order matters here!
1st give the dimensions, then the array. */
{
for (size_t i = 0; i < x; ++i)
{
for (size_t j = 0; j < y; ++j)
{
a[i][j] = (int) (i * j); /* or whatever values you need ... */
}
}
}
int main(void)
{
size_t x, y;
/* Read in x and y from where ever ... */
{
int a[x][y]; /* Define array of user specified size. */
init_a(x, y, a); /* "Initialise" the array's elements. */
...
}
}
It is actually pretty simple. All you have to do is this:
int i[][];
You are overthinking it. Same as a normal array, but has two indexes.
Let's say you want to create a "table" of 4 x 4. You will need to malloc space for 4 pointers, first. Each of those index points will contain a pointer which references the location in memory where your [sub] array begins (in this case, let's say the first pointer points to the location in memory where your first of four arrays is). Now this array needs to be malloc for 4 "spaces" (in this case, let's assume of type INT). (so array[0] = the first array) If you wanted to set the values 1, 2, 3, 4 within that array, you'd be specifying array[0][0], array[0][1], array[0][2], array[0][3]. This would then be repeated for the other 3 arrays that create this table.
Hope this helps!

int** vs int[const][const] differences

I was writing a code the other day and I found it rather strange, that int** and int[][] does not behave the same way. Can anyone point out the differences between them? Below is my sample code, which fails with a segmentation fault, if I pass constant size 2d array, while it does work fine when I pass a dinamically allocated 2d array.
I am confused mainly because ant int[] array works the same as int*.
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int **t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[0][j] < t[0][j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k][j];
t[k][j] = t[k][j+1];
t[k][j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
So based on the below answers I realize, that a multidimensional array is stored continuously in a row major order. After some modification, the below code works:
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int *t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[j] < t[j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k*m + j];
t[k*m + j] = t[k*m + j+1];
t[k*m + j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
My new question is this: How to modify the code, so that the procedure works with int[][] and int** also?
Realize that int **t makes t a pointer to a pointer, while int t[3][6] makes t an array of an array. In most cases, when an array is used in an expression, it will become the value of the address of its first member. So, for int t[3][6], when t is passed to a function, the function will actually be getting the value of &t[0], which has type pointer to an array (in this case, int (*)[6]).
The type of what is being pointed at is important for how the pointer behaves when indexed. When a pointer to an object is incremented by 5, it points to the 5th object following the current object. Thus, for int **t, t + 5 will point to the 5th pointer, while for int (*t)[M], t + 5 will point to the 5th array. That is, the result of t + 5 is the same as the result of &t[5].
In your case, you have implemented void sort_by_first_row(int **t, int n, int m), but you are passing it an incompatible pointer. That is, the type of &t[0] (which is what t will become in main) is not the same as what the function wants, a int **t. Thus, when the sorting function starts to use that address, it will think its indexing into pointers, when the underlying structure is an array of arrays.
int** is quite different from int[][]. int** is simply a pointer to a pointer and would appear like the following:
in reality, you can access the entire multidimensional array with simply int* pointing to the first element, and doing simple math from that.
Here is the result of the separate allocations (in your commented code):
However when you allocate a multidimensional array, all of the memory is contiguous, and therefore easy to do simple math to reach the desired element.
int t[3][6];
int *t = (int*) malloc((3 * 6) * sizeof(int)); // <-- similarly
This will result in a contiguous chunk of memory for all elements.
You certainly can use the separate allocations, however you will need to walk the memory differently.
Hope this helps.
int t[3][6] is very nearly the same thing as int t[18]. A single contiguous block of 18 integers is allocated in both cases. The variable t provides the address of the start of this block of integers, just like the one-dimensional case.
Contrast this with the case you have marked as "working", where t gives you the address of a block of 3 pointers, each of which points to a block of memory with 6 integers. It's a totally different animal.
The difference between t[3][6] and t[18] is that the compiler remembers the size of each dimension of the array, and automatically converts 2D indices into 1D offsets. For example, the compiler automatically converts t[1][2] into *(t + 1*6 + 2) (equivalent to t[8] if it were declared as a one-dimensional array).
When you pass a multi-dimensional array to a function, there are two ways to handle it. The first is to declare the function argument as an array with known dimension sizes. The second is to treat your array like a 1D array.
If you are going to declare the size of your array, you would declare your function like this:
void sort_by_first_row(int t[][6], int n)
or this
void sort_by_first_row(int t[3][6])
You either have to declare all array dimension sizes, or you can leave out the first size. In both cases, you access elements of t using t[i][j]; you've given the compiler enough information to do the offset math that converts from 2D notation to a 1D index offset.
If you treat it as a 1D array, you have to pass the array dimensions and then do the offset math yourself.
Here's a full working example, where f and f2 both generate the same output:
void f(int* t, int m, int n)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
std::cout << t[i * n + j] << " ";
std::cout << std::endl;
}
void f2(int t[][6], int m)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < 6; j++)
std::cout << t[i][j] << " ";
std::cout << std::endl;
}
int main()
{
int t[3][6];
int val = 1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 6; j++)
{
t[i][j] = val;
val++;
}
}
f(&(t[0][0]), 3, 6);
f2(t, 3);
return 0;
}
One thing to note is the hack-ish way I had to pass t to f. It's been a while since I wrote in C/C++, but I remember being able to pass t directly. Maybe somebody can fill me in on why my current compiler won't let me.
A int ** is a pointer to a pointer to an int, and can be a pointer to an array of pointers to arrays of ints. A int [][] is a 2-dimensional array of ints. A two-dimensional array is exactly the same as a one-dimensional array in C in one respect: It is fundamentally a pointer to the first object. The only difference is the accessing, a two-dimensional array is accessed with two different strides simultaneously.
Long story short, a int[][] is closer to an int* than an int**.

Resources