C语言进阶之路复习贴

指针篇

数组指针,就是指向数组的指针

指针数组,就是一个数组,它的成员是指针

数组指针:

int arr[10]={0}

arr代表着首元素的地址,arr 等同于 &arr[0]

同时,arr还是数组名

而 &arr 表示的是 数组的地址

通常,在声明指针的时候,例如int *A=&B,就是说创建了一个整形指针A,它指向B的地址(B的地址被赋值给了A),那么A==&B,*A==B

同理,

int n[10]={0};

int (*arr)[10]=&n;

则说明arr==&n,*arr==n(也就是&n[0])

所以*(*arr)==n[0]

由此可以知道偏移量的规律

n+1,这里的n是首元素地址,因此偏移量是一个元素,也就是一个整形的大小

n+1==&n[1]

arr+1,这里的arr是数组指针,是数组的地址,因此偏移量是一个数组的大小,一个数组的大小是多少,这取决的arr指向的数组地址对应的数组的特征,比如arr就是指向元素为10个整形的数组,那么偏移量就是40字节

;;;;;;;;;;;;;;;;;;;;;;;;

这里复习一下十六进制和地址

在C语言里,地址用十六进制表示,十六进制的特征是0x开头,后面跟八位数

在十六进制中,0-9用阿拉伯数字表示,10-15用A-F表示

将十进制转化为16进制,可以参考一下将十进制转化为2进制,用短除法

;;;;;;;;;;;;;;;;;;;;;

这里还有二进制转化成十六进制的比较简单的方法

;;;;;;;;;;;;;;;;;;;;;

如果上面的例子中

n的地址是 0x027CFA8C

那么 n+1 是 0x027CFA90(增加了一个偏移量,也就是四个字节,现在说的4个字节的“4”是十进制的,转化为十六进制也是4,因此直接和十六进制地址相加就可以了,0x027CFA8C+4)

 arr的地址也是0x027CFA8C(数组指针是将指针指向的地址对应的数据圈定为了数组,而不再和以前一样是整形等单独的数据类型,但是无论是数组还是数组的元素,数据存储的位置并没有改变)

arr+1的地址就是arr向后偏移40字节,十进制中的40在十六进制中是28,因此是0x027CFA8C+28,即0x027CFAB4

数组指针的构成(或者说字符串指针的构成)

int (*数组指针名)[指针指向的数组含有的元素个数]

指针数组:

写法:int *p[10]

意味着一个名为p的数组,有十个元素,元素类型是整形指针

同样的,也有char *x[10]

关于二维数组

二维数组的元素是一维数组

因此二维数组的首元素是第一个数组,二维数组的数组名也是第一个数组的地址,因此二维数组数组名本身就是一个数组指针,二维数组的元素本身就是数组(一维)

Eg:

int n[3][10]={0};

int (*arr)[3][10];

n[1][3]==(*arr)[1][3]==*((*arr)+1)+3

函数指针

就是指向函数的指针

函数其实是有地址的,函数名(或者&函数名)就是函数的地址

int Add(int x,int y)
{
    return x+y;
}
int main()
{
    int (*pf)(int,int)=&Add;
    return 0;
}

由此可以看出函数指针的书写格式:

函数指针指向的函数的数据类型 (*函数指针名)(函数指针指向的函数的形参数据类型,同上)

对于函数而言,在取用函数的地址时,取地址符号可以省略,对于函数指针而言,定义的时候,指针名之前的解引用符号可以省略

int (*p)(int ,int)=&Add;
int (*P)(int ,int)=Add;
int (p)(int ,int)=&Add;
int (p)(int ,int)=Add;
//以上四种写法都是可以的

以下为几个例子 

#include<stdio.h>
int Add(int x,int y)
{
    return x+y;
}
int main()
{
    int (*pf)(int,int)=&Add;
    int sum=(*pf)(2,3);//对于函数指针解引用,调用函数,并进行传参
    printf("%d/n",sum);
    return 0;
}
(*(void(*)())0)()

//这段代码是啥意思呢
//先看里面,void(*)()是一个函数指针
//(void(*)())0是利用强制类型转换,把0强制转换为函数指针类型,且是void(*)()类型的指针
//*(void(*)())0对于这个强转后的函数指针进行解引用并传参使用
//但是这段代码没法运行    (出自《C陷阱与缺陷》)

void(*signal(int ,void(*)(int)))(int)

//这里本质是对于函数signal的声明
//这段代码的主体是函数指针的声明,在指针函数的声明中,第一个括号的取地址符号后面跟的应该是函数指针名,其实就是函数地址
//为什么这么说呢,因为在声明之后都是将某个函数的地址赋值给函数指针名,因此其实第一个括号的取地址符号后面跟的就是函数地址,而在这里却是一个函数,这只能说明一个问题,那就是后面跟的个函数的返回值是指针
//既然signal是个函数,那我们看一下他的形参,第一个是一个整形,第二个是一个函数指针,这个函数指针对应的函数返回值类型是void,形参是int类型,不过同样,这个也是无法使用的,因为没有函数指针名

但是要注意的是,这只能声明一下signal,而并非定义signal,因为函数要实现的功能没有说明

函数指针数组

用来存储同类的函数指针的数组

写法

函数指针对应函数返回类型 (*函数指针数组名[成员个数])(函数指针对应函数形参类型,同上...)

举个例子

#include<stdio.h>
int Add(int x, int y)
{
    return x+y;
}
int Sub(int x, int y)
{
    return x-y;
}
int Mul(int x, int y)
{
    return x*y;
}
int Div(int x, int y)
{    
    return x/y;
}
int main()
{
    int (*pf[4])(int , int )={Add,&Sub,&Mul,Div};
//函数和函数指针的取地址和解引用符号都可以省略
    for(int i=0;i<4;i++)
    {
        printf("%d\n",pf[i](8,4));
//这里pf前面也省略了*
    }
    return 0;
}

指向函数指针数组(的地址)的指针

int Add(int x, int y )
{
    return x+y;
)
int main()
{
    int (*p)(int,int)=Add;//函数指针
    int (*pf[4])(int,int);//函数指针数组
    int (*(*PF)[4])(int,int)=&pf;//函数指针数组指针
    return 0;
}

用这种思想可以套娃

回调函数

就是一个通过函数指针调用的函数。

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数是一种极致,回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

Eg1:

#include<stdio.h>
int a(int x,int y)
{
    return x+y;
}
int b(int x,int y)
{
    return x-y;
}
int c(int x,int y)
{
    return x*y;
}
int d(int x,int y)
{
    return x/y;
}
void calc(int (*pf)
int main()
{
    int w,x,y;
    int (*pp[5])(int ,int )={0,a,b,c,d};
    do
    {
        printf("输入 1 进行加法运算\n输入 2 进行减法运算\n输入 3 进行乘法运算\n输入 4 进行除法运算\n输入 0 结束程序\n");
        scanf("%d",&w);
        if(w==1|w==2|w==3|w==4)
        {
            printf("请输入你的两个数据\n");
            scanf("%d%d",&x,&y);
            printf("%d\n",(*pp[w])(x,y));
        }
        else if(w==0)
        {
            printf("程序结束\n");
            break;
        }
        else
        {
            printf("输入错误\n");
        }
    }while(1);
    return 0;
}

这里的加减乘除这四个函数就是回调函数,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值