[4] 数组和指针的前世今生 - 指针篇

给函数传递1个一维数组

在C语言中,任何一维数组传递给函数都会转化为指针,所以需要约定来提示数组的长度,一般有两个基本的方法:
1、增加一个额外的参数,表示元素的数目(argc就是这个作用)
2、赋予数组最后一个元素一个特殊的值,提示它是数组的尾部(字符串的’\0’),这个特殊值不会作为正常的元素值出现在数组中

二维数组的情况更加复杂,数组会被改写成指向数组第一行的指针。这个时候需要两个约定,其中一个用来提示每行的结束,另一个用于提示所有行的结束。
1、提示单行结束可以使用一维数组的两种方法,提示所有行结束也可以这样。
2、我们所接受的是一个指向数组第一个元素的指针,每次对指针执行++操作,指针就指向数组下一行的起始位置,但是怎么知道到达了最后一行呢?可以增加一个额外的行,行内所有元素都是不可能正常出现在数组中的元素,每次指针++时,检查是否到达了最后一行。定义中方法是,传递一个额外的参数,提示数组的行数。

用指针向函数传递多维数组

  • 上面说的方法,虽然笨拙,可以解决标记数组范围的难题。
  • 在C语言中,没发给函数传递一个普遍的多维数组,也就是说每个函数只能接收一个固定了长度的数组参数,像下面这样:
void func(int a[][3][5]);(这样写函数内部无法知道最后一行,需要额外的参数或者一个约定)
int b1[10][3][5];//OK
int b2[500][3][5];//OK
int b3[1][3][4];//ERROR
...//ERROR
  • 必须给编译器提供除了最左边一维,其他所有维的长度
  • 解决这个问题,最好的办法是放弃传递二维数组[x][y],改为传递一维数组[x+1],它的元素类型是指向[y]的指针,最后一个位置存放NULL指针提示数组的结束

二维或者更多维的数组无法在C语言中用做一般形式的参数,比如[][][]这种,这样就无法写出通用的代码,有如下方法解决这个问题:

方法1

void my_func(int my_array[10][20]);
简单易懂,但是是特殊化的函数,无法作为通用函数。

方法2

void my_func(int my_array[][20]);
void my_func(int (*my_array)[20]);
依旧是特殊化的函数,需要额外的参数判断最后一行

方法3

void my_func(char **my_array);

  • 这个做法要有效,必须先把二维数组改写为Iliffe向量的形式,即先要把a[][]改写为*a[]的形式
  • Iliffe这种结构的美感在于,它允许任意的字符串指针数组传递给函数,但是必须是指针数组,而且必须是指向字符串的指针数组。因为字符串和指针都有一个显式的越界值\0和NULL,可以作为结束标记。
  • 其他类型则不能使用这个方法,因为没有内置的方法知道它达到了某一维的结束位置
  • 即使是char**,还是会传递argc参数,记录字符串的数量,因为一般来说,不会给char**最后填充一行NULL指针

方法4

void my_func(/* 自己的下标方式 */);
转换多维数组为一维数组,传递一维数组,下标方式自己制定一个,不是特别推荐使用

总结

如果多维数组的各个维度的长度都是完全固定的值,那么把它传递给函数没有问题,如果情况更普遍一些,则会比较复杂,如下:

  • 一维数组:没有问题,但是需要包括一个计数值或者一个能够识别越界位置的结束符。
  • 二维数组:不能直接传递给函数,对于字符串,可以写成Iliffe向量的形式,并且使用相同的下标表示法。对于其他类型,需要增加1个计数值或者能够标识越界的结束符,依赖于调用函数和被调函数的约定。
  • 三维或更多维的数组:都无法使用。必须分解为几个维数更少的数组。

使用指针从函数返回一个数组

  • 严格来说,无法直接从函数返回数组,但是可以返回指向数组的指针,确切的说,可以返回指向任意数据结构的指针。
int (\*paf())[20];//paf是函数,返回值是int(\*)[20]
//定义如下:
int (\*paf())[20]
{
    int (*pear)[20];
    pear = calloc(20,sizeof(int));
    if(!pear) longjmp(error,1);
    return pear;
}
int main()
{
    int (*result)[20];
    ...
    result = paf();
    return 0;
}

Reference

C专家编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值