指针进阶——指针的类型以及指针的应用2

四、数组传参和指针传参

4.1 一维数组传参

#include<stdio.h>
int main()
{
    int arr[] = {1,2,3};
    test(arr);
    return 0;
}

如果要把数组arr传给test,test的形参可以设置成什么样呢?

第一种用数组的方式接收——test(int arr),test(int arr[3]),test(int arr[])。或者是以指针的方式接收,因为数组名是首元素的地址——test(int* p)。

指针数组的传参,如果这时候将一个指针数组int*arr[10] 传给test,形参又可以怎么接收呢?与上面类似的,可以写成test(int(*arr)),test(int **arr),第二种传参的方式是因为数组名是首元素的地址,而首元素又是一个指针,从而是一个arr是一个二级指针。

4.2 二维指针的传参

#include<stdio.h>
int main()
{
    int arr[3][5] = {0};
    test(arr);
    return 0;
}

类似的,对于一个3行5列的二维数组,它传参给test时候,test可以以数组的方式接收,也可以以指针的方式接收。

具体的实现方式是——test(int arr[3][5]),test(int arr[][5]),test(int (*arr)[5]).

4.3 一级指针的传参

#include <stdio.h>
void print(int *p, int sz)
 {
     int i = 0;
     for(i=0; i<sz; i++)
     {
       printf("%d\n", *(p+i));
     }
}
int main()
{
     int arr[10] = {1,2,3,4,5,6,7,8,9};
     int *p = arr;
     int sz = sizeof(arr)/sizeof(arr[0]);
     //一级指针p,传给函数
     print(p, sz);
     return 0;
 }

上图就是一个一级指针p传给print函数的方式。

思考:

当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

答案:

#include<stdio.h>
int main()
{
    int a = 1;
    int arr[] = {1};
    int* arr[] = {&a};
    int arr[3][5] = {0};
    print(&a);//将一个整形的地址传入
    print(arr);//整形数组的数组名就是首元素地址 故也是一个一级指针,也可传入
    print(arr[0]);//一个整形指针数组的某一个元素都可以传入print 
    print(*(arr+i)+j)//其中i和j是保证不越界访问下的合适偏移量  
        //一个二维数组的数组名相当于第一行的一维数组的地址
        //只要在数组范围内对arr加减都可以得到任意一行的某个元素的地址。
        //再解引用,相当于得到了某一行一维数组的数组名,数组名就是首元素地址。
    return 0;
}

 上述给出了基本能用到的所有传入一级指针的方式,可能还有其他的很多套娃传参方式,这里不一一列举了。

4.4 二级指针传参

顾名思义就是将二级指针当作参数传给函数 和一级指针十分类似,不赘述。

下面不加解释地给出一些二级指针的传参方式。

#include<stdio.h>
int main()
{    
    int a = 10;
    int *p = &a;
    int** pp = &p;
    int* arr[] = {p};
    int** krr[] = {pp};
    print(pp);//p是指针 pp是它的地址 也就是二级指针
    print(&p);//和上面是等价的
    print(arr);//指针数组的数组名是首元素地址 首元素是指针 从而数组名是二级指针
    print(krr[0]);//一个二级指针数组的任意元素都是二级指针
    return 0;
}

五、函数指针

函数指针——一个指向函数的指针,可以通过它来调用函数,这为后面讨论回调函数打下基础。

假设现在实现了一个test函数,想要得到它的地址,具体的声明是什么样子?

void test(int n)
{
    return 0;
}
int main()
{
    void (*pt)(int n) = &test;//pt是函数指针。
    //一个函数指针的声明——返回值+(*函数指针名)+(函数的参数);
    printf("%p\n",pt);
    return 0;
}

一个数组名是它的首元素地址,那一个函数名呢?

答案是就是它自己的地址。

void test(int n)
{
    return 0;
}
int main()
{
    void (*pf)(int n) = test;
    void (*pt)(int n) = &test;
    printf("%p\n",pt);
    return 0;
}

输出的结果是一样的,说明函数名也是函数的地址。

 有了函数指针,就可以通过函数指针来调用函数,和一般的指针变量一样,只要解引用就好,不过函数指针解引用后还需要传参,毕竟是一个函数。

#include<stdio.h>
void test(int n)
{
    printf("%d",n);
    return 0;
}
int main()
{
    void (*pf)(int n) = test;
    (*pf)(1);//解引用进行函数的调用 一定要用括号把pf和星号括起来 否则pf会先和后面的括号结合,出现错误
    return 0;
}

事实上,对于函数指针变量,不加星号解引用也是可以直接调用函数的!

#include<stdio.h>
void test(int n)
{
    printf("%d",n);
    return 0;
}
int main()
{
    void (*pf)(int n) = test;
    pf(1);//解引用进行函数的调用
    return 0;
}

请思考一下这两个代码的意思

1、(* (void (*)() ) 0) (); 

2、void (*   signal(int , void(*)(int) )         )   (int)  ;

答案:(void (*)())0表示将0强制转化为一个返回值为void 空参的函数指针。用星号解引用得到了这个函数,最后一个括号用于传参。 

  signal(int , void(*)(int) ) signal先和括号结合,它的参数是一个int和一个函数指针。由于*要和signal函数的返回值结合 说明它的返回值是一个函数指针,括号外面的void和int是它的返回类型和形参类型。

六、函数指针数组

声明的方式:函数的返回类型+(*数组名[元素个数])+(函数的形参类型)

int (*parr1[10])();

代码中parr1就是数组名

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值