二维数组作为形参的参数传递问题

首先,我引用了谭浩强先生编著的《C程序设计》上面的一节原文,它简要介绍了如何将二维数组作为参数传递,原文如下(略有改变,请原谅):

  [原文开始]
  可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明,如:
    void Func(int array[3][10]);
    void Func(int array[][10]);

  二者都是合法而且等价,但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的:
    void Func(int array[][]);
  因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第二维,下面写法是错误的:
    void Func(int array[3][]);

  实参数组维数可以大于形参数组,例如实参(zhihui3409注:应该是形参)数组定义为:
    void Func(int array[3][10]);
  而形参(zhihui3409注:应该是实参)数组定义为:
    int array[5][10];
  这时形参数组只取实参数组的一部分,其余部分不起作用。
  [原文结束]

  大家可以看到,将二维数组当作参数的时候,必须指明所有维数大小或者省略第一维的,但是不能省略第二维或者更高维的大小,这是由编译器原理限制的。
  根据编译原理可知,如果我们省略了第二维或者更高维的大小,编译器将不知道如何正确的寻址。但是我们在编写程序的时候却需要用到各个维数都不固定的二维数组作为参数,这就难办了,编译器不能识别啊,怎么办呢?不要着急,编译器虽然不能识别,但是我们完全可以不把它当作一个二维数组,而是把它当作一个普通的指针,再另外加上两个参数指明各个维数,然后我们为二维数组手工寻址,这样就达到了将二维数组作为函数的参数传递的目的,根据这个思想,我们可以把维数固定的参数变为维数随机的参数,例如:
  void Func(int array[3][10]); 
  void Func(int array[][10]);
  变为:
  void Func( int **array , int RowSize, int LineSize);
  在转变后的函数中,array[i][j]这样的式子是不对的(不信,大家可以试一下),因为编译器不能正确的为它寻址,所以我们需要模仿编译器的行为把array[i][j]手工转变为:
  *((int*)array + LineSize*i + j);即把二维数组当作一维数组来处理,这是比较容易理解的方式。其它方式见下面总结的第二点。

  数组作为形参的问题总结:
  1 一维数组作为函数形参
  数组作为形参时,编译器通常只会检查数组形参关联的实参,检查的项目包括实参是不是指针、指针类型和数组元素的类型是否匹配,但不会检查数组的长度。
   void print( int *a[] )
  void print( int *a[10] )
  void print( int *a )
  以上三个函数的声明是等价的。

  在很多情况下,将数组形参直接定义为指针要比使用数组语法定义方便很多。因为定义为指针后,函数可以借助于指针方便的操作数组元素。
  
数组以非引用类型的传递时,此时数组会自动转换为同类型的指针,即初始化为相应类型实参的副本。调用函数时,函数实际操作的是指针的副本,而不会修改实参指针的值,但是可以通过指针改变数组元素的值。

  2 多维数组的传递
  多维数组的元素本身就是数组。

  对二维数组的处理可以采用将二维数组看作一维或者二维数组来处理,下面两个例子分别采用了这两种方法。第3个例子有点不同,但实际上也是利用了一维数组作中间过渡处理。

  例1 将二维数组当作一维数组来处理:
         //print_array和主函数中的循环printf实现了同样效果
         #include <stdio.h>
         void print_array(int *p,int RowSize,int LineSize)
         {
          int i,j;
          for(i=0 ; i<RowSize ;i++)
          {
           for(j=0 ; j<LineSize ;j++)
            printf("%d ",*(p+i*LineSize+j));
           printf("\n");
          }
         }

         void main() 
         { 
          int i,j,a[3][3]={ {1,0,0} , {0,1,0} , {0,0,1} };
          print_array( (int *)a ,3,3);
          for(i=0;i<3;i++)
          {
           for(j=0;j<3;j++)
            printf("%d ",*(*(a+i)+j));
           printf("\n");
          }
         }

  例2 将二维数组依旧当作二维数组来处理
  下面是一个字符串数组的参数传递程序,实现将字符串数组中的字符串按照从小到大的顺序进行排序:
         //WordSort实现了对5个字符串的排序
         #include "stdio.h"
         #include "stdlib.h"
         #include "string.h"
         void WordSort(char p[][10],int RowSize)
         {
          int n=0,m;
          char temp[10];
          for(n=0;n<RowSize;n++) 
           for(m=n+1;m<RowSize;m++) 
           if( strcmp(p[m],p[n]) < 0 )
           { 
            strcpy(temp,p[n]);
            strcpy(p[n],p[m]);
            strcpy(p[m],temp);
           }
          for(n=0;n<5;++n)
           printf("In subfunction:%s\n",p[n]);
         }

         void main()
         {
          int k=0;
          char word[5][10];
          for(;k<5;++k)
           scanf("%s",&word[k]);
          WordSort(word,5);
          printf("sorted word:\n");
          for(k=0;k<5;k++)
           printf("In main function:%s\n",word[k]);
          system("pause");
         }
  
  例3 用“行指针”传递参数
  运行下面程序:       
         /************************************/
         //二维数组作为形参的参数传递方式之一
         /************************************/
         #include <stdio.h>
         void print_array_1(int (*a)[3], int Row_Size) 
         { 
          int j; 
          for(j=0;j<3*Row_Size;j++)
          {
           printf("%d ",(*a)[j]);
           if(j%3==2) printf("\n");
          }
         }

         void print_array_2(int (*a)[3], int Row_Size)
         { 
          int i,j;
          for(i=0;i<Row_Size;i++) 
          {
           for(j=0;j<3;j++) 
            printf("%d ",*(*(a+i)+j));
           printf("\n");
          }
         }

         void main() 
         { 
          int i,j,value=0; 
          int a[4][3]={0}; 
          for(i=0;i<4;i++) 
           for(j=0;j<3;j++) 
            a[i][j]=value++;

          print_array_1(a,4);
          printf("\n");
          print_array_2(a,4); 
         } 


  这个程序中的两个函数实现了相同的功能:打印数组元素。这种方法可能容易使人迷惑:int (*a)[3] 是什么东西呢?还得看强哥的书(P229-P230),上面这样写道(在本例中):
    *a有3个元素,每个元素为整型。也就是a所指向的对象是有3个整型元素的数组,即a是行指针。
 
  再强调一遍 int (*a)[3] 中括号的作用,如果不明白它的重要性,请仔细对比本文章黄色背景的代码。
  
  补充一点,用这个方法处理字符串数组(字符型二维数组),还是比较方便的:用这样一个例子结束本文:

        //打印数组内字符串(一行)
        #include <stdio.h>
        void print_string(char (*string)[20], int Row_Size)
        {
         int i;
         for(i=0;i<Row_Size;i++)
          printf("%s\n",string+i);
        }

        void main()
        {
         char a[6][20]={"God","bless","you","who","help","themselves"};
         print_string(a,6);
        }
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值