接上一节
目录
十一、指针函数和函数指针
11.1 指针函数
函数的返回值为指针类型的函数,叫做指针函数
- 不要返回局部变量的数据(eg: 局部变量、局部数组)
- 作为另外一个函数的参数

#include<stdio.h>
int *fun()
{
//函数调用完会释放
int a=20; //2000
return &a; //return 2000
//局部变量当函数调用完会释放,虽然返回了地址,但是变成了野指针
}
char *fun1()
{
//char str[100]="hello"; //主要是局部变量,函数执行完空间释放
static char str[100]="hello";//空间开辟在数据区,全局生命周期
return str;
}
char *fun2()
{
//char str[100]="hello";//局部变量,不能返回
char *p="hello"; //字符串常量(数据段:全局生命周期)类型 char* 说明存放的是字符串的地址
printf("%p\n","hello");
return p;
}
int main()
{
#if 0
int *p=fun();
printf("ret = %d\n",*p);
#endif
char *p=fun2();
printf("p %s\n",p);
return 0;
}
#include<stdio.h>
int main()
{
char str[100]="hello";
//char *p="hello";
char *p=str;
//str[0]='a';
//printf("%s\n",str);//aello
//通过数组可改,存储的地址是栈区,可读可写
//p[0]='a';
//存储的地址是数据段的.rodata段,保存字符串常量,不可改
*p='a';
printf("%s\n",p); //aello
printf("%s\n",str); //aello
}
#include <stdio.h>
char * mystrncpy(char*dst ,char* src,int n)
//返回值为指针类型
{
char * tmp = dst;
while((*dst=*src) && --n)
{
dst++;
src++;
}
if(0==n)
{
*(dst+1) ='\0';
}
return tmp;
}
int main()
{
char str1[100]="hello";
char str2[100]={0};
char* p = mystrncpy(str2,str1,10);
printf("%s\n",p);
printf("%s\n",str2);
return 0;
}
11.2 函数指针
函数指针,本质是一个指针,存储某一个函数的地址<“把操作存入指针”>函数名本质也是一个指针,存储了一个地址,指向代码段中一个对数据操作的代码
函数名对应的地址-->指针
#include<stdio.h>
double add(double a,double b) // int (*) (int,int)
{
return a+b;
}
double sub(double a,double b)
{
return a-b;
}
double mul(double a,double b)
{
return a*b;
}
double div(double a,double b)
{
return a/b;
}
int main()
{
//add(a,b)
double (*p)(double,double)=NULL; //函数指针
double a=10;
double b=20;
int choose = 0;
printf("1 +\n2 -\n3 *\n4 /\n");
printf("want to do?\n");
scanf("%d",&choose);
switch(choose)
{
case 1:
p=add;
break;
case 2:
p=sub;
break;
case 3:
p=mul;
break;
case 4:
p=div;
break;
default:
p=add;
}
double ret = p(a,b);//add(a,b)
printf("p(a,b) ret: %.2lf\n",ret);
return 0;
}
应用:降低代码耦合度,被称为回调函数-->会被 被动调用的函数
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int asc(int a,int b)
{
//return a>b;
//return a>b?1:0;
if(a>b)
{
return 1;
}
return 0;//无需交换
}
int desc(int a,int b)
{
if(a<b)
{
return 1;
}
return 0;//无需交换
}
int asc_abs(int a,int b)
{
return abs(a)>abs(b);
}
int bub(int *a,int len,int (*fun)(int,int))
{
int i=0,j=0;
for(j=len-1;j>0;j--)
{
for(i=0;i<j;i++)
{
if(fun(a[i],a[i+1]))
{
int t=a[i];
a[i]=a[i+1];
a[i+1]=t;
}
}
}
for(i=0;i<10;i++)
{
printf("%d ",a[i]);
}
return 0;
}
int main()
{
int a[10]={0};
srand(time(NULL));
int i=0;
for(i=0;i<10;++i)
{
a[i]=rand()%10;
}
for(i=0;i<10;i++)
{
printf("%d ",a[i]);
}
bub(a,10,asc_abs);//desc/abs
printf("ret:\n");
printf("\n");
return 0;
}
作为函数的设计者,希望显示数据的时候,可以更加多种规则显示,所以需要主调者规则调入函数因此需要使用函数指针进行解耦合
其中的fun()函数就是回调函数,这个函数就是被动调用
十二、二级指针
定义:指向指针变量的指针就是二级指针

