传递多个维阵列C中的函数 [英] Pass multiple-dimensional array to a function in C

查看:136
本文介绍了传递多个维阵列C中的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的功能:

 无效MYFUNC(INT **改编,诠释N){
  INT I,J;
  对于(i = 0; I< N ++我){
    为(J = 0; J< N ++ j)条{
      的printf(%d个,*(ARR + I * N + J)); //用逗号打印号码
    }
    的printf(\\ n); //只是断裂线
  }
}

在其他功能我有一个二维数组是这样的:

  INT的main(){
  INT seqs [8] [8] = {
    {0,32,36,52,48,16,20,4},
    {0,16,20,52,48,32,36,4},
    {0,32,36,44,40,8,12,4},
    {0,8,12,44,40,32,36,4},
    {0,32,36,38,34,2,6,4},
    {0,2,6,38,34,32,36,4},
    {0,32,36,37,33,1,5,4},
    {0,1,5,37,33,32,36,4}
  };  //调用到MYFUNC
  MYFUNC(seqs,8); //这是观念
}

但是编译器把我这个错误:

  lab.c:在函数'主':
lab.c:75:5:警告:传递从兼容的指针类型'MYFUNC'的参数1 [默认启用]
lab.c:4:6:注:应为** INT,但参数的类型为INT(*)[8]

什么是传递这个数组以正确的方式( seqs )的功能( MYFUNC )?


解决方案

在C99或C11,你会做这样的:

 无效MYFUNC(INT N,INT ARR [N] [N])
{
    的for(int i = 0; I< N ++ I)
    {
        对于(INT J = 0; J< N ++ j)条
            的printf(%d个,编曲[I] [J]);
        的printf(\\ n);
    }
}

请注意,这个大小precedes,不遵循,数组。此功能将与正常工作:

  INT主要(无效)
{
    INT seqs [8] [8] =
    {
        {0,32,36,52,48,16,20,4},
        {0,16,20,52,48,32,36,4},
        {0,32,36,44,40,8,12,4},
        {0,8,12,44,40,32,36,4},
        {0,32,36,38,34,2,6,4},
        {0,2,6,38,34,32,36,4},
        {0,32,36,37,33,1,5,4},
        {0,1,5,37,33,32,36,4},
    };
    MYFUNC(8,seqs);    INT MATRIX3X3 [3] [3] = {{1,2,3},{2,4,6},{3,6,9}};
    MYFUNC(3 MATRIX3X3);
}


有人问我:


  

您例子并看起来好多了确实,但它明确定义?为 N 确实保证前 INT ARR进行评估[N] [N] ?不会的功能参数计算顺序是不确定的行为?


旧标准(ISO / IEC 9899:1999)说,在§6.7.5.2*的数组声明的*:


  

¶5的如果大小是前pression不是整型常量前pression:如果在它发生
  声明在函数原型范围,如果它是由替换* 将被处理;除此以外,
  每次评价时,应当有一个大于零的值。每个实例的大小
  可变长度数组类型的在其寿命期间不会改变。凡大小
  前pression是的sizeof 运算符的操作数的一部分,并且不断变化的价值
  大小当然pression不会影响操作的结果,它是未指定是否
  规模前pression进行了评价。


和它提供了一个例子(这是不规范的文本,因为它是一个例子,但强烈表示期望是什么):


  

例4动态可变(VM)类型的所有声明都必须在任块范围或
  函数原型范围。与静态声明数组对象的extern 存储类说明
  不能有一个可变长度数组(VLA)型。然而,随着静态声明的对象存储类
  符可以具有一个虚拟机的类型(即,一个指向VLA类型)。最后,所有标识与申报
  VM类型必须是普通的标识符,并且不能,因此,是结构或联合的成员。

 的extern INT N;
int类型的[N]; //无效:文件范围VLA
EXTERN INT(* P2)[N]; //无效:文件范围内的VM
INT B〔100〕; //有效:文件范围内,但不是VM
无效fvla(INT男,INT C [M] [M]); //有效:VLA与原型范围
无效fvla(INT男,INT C [M] [M]。)//有效:调整自动指向VLA
{
    的typedef诠释VLA [M] [M]; //有效:块范围的typedef VLA
    结构标记{
        INT(* Y)[N]; //无效:Y不是普通的标识符
        诠释Z [N]; //无效:Z不是普通的标识符
    };
    INT D [M]; //有效:汽车VLA
    静态INT E [M]; //无效:静态块范围VLA
    EXTERN INT F [M]; //无效:F有挂钩,VLA
    INT(* S)[M]。 //有效:自动指向VLA
    EXTERN INT(* R)[M]。 //无效:r的联动点VLA
    静态INT(* Q)[M] =和B; //有效:q是一个静态块指针VLA
}


有显示动态可变功能参数的其他例子。

此外,在§6.9.10函数定义,它说:


  

