目录
- 字符指针变量
- char*
- 数组指针变量
- 数组指针变量是什么
- 数组变量的写法与初始化
- 二维数组传参的本质
- 函数指针变量
- 函数指针变量是什么及创建
- 函数指针变量怎么用
- 两个有趣的代码
- typedef 关键字
- 函数指针数组
- 函数指针数组的运用——转换表
字符指针变量
char*
我们一般使用char*时,是如下使用的
intmain(){charc='w';char*ch=&c;return0;}这里有char的另一种用法,即可以用char来存放字符串。
存放字符串的两种方法
- 运用数组————char arr[ ] =…
- 运用字符指针变量,如下
intmain(){char*ch="abcdefg";//“abcdefg"是常量字符串,指针变量ch存放的是a的地址printf("%c",*ch);//这里打印的是aprintf("%s",*ch);//这里打印的是abcdefgreturn0;}不过即然说了abcdefg是常量字符串,所以它是不能更改的。为了严谨性和避免程序崩溃,我们一般在char* ch前添加const以表明不能修改。
下面再分享一道题加深理解
#include<stdio.h>intmain(){charstr1[]="hello bit.";charstr2[]="hello bit.";constchar*str3="hello bit.";constchar*str4="hello bit.";if(str1==str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if(str3==str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return0;}结果
str1与str2因为str1与str2是数组,它们先向内存申请空间地址,再存放hello bit. 它们只是存放的的内容相同,但是str1与str2比较的本质是数组的起始地址,所以结果是are not same
str3与str4这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同⼀个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。
同理,字符指针数组
intmian(){char*pp[3]={"abcd","hijk","wml"};//pp[1]存的是字符a的地址//pp[2]存的是字符h的地址//pp[3]存的是字符w的地址return0;}数组指针变量
数组指针变量是什么
先申明数组指针变量是指针,具体是什么见如下类比
整型指针int*p 指向整型变量的指针,存放的是整型变量的地址 字符指针char*p 指向字符变量的指针,存放的是字符变量的地址 数组指针int(*p)[5]=&arr 指向数组的指针,里面存放的是数组的地址注意区分前面所学的指针数组:它表示存放指针变量的数组。
数组变量的写法与初始化
intmain(){intarr[3]={1,2,3};int(*p)[5]=&arr;//&数组名 是整个数组的地址return0;}理解
- 为什么是(p): 因为*与p在一起才能表示p是指针变量,如果不加()就变成了intp[3],此时*与int在一起了,p成指针数组了。
- [参数] :表明指向的数组有几个元素。
intmain(){chararr[3]={'a','b','c'};char(*p)[3]=&arr;return0;}以上也是一个数组变量
二维数组传参的本质
voidtest(arr[3][5],inta,intb){inti=0;intj=0;for(i=0;i<a;i++){for(j=0;j<b;j++0){printf("%d ",arr[i][j]);}printf("\n");}intmain(){intarr[3][5]={{1,2,3,4,5},{2,3,4,5,6},{8,9,5,4,5}};test(arr,3,5);return0;}前文所说二维数组的元素是一维数组(每一行),所以当二维数组传参时,传的也是首元素的地址,即第一行(一维数组)。所以函数对二维数组传参的接收有另一种写法
voidtest(int(*p)[5],inta,intb)//接收的是第一行代表的一维数组的地址{inti=0;intj=0;for(i=0;i<a;i++){for(j=0;j<b;j++0){printf("%d ",*((*arr+i)+j))://数组地址+-与数组中每一个元素+-不同}printf("\n");}函数指针变量
函数指针变量是什么及创建
类比前文,函数指针————指向函数的指针变量,用来存放函数的地址。
voidtest();intmain(){printf("%p",test);//打印的是函数的地址printf("%p",&test);//打印的是函数的地址return0;}不同于数组
- 数组名是数组首元素的地址,函数名是函数的地址
- &数组名是数组的地址,&函数名是函数的地址
下面是函数指针的写法
voidtest(intx,inty);intmain(){void(*p)(intx,inty)=test//P1 P2 P3return0;- P1:与指向函数的返回类型有关
- P2:指针变量的名字
- P3:与指向函数的参数有关
该指针变量的类型为 ==void(*)(int x,int y)==即去掉指针变量的名字
函数指针变量怎么用
函数指针变量是通过解引用来使用的,一般有两种解引用
- (*p)(传入的参数): (*p)就等效于函数本身,注意括号不能少。
- p(传入的参数):p就等效于函数本身,这里可以不用解引用操作符*仅限函数指针
#include<stdio.h>intAdd(intx,inty){returnx+y);}intmain(){inta=3;intb=5;int(*p)(intx,inty)=Add;//也可以是&Addintr=(*p)(a,b);//int r = p(a,b);printf("%d",r);//打印的结果是8。如上展示了函数指针变量解引用的用法。
两个有趣的代码
(*((void)(*)())0)();上述代码实质是调用0地址代表的函数。
- ((void)(*)())是强制类型转换,将0转换为一个函数指针,它此时代表着0地址的函数。
- 而( *((void)(*)())0) (),是在调用这个函数指针,这个函数没有返回值,也没有参数。
void(*signal(int,void(*)(int)))(int);上述代码是一个函数声明。
- 一个signal函数,传参类型是int和void(*)(int)类型的
- 它的返回类型是外围的void(*)(int)类型的
typedef 关键字
typedef 能够重新将复杂的类型重命名
下面将展示常见的typedef用法
简化一些复杂的类型
typedefunsignedintunit;unit a=7;//或者简化数组指针typedefint(*ptr_t)[5];//c语言语法,不能写成typedef int(*)[5] ptr_tintarr[5]={0};ptr_tp=&arr;//或者简化函数指针typedefvoid(*ptr_t)(int);//不能写成typedef void(*)(int)ptr_tptr_tsignal(int,ptr_t);函数指针数组
当我们想要用到一个可以用来存放函数指针的数组时,就需要函数指针数组
intAdd(intx,inty){}intSub(intx,inty){}intMul(intx,inty){}intDiv(intx,inty){}intmain(){int(*per[4])(int,int)={Add,Sub,Div,Mul};和数组的写法 类型+数组名+[ 参数 ]类似
int(*)(int,int)是数组的类型,per是数组名。
该数组中存放的函数指针都是**int(*)(int,int)**类型的。
函数指针数组的运用——转换表
#include<stdio.h>intadd(inta,intb){returna+b;}intsub(inta,intb){returna-b;}intmul(inta,intb){returna*b;}intdiv(inta,intb){returna/b;}intmain(){intx,y;intinput=1;intret=0;int(*p[5])(intx,inty)={0,add,sub,mul,div};//转移表do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("请选择:");scanf("%d",&input);if((input<=4&&input>=1)){printf("输⼊操作数:");scanf("%d %d",&x,&y);ret=(*p[input])(x,y);printf("ret = %d\n",ret);}elseif(input==0){printf("退出计算器\n");}else{printf("输⼊有误\n");}}while(input);return0;}以上通过输入一个数,找到对应函数指针数组里的函数并且调用该函数,这种类似跳转的感觉就是转换表
局限性只有返回类型和参数类型相同的函数,才能存入数组