数组指针本质上就是一个指针,它里面存放的是数组的首地址。
#include
void show(int (*p)[4],int n)
{
for(int i=0;i
指针数组的本质就是数组,不过所有存储元素都是指针。当你想一次性定义出多个相同数据类型的指针时,可以使用指针数组
int* a[3] ;
char* names[4]={"ikun","ctrl","music","susan"};
sizeof(names);//--->4*4=16;
int main(int argc,const char * argv[])
{
return 0;
}
//argc:参数的个数 包括./a.out
//argv:参数的值列表 argv[0]="./a.out" argv[1] ="第一个参数"
注意:1.命令上传递过来的所有参数都是字符串
2.只要用到命令行传递的参数必须加容错判断
if(argc ==1)//./a.out ==1
{
printf("err\n");
return -1;
}
1.argc和argv 变量名可以改变
2.argv的数据类型是:char *[]
示例:
//判断终端输入的是否是质数
#include
int myatoi(char *p)
{
int num = 0;
int i = 0;
while(p[i])
{
num = mun*10 +p[i]-48;
i++;
}
return num;
}
int isPrime(int num)
{
for(int i=2;i
终端命令:
./a.out 123
#123是传递给a.out文件的参数
简单来说就是:一个函数直接或者间接调用自己。递归函数运用比较少,因为它要在栈内开辟空间,如果递归没有写好出口,就会造成栈溢出。
//递归实现计算阶乘
#include
int fun(int n)
{
if(n==1)//递归结束条件
{
return 1;//递归出口,如果递归函数不写出口会导致无限递归,最后消耗完栈空间后,栈溢出报错。
}
return n*fun(n-1);
}
int main ()
{
int n=0;
scanf("%d",&n)
int res =fun(n);
printf("%d! is%d\n",n,res);
return 0;
}
本质还是个指针,就是指向指针的指针。存放的是一级指针的地址
int *p; //一级指针---》保存普通变量的首地址
int **p; //二级指针---》保存一级指针的首地址
int ***p; //三级指针---》保存二级指针的首地址
int ****p; //四级指针---》保存三级指针的首地址
二级指针的定义:
int a=10086;
int *p=&a;
int **q=&p;
通过二级指针修改变量:
**q=10;
//对一级指针取地址,就变成了二级指针
#include
int main()
{
int a=10;
int *p=&a; //一级指针
int **q=&p; //二级指针
//打印a的值
printf("%d %d %d",a,*p,**q);
//打印a的地址
printf("%p %p %p",&a,p,*q);
//打印p的地址
printf("%p %p",&p,q);
return 0;
}
q //int **
*q //int *
**q //int
&q //int ***
*降级
&升级
#include
#include
void get_mermory(int *q)
{
q=malloc(10*sizeof(int ));//申请40字节空间,首地址赋值给q
}
int main(int argc, const char *argv[])
{
int i=0;
int *p=NULL;
get_mermory(p);//值传递
for(i=0;i<10;i++)
{
p[i]=i;//赋值
}
for(i=0;i<10;i++)
{
printf("%d\n",p[i]);//打印
}
free(p);//释放手动申请的空间
return 0;
}
//运行结果:段错误。函数结束后函数内的临时变量被清空。无法改变p指针是空指针的事实,对空指针指向的地址赋值,段错误。
//修改代码:(1)
#include
#include
void get_mermory(int **q)//变成了二级指针
{
*q=malloc(10*sizeof(int ));//修改指针指向
}
int main(int argc, const char *argv[])
{
int i=0;
int *p=NULL;
get_mermory(&p);//地址传递
for(i=0;i<10;i++)
{
p[i]=i;
}
for(i=0;i<10;i++)
{
printf("%d\n",p[i]);
}
free(p);
return 0;
}
//修改代码:(2)通过函数返回值实现修改p的指向
#include
#include
int * get_mermory()
{
int*p= malloc(10*sizeof(int ));
if(p==NULL)//非空校验
{
printf("空间开辟失败\n");
return -1;
}
return p;
}
int main(int argc, const char *argv[])
{
int i=0;
int *p=NULL;
p=get_mermory();
for(i=0;i<10;i++)
{
p[i]=i;
}
for(i=0;i<10;i++)
{
printf("%d\n",p[i]);
}
free(p);
return 0;
}
#include
void change_ptr(int **p,int *q)
{
*p=q; //*p ---p1
}
int main()
{
int a=10,b=20;
int *p1=&a;
printf("修改前p的指向是:%d\n",*p1); //10
change_ptr(&p1,&b);
printf("修改后p的指向是:%d\n",*p1); //20
return 0;
}
//二级指针常用来修改一级指针保存的内容
#include
//void show(char *p[5],int n) ---转成二级指针
void show(char **p,int n)
{
for(int i=0;i
本质还是函数,只不过他的返回值是指针类型。
作用:调用完函数能获得一个地址
void* malloc(int size); //void* 返回值是无类型的指针
char* strcpy(char *dest,const char *src)
char* strcat(char *dest,const char *src)
本质是指针,是指向函数的指针。存放的是一个函数的地址//定义一个指针
数据类型* 指针名 =地址---》函数名
函数的数据类型是什么???
指针特点---》*
数组特点---》[]
函数特点---》()保留()才知道这是函数
void fun(void); //无参无返回值<--->void fun();
//类型 (void) 除掉不重要的函数名和形参变量名(形参名可以不去)就是函数的类型
int getmax(int a,int b)
//类型 int(int ,int)
char *strcpy(char *a,char* b)
//类型 char*(char*,char*)
void fun();
void (void)*p=fun; //由于()的优先级高,这样等号左边会被视为一个函数的声明---》
//加()---》
void (void)(*p)=fun;
//但依旧是从左往右识别,这样写还是不合适---》
//(*p)前移----》
void (*p)(void)=fun;
再来两个例子:
char *strcpy(char *a,char* b);
char *isWithin(char *s,char ch);
char*(*p)(char *,char *)=strcpy;
//给指针名删了---》指针类型:char*(*)(char *,char *)
//给(*p)一起删了---》指针指向的类型:char* (char *,char *)
char*(*q)(char *,char)=isWithin;
//直接复制函数声明,把函数名的位置换成(*p),然后把形参名删了,加上等号以及等号右边的函数名
//切记,*p的括号不能省掉,不屑括号就变成了,指针函数了。--》void *p(void);
函数指针的作用:
1.能用函数名一样使用
调用函数时可以通过函数名或者通过函数指针来调用
2.能将一个函数当作另一个函数的参数进行传递
#include
int getSum(int a,int b)
{
return a+b;
}
int getSub(int a,int b)
{
return a-b;
}
int getMul(int a,int b)
{
return a*b;
}
int getDev(int a,int b)
{
return a/b;
}
int main()
{
//定义指针指向getSum()
int (*p)(int ,int )=getSum;
int res=0; //用于保存计算结果
res =getSum(10,5); //通过函数名调用函数
printf("res is %d\n",res);
res =p(10,5); //通过函数指针调用,函数指针能函数名一样使用
printf("res is %d\n",res);
p=getSub; //修改p指针的指向,指向了getSub函数
res =p(10,5);
printf("res is %d\n",res);
p=getMul; //修改p指针的指向,指向了getMul函数
res =p(10,5);
printf("res is %d\n",res);
p=getDev; //修改p指针的指向,指向了getDev函数
res =p(10,5);
printf("res is %d\n",res);
res=callFun(getSum,10,5); //传函数名实现函数调用函数
printf("res is %d\n",res);
return 0;
}
//通过修改指针指向来实现调用不同函数,这样写很麻烦。可以通过函数指针优化程序,使得程序更加简单。
#include
int getSum(int a,int b)
{
return a+b;
}
int getSub(int a,int b)
{
return a-b;
}
int getMul(int a,int b)
{
return a*b;
}
int getDev(int a,int b)
{
return a/b;
}
int callFun(int (*p)(int ,int ),int a,int b)
{
return p(a,b);
}
int main()
{
int res=0; //用于保存计算结果
res=callFun(getSum,10,5); //传函数名实现函数调用函数,不用在主函数中来回修改指针指向。
printf("res is %d\n",res);
res=callFun(getSub,10,5);
printf("res is %d\n",res);
res=callFun(getMul,10,5);
printf("res is %d\n",res);
res=callFun(getDev,10,5);
printf("res is %d\n",res);
return 0;
}
//实现并不知道调用的是什么函数,再调用的时候传递函数名实现具体调用。提高了函数的功能性,可拓展性。
//回调函数:只要参数列表中有一个参数类型是函数指针的函数就是回调函数。在函数的内部一定会用指针调用指向的函数,所以称为回调函数。callFUn就是一个回调函数。
}
本质是数组,但是数组中的每一个元素都是一个函数指针。
作用:能一次性定义多个相同数据类型对的函数指针。
上面定义了四个函数:getSum,getSub,getMul,geyDev
如果要分别定义一个指针指向他们就得写重复的代码
int(*p)(int ,int )=getSum;
int(*q)(int ,int )=getSub;
int(*r)(int ,int )=getMul;
int(*s)(int ,int )=getDev;
//定义函数指针数组存放他们
数据类型 数据名[];
--->
int(*)(int,int)a[]
()优先级最高,[]优先级高于*
--->
int (*a[4])(int ,int)={getSum,getSub,getMul,getDev};
元数个数:[]里的写几个就是几个
元素类型:除掉数组名和[]---》int(*)(int ,int)
函数指针指向的类型:在元素类型基础上给(*)删了---》int(int ,int)
其中:
a[0]=getSum;
a[1]=getSub;
a[2]=getMul;
a[3]=getDev;
const :常量化
被修饰的变量不能被修改,被常量化了。
const int a=10;<--->int const a=10;
//无法修改a的值,尝试修改会报错。
const int * ptr; //常量指针
int const *ptr; //指针常量
#include
int main()
{
int a=10;
int b=20;
int const*p=&a; //const修饰*p,无法修改*p里面保存的内容,但是可以通过指针修改它指向的内容 常量指针
a=30;
printf("a is %d\n",a);
int * const q=&a; //const修饰p,无法修改p里面保存的内容,无法通过指针修改它指向的内容,但是可以指向别的地方 指针常量
*p=30;//报错 *p只读
printf("a is %d\n",a);
q=&b;//报错 q只读
printf("a is %d\n",a);
return 0;
}