¶10进入时的功能,每一个可变地修改的参数的大小前pressions是
  评估和每个参数的前pression的值转换为的类型
  相应的参数仿佛被分配。 (阵列前pressions和功能
  代号为参数转换为调用之前的指针。)


I have a function like this:

void myfunc(int** arr, int n) {
  int i, j;
  for(i=0; i<n; ++i) {
    for(j=0; j<n; ++j) {
      printf("%d,", *(arr + i*n + j) );  // Print numbers with commas
    }
    printf("\n");                        // Just breakline
  }
}

in other function I have an two-dimensional array like this:

int main() {
  int seqs[8][8] = {
    {0, 32, 36, 52, 48, 16, 20, 4},
    {0, 16, 20, 52, 48, 32, 36, 4},
    {0, 32, 36, 44, 40, 8, 12, 4},
    {0, 8, 12, 44, 40, 32, 36, 4},
    {0, 32, 36, 38, 34, 2, 6, 4},
    {0, 2, 6, 38, 34, 32, 36, 4},
    {0, 32, 36, 37, 33, 1, 5, 4},
    {0, 1, 5, 37, 33, 32, 36, 4}
  };

  // Call to myfunc
  myfunc(seqs, 8);  // This is the idea
}

But compiler throw me this error:

lab.c: In function 'main':
lab.c:75:5: warning: passing argument 1 of 'myfunc' from incompatible pointer type [enabled by default]
lab.c:4:6: note: expected 'int **' but argument is of type 'int (*)[8]'

What is the right way to pass this array (seqs) to function (myfunc)?

解决方案

In C99 or C11, you would do it like this:

void myfunc(int n, int arr[n][n])
{
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < n; ++j)
            printf("%d,", arr[i][j]);
        printf("\n");
    }
}

Note that the size precedes, not follows, the array. This function will work correctly with:

int main(void)
{
    int seqs[8][8] =
    {
        { 0, 32, 36, 52, 48, 16, 20, 4 },
        { 0, 16, 20, 52, 48, 32, 36, 4 },
        { 0, 32, 36, 44, 40,  8, 12, 4 },
        { 0,  8, 12, 44, 40, 32, 36, 4 },
        { 0, 32, 36, 38, 34,  2,  6, 4 },
        { 0,  2,  6, 38, 34, 32, 36, 4 },
        { 0, 32, 36, 37, 33,  1,  5, 4 },
        { 0,  1,  5, 37, 33, 32, 36, 4 },
    };
    myfunc(8, seqs);

    int matrix3x3[3][3] = { { 1, 2, 3 }, { 2, 4, 6 }, { 3, 6, 9 } };
    myfunc(3, matrix3x3);
}


I was asked:

Your example does look much better indeed, but is it well-defined? Is n really guaranteed to be evaluated before int arr[n][n]? Wouldn't the order of evaluation of function parameters be unspecified behavior?

The old standard (ISO/IEC 9899:1999) says in §6.7.5.2*Array declarators*:

¶5 If the size is an expression that is not an integer constant expression: if it occurs in a declaration at function prototype scope, it is treated as if it were replaced by *; otherwise, each time it is evaluated it shall have a value greater than zero. The size of each instance of a variable length array type does not change during its lifetime. Where a size expression is part of the operand of a sizeof operator and changing the value of the size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated.

And it gives an example (it is non-normative text because it is an example, but strongly indicative of what is expected):

EXAMPLE 4 All declarations of variably modified (VM) types have to be at either block scope or function prototype scope. Array objects declared with the static or extern storage-class specifier cannot have a variable length array (VLA) type. However, an object declared with the static storage class specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.

extern int n;
int A[n];                       // invalid: file scope VLA
extern int (*p2)[n];            // invalid: file scope VM
int B[100];                     // valid: file scope but not VM
void fvla(int m, int C[m][m]);  // valid: VLA with prototype scope
void fvla(int m, int C[m][m])   // valid: adjusted to auto pointer to VLA
{
    typedef int VLA[m][m];      // valid: block scope typedef VLA
    struct tag {
        int (*y)[n];            // invalid: y not ordinary identifier
        int z[n];               // invalid: z not ordinary identifier
    };
    int D[m];                   // valid: auto VLA
    static int E[m];            // invalid: static block scope VLA
    extern int F[m];            // invalid: F has linkage and is VLA
    int (*s)[m];                // valid: auto pointer to VLA
    extern int (*r)[m];         // invalid: r has linkage and points to VLA
    static int (*q)[m] = &B;    // valid: q is a static block pointer to VLA
}

There are other examples showing variably modified function parameters.

Also, in §6.9.10 Function definitions, it says:

¶10 On entry to the function, the size expressions of each variably modified parameter are evaluated and the value of each argument expression is converted to the type of the corresponding parameter as if by assignment. (Array expressions and function designators as arguments were converted to pointers before the call.)

这篇关于传递多个维阵列C中的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