Home > front end >  Trying to get difference of 2 2D arrays using pointers
Trying to get difference of 2 2D arrays using pointers

Time:11-05

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;
}

CodePudding user response:

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 run this down step-by-step.

  1. 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;
}
  1. 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("]", 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.

  1. 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("]", 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 Stephan 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.

CodePudding user response:

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])

Also, you should also 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]);

CodePudding user response:

Several issues ...

  1. readMatrix uses an int *arr arg [correctly]. But, we want this to be compatible with sumM
  2. sumM uses int * args, but tries to use dereference them using 2D array syntax.
  3. In sumM, using (e.g.) &arr[i][j] is the address of the element and not its value [which is what we want].
  4. 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]).
  5. 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