c - 指针、数组和函数

标签 c arrays function pointers

我编写了一个可以旋转 4 x 4 数组的函数,现在我想输出它......但是我收到了一堆警告,但它可以编译并且可以工作,所以我想我只犯了一些“小/正式”错误。

#include <stdio.h>

//-----------------------------------------------------------------------------
///
/// This function prints four 4x4 matrix
///
/// @param m1, m2, m3, m4 input matrix you want to print.
///
/// @return 0
//-----------------------------------------------------------------------------

void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4])
    {
        for(int i = 0; i < 4; i++)
        {
            for(int j = 0; j < 4; j++)
            {
                printf("%c ", m1[i][j]);
            }
            printf(" ");
            for(int j = 0; j < 4; j++)
            {
                printf("%c ", m2[i][j]);
            }
            printf(" ");
            for(int j = 0; j < 4; j++)
            {
                printf("%c ", m3[i][j]);
            }
            printf(" ");
            for(int j = 0; j < 4; j++)
            {
                printf("%c ", m4[i][j]);
            }
            printf("\n");
        }
        printf("\n");
        return 0;
    }

//-----------------------------------------------------------------------------
///
/// This function rotates a 4x4 matrix 
/// (and collects tears from overworked students @2am, because wtf is  )
///
/// @param m, the matrix you want to rotate
///
/// @return m_r the rotated matrix
//-----------------------------------------------------------------------------

char *rotate_matrix(char m[4][4])
{
    static char m_r[4][4];
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            m_r[i][j] = m[3-j][i];
        }
    }
    return *m_r;
}

int main(void)
{
char matrix_t [4][4] = {{ '-', '-', '-', '-' },
                        { '-', 'O', '-', '-' },
                        { 'O', 'O', 'O', '-' },
                        { '-', '-', '-', '-' }
                       };
char matrix_z [4][4] = {{   '-', '-', '-', '-' },
                        { '-', 'O', 'O', '-' },
                        { 'O', 'O', '-', '-' },
                        { '-', '-', '-', '-' }
                       };
char matrix_l [4][4] = {{   '-', '-', '-', '-' },
                        { '-', 'O', '-', '-' },
                        { '-', 'O', '-', '-' },
                        { '-', 'O', 'O', '-' }
                       };
char matrix_i [4][4] = {{   '-', '-', 'O', '-' },
                        { '-', '-', 'O', '-' },
                        { '-', '-', 'O', '-' },
                        { '-', '-', 'O', '-' }
                       };
char (*array)[4][4];

  print_matrix(matrix_t, matrix_z, matrix_l, matrix_i);
  array = rotate_matrix(matrix_t);
  print_matrix(array, matrix_z, matrix_l, matrix_i);
    return 0;
}

这是我得到的错误:
102:9: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]


array = rotate_matrix(matrix_t);

,
103:16: warning: passing argument 1 of ‘print_matrix’ from incompatible pointer type [-Wincompatible-pointer-types]


print_matrix(array, matrix_z, matrix_l, matrix_i);


note: expected ‘char (*)[4]’ but argument is of type ‘char (*)[4][4]’


void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4])

老实说,我没有收到这些错误,因为代码似乎工作,我从来没有超出界限,显然我没有做任何内存违规......

最佳答案

警告是因为这些:

char *            // pointer to char         or to first element of char[]
char (*)[4]       // pointer to char[4]      or to first element of char[][4]
char (*)[4][4]    // pointer to char[4][4]   or to first element of char[][4][4]

是不同的类型。指针不仅表示内存位置,而且(通过其类型)应该如何解释该内存位置。

一个棘手的问题是数组名称(或任何其他计算结果为数组的表达式)衰减为指针。例如,这是完全有效的:
char abc[4] = "abc";    // abc is an array of four characters
char a = *abc;          // a is 'a', the first character of abc

. . .相反,您可以在指针上使用数组表示法(执行指针算术并立即取消引用结果):
char * abc = "abc";     // abc is a pointer (into static memory)
char c = abc[2];        // c is 'c', the third character of abc

所以char *可与 char ()[] 互换, char (*)[4]可与 char ()[][4] 互换, 和 char (*)[4][4]可与 char ()[][4][4] 互换.

更棘手的是,C 并不完全支持将数组作为函数参数传递(尽管如果你真的想要这样,你可以通过将数组包装在一个结构中并传递它来实现相同的效果)。它确实允许您将函数参数声明为具有数组类型,但这实际上是具有指针类型的函数参数的语法糖。所以这三个签名是等价的:
void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4])
void *print_matrix(char m1[][4], char m2[][4], char m3[][4], char m4[][4])
void *print_matrix(char (*m1)[4], char (*m2)[4], char (*m3)[4], char (*m4)[4])

您的代码有效,因为您的各种警告都被取消了:
  • rotate_matrix应该返回 char (*)[4] (指向 char[][4] 的第一行的指针)或 char (*)[4][4] (指向完整 char[4][4] 的指针)。相反,你让它返回 char * ,并为此,您取消引用所需的指针,从而获得(在数组到指针衰减之后)指向矩阵第一行的第一个元素的指针。当然,所有这些指针都指向同一个内存位置,只是类型不同。
  • 用返回类型声明它char (*)[4] ,你可以写char (*rotate_matrix(char m[4][4]))[4] . . .但最好声明一个 row类型,typedef char row[4] ,然后写row * rotate_matrix(char m[4][4]) .在这种情况下,您将返回 m_r最后,它衰减为指向 m_r 第一行的指针.
  • 用返回类型声明它char (*)[4][4] ,同样的事情,只是有额外的[4]的(以及类似 matrix 而不是 row 的名称)。在这种情况下,您将返回 &m_r最后,表示指向整个 m_r 的指针.
  • 恕我直言,上述任何一种方法都很好,尽管您当然必须调整调用站点以匹配。对于这个答案的其余部分,我将假设我们正在做第二个版本,返回类型为 char (*)[4][4] 的版本。 .
  • array有类型 char (*)[4][4] ,这很好。 array = rotate_matrix(matrix_t) 中的代码警告是因为 rotate_matrix 的错误声明.但是返回指针的实际值已经很好了,至少在典型平台上是这样。
  • 也就是说,如果您打算将此类型用于 array , 那么你应该叫它 array_ptr ,因为它是指向您通常的数组类型的指针。
  • 但是你通过 array作为 print_matrix 的参数,它采用 char [4][4] 类型的参数, 意思是 char (*)[4] .您无法转换 char (*)[4][4] (指向 4 行 4 个字符的数组的指针)指向 char (*)[4] (指向 4 个字符的数组的指针)。要解决此问题,您只需取消引用 array , 通过 *array反而。

  • (注意:我不确定上述所有隐式转换是否都能保证有效;指向不同类型对象的指针可能并非在所有平台上都可以相互转换。即使在典型的现代平台上,它们都是可相互转换的,你可能会违反严格的别名规则,这意味着您的编译器最终可能会执行完全破坏您的代码的优化。但它通常会起作用。)

    关于c - 指针、数组和函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40569760/

    相关文章:

    javascript - array.splice = 什么意思?

    javascript - 将函数传递给另一个函数 : Using a variable within the function as the argument to the functions being passed to it

    c - 使用clock()来统计程序执行时间

    c - 如何将 int64 位数据转换为 uint 32 位数据。 C 运算符不得用于 64 位数据

    c++ - 从内存中绘制位图

    c - 仅使用递归计算 c 中的质因数

    java - 在 java 中声明 long[] 数组

    algorithm - 计算二值图像中对象的长度 - 算法

    arrays - MIPS 中的二维数组

    c - 在函数上使用 typedef