应用:
- 函数调用的地址传递中,需要通过改变指针变量本身(使用二级指针,能改变指针的指向)
- 区分一级指针:如果需要改变指针指向的内容,使用一级指针
- 函数传参过程中, char **,char*[]-->指针数组,是兼容类型
十三、const指针
Const 常量
int a=10;
const int b=10;//只读变量
b=20; //错误,因为只读变量不能赋值
const int c;//写法是错误的、因为是只读变量,所以需要在定义的时候就初始化
c=20;//否则后面都是赋值会报错
#include<stdio.h>
int main()
{
const int *p; //表示指针指向的内容不能被修改,常量指针
int const *p1; //const在前在后无所谓,这两个一样
int *const p; //表示指针的指向(指针本身)不能变化,(整形的)指针常量-->类似数组名
const int*const p; //指针本身不能变,指针指向的内容也不能变-->指向常量的常量指针
char str[100]="hello";
char str2[100]="world";
//最常用
const char *p=str;
// p[0]='a';//错误的,不能通过P去修改str的内容
str[0]='a'; //对的,只说了P是只读的,没说str是只读的
p=str2; //对的,表达的内容不能变,没有说指针本身不能变
char *const p2=str; //定义的时候就要初始化
p2[0]='a'; // 对的,指针本身不能变,指向的内容可以修改
// p2=str2; //错误的,本身不能变化
const char*const p3=str; //指向常量的常量指针,指针本身不能变,指向的内容也不能变
// p3[0]='a'; //错误
// p3=str2; //错误
}
十四、void *万能指针
void a;// 错误的,编译器不知道给a要开辟多大的空间
void 函数的返回值
void * 函数的返回值,函数的参数
void * 作为函数的参数的时候,可以接受任意类型的指针
- void*保存内存的地址
- 其他任意类型的指针给void*赋值或参数传递,不需要额外操作,直接赋值或参数传递就可以了
- 当需要把void*转换为其他类型的指针时,需要强制类型转换后才可以使用
- void*中只保存了地址,不知如何对数据进行访问,如果没有转换,*p,p+1都会失败,没有void类型的变量
- void*用于函数的返回值、函数的参数(mycpy.c最能体现这一点)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void show_char(void *p)
{
printf("%c",*(char *)p);
}
void show_int(void *p)
{
printf("%d ",*(int *)p);
}
void show_double(void *p)
{
printf("%lf ",*(double *)p);
}
void show(void *a,int len,int size,void (*show_change)(void*))
{
int i=0;
for(i=0;i<len;i++)
{
show_change(((char*)a+i*size));
}
printf("\n");
}
int main()
{
char str[5]="hello";
int a[5]={1,2,3,4,5};
double b[5]={1.1,2.2,3.3,4.4,5.5};
show(str,strlen(str),sizeof(str[0]),show_char);
show(a,5,sizeof(a[0]),show_int);
show(b,5,sizeof(b[0]),show_double);
return 0;
}
mycpy.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void* mymemcpy(void* dst,void* src,int size)
{
char * pdst = (char*)dst;
char* psrc= (char*)src;
int i = 0 ;
for(i=0;i<size;i++)
{
*pdst=*psrc;
pdst++;
psrc++;
}
return dst;
}
int main()
{
double d1[5]={1.11,2.22,3.33,4.44,5.55};
double d2[5]={0};
mymemcpy(d2,d1,sizeof(d1)); // 8*5 =40
int i = 0 ;
for(i=0;i<5;i++)
{
printf("%lf\n",d2[i]);
}
}
218

被折叠的 条评论
为什么被折叠?



