C语言 尝试使用指针获取2个2D数组的差值

5anewei6  于 2023-01-16  发布在  其他
关注(0)|答案(3)|浏览(159)

我试图创建一个减法函数使用指针为二维数组,但当我运行它,我得到
表达式必须具有指向对象的指针类型,但它具有类型"int" C/C ++(142)
有人能解释一下为什么我会得到这个错误,还有什么更好的方法吗?
这是我的密码
读取数组的函数

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

用于减去2个2D阵列的函数

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

主要功能

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

umuewwlo1#

我是StackOverflow的新手。如果我不能很好地表达自己,我很抱歉,但是我想我找到了解决你问题的方法。
让我们一步一步地看一下。
1.当将数组传递给函数时,不需要编写下标。
这意味着,与此相反:

readMatrix(&arrA[3][4]);

就写这个:

readMatrix(arrA);

您还可以(实际上应该)删除指针运算符(&),因为当只使用数组名时,它会自动充当指针。
现在我们来看一下readMatrix的定义。

int *readMatrix(int *arr)

对多维数组使用指针是可以的,但是编译器会发出很多警告。
最标准的方法是在函数定义中使用下标:

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. subM中的下标
    对于您的情况,有两种方法可以访问多维数组。
    或者告诉编译器这个函数接受多维数组:
    而不是这个:
int *subM(int *arrA, int*arrB, int *arrC)...

请执行以下操作:

int *subM(int arrA[3][4], int arrB[3][4], int arrC[3][4])...

代码将如下所示:

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;
}
    • 或者**使用一些C/C ++专用的指针魔术:)(不要与上面的解决方案结合使用)

而不是这个:

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

试试这个:

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

使用其中一种方法,但第一种方法似乎更标准,因为编译器不会在第一种方法上抛出警告。
1.返回值
你可能知道接下来会发生什么。我只是在写代码。
取代:

return arr;
return arrC;

我更喜欢这个警告较少:

return arr[0];
return arrC[0];

原因很简单,它实际上指向同一个地址,但却让编译器守口如瓶。
我想就是这样了。最后的代码应该是这样的:

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

编译良好,无警告。
这些代码片段只是我的推荐。如果你想知道用C做某事的最标准方法,你可能要去查一下。一本好书也是推荐的。例如,我用Stephen Prata的C Primer Plus学习了C。一本很棒的书,有很多例子和插图来帮助你理解情况。
再次为我的英语道歉。我想还有很长的路要走。
如果我遗漏了什么或在什么地方犯了错误,请让我知道。
编辑:是斯蒂芬·普拉塔,不是斯蒂芬;)

vbopmzt1

vbopmzt12#

根据下标运算符[]的定义,表达式

A[B]

相当于:

*(A + B)

因此,

A[B][C]

相当于:

*( *(A+B) + C )

如果你把这个应用到

&arrC[i][j] =  &arrA[i][j] - &arrB[i][j];

它相当于:

&*( *(arrC+i) + j ) = &*( *(arrA+i) + j ) - &*( *(arrB+i) + j );

该表达式

&*( *(arrC+i) + j ) )

无效,原因如下:
该子表达式

*(arrC+i)

的类型为int,因为解引用int *会产生int

*(arrC+i) + j

也将计算为int
在计算完该子表达式后,尝试使用非法的*运算符取消对int的引用。只能取消对指针类型的引用。
子表达式

*( *(arrA+i) + j )

以及

*( *(arrB+i) + j )

有完全相同的问题,在这两个表达式中也都是在解引用int
实际问题是您使用以下参数声明了函数subM

int *subM(int *arrA, int *arrB, int *arrC)

在C中,数组通常通过传递一个指向(外部)数组第一个元素的指针(可能是decayed)传递给函数。
因此,如果您向函数传递的是一维数组,则参数类型int *是正确的,但对于二维数组则不正确。这是因为指向二维int数组的外部数组的第一个元素的指针在您的情况下具有int (*)[4]类型,即指向4个int元素的一维数组的指针。但是,您传递的是指向单个int对象(不是数组)的指针,因此您传递的指针类型错误。
因此,应将参数类型更改为以下类型:

int *subM( int (*arrA)[4], int (*arrB)[4], int (*arrC)[4] )

这样写可能更清楚一些:

int *subM( int arrA[3][4], int arrB[3][4], int arrC[3][4] )

这两行是等效的,因为数组decay在用作函数参数时指向指针。
同样,你应该改变你调用函数的方式。你应该改变

subM(&arrA[3][4],&arrB[3][4],&arrC[3][4]);

致:

subM( arrA[3], arrB[3], arrC[3] );

由于array to pointer decay,该行等效于:

subM( &arrA[3][0], &arrB[3][0], &arrC[3][0] );
8fq7wneg

8fq7wneg3#

几个问题...

  1. readMatrix使用int *arr参数[正确]。但是,我们希望它与sumM兼容
  2. sumM使用int *参数,但尝试使用二维数组语法取消引用它们。
    1.在sumM中,使用(例如)&arr[i][j]是元素的 * 地址 *,而不是 * 它的 * 值 * [这是我们想要的]。
    1.在main中,我们传递(例如)&arr[3][4]。它指向数组的 end,所以这是UB(未定义行为)。我们希望传递数组的起始地址(例如arr&arr[0][0])。
    1.不需要将指针传递回结果数组,因为调用方将地址作为参数传递。
    下面是重构后的代码,它带有注解:
#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;
}

在上面的代码中,我使用了cpp条件来表示旧代码和新代码:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

注意:通过unifdef -k运行文件可以清除此问题

相关问题