函数概述
函数具备3要素:1、函数名(地址)2、输入参数3、返回值
如何用指针保存函数呢?
int fun(int,int,char);
int (*p)(int,int,char);
#include <stdio.h>
int main()
{
int (*myshow)(const char *,...); //const char *后面不一定要写名字,这里只是声明告知
printf("hello world!\n");
myshow = printf; //此时myshow和printf读内存的方式一致,就可以用指针来描述函数
myshow("==============\n");
return 0;
}
>>hello world!
>>==============
函数指针第一种使用方法:
#include <stdio.h>
int main()
{
int (*myshow)(const char *,...); //const char *后面不一定要写名字,这里只是声明告知
printf("the printf is %p\n",printf); //printf本身也是个地址,为0x8048320,可能会变
myshow = (int (*)(const char *,...))0x8048320; //把一个地址变成一个函数声明
myshow("==============\n");
return 0;
}
>>the printf is 0x8048320
>>==============
int (*p[7])(int,int); //数组里存放的地址是函数地址
p[0] = fun1;
p[1] = fun2;
实参形参拷贝
#include <stdio.h>
void myswap(char buf)
{
printf("the buf is %x\n",buf);
}
int main ()
{
int a = 20;
myswap(0x1234); //0x1234默认是int型
return 0;
}
>>the buf is 34
对指针、数组的传参都是可以的
#include <stdio.h>
void myswap(int buf) //p是四个字节,所以要用int接收
{
printf ( "the buf is %x\n" , buf);
}
int main()
{
int a = 20;
char *p = "hello world!";
printf("the p is %x\n",p);
myswap(p);
return 0;
}
>>the p is 40068b
>>the buf is 40068b
#include <stdio.h>
void myswap(int buf)
{
printf ( "the buf is %x\n" , buf);
}
int main()
{
int a = 20;
char *p = "hello world!";
char b[10];
printf("the b is %x\n",b);
myswap(b);
return 0;
}
>>the b is xxx..
>>the buf is xxx..
指针函数
主体是函数,返回类型是指针
int* f(int x, int y)
函数指针
首先f是指针,指向一个函数
int (*f)(int x, int y)
输入参数
值传递
如看到类似此种程序:
void fun(int a) //这里是对a进行了一份拷贝,在函数中怎么变都是对副本变
{
a = xxx;
}
int main()
{
int a = 20; //对这里的a没有进行任何修改,这里的a还是不变
fun(a);
printf a==?
}
地址传递
如下程序:
#include <stdio.h>
void swap (int *a,int *b)
{
int c;
c = *a;
*a= *b;
*b=C;
}
int main ()
{
int a = 20;
int b = 30;
int c;
printf ("the a is 8d,the b is %d\n",a,b);
swap(&a, &b); //这里传递的就是a,b的地址
printf ("after swap, the a is %d,the b is %d\n",a,b);
}
连续空间的传递
1、数组 数组名---标签
实参:
int abc[10];
fun(abc);
形参:
void fun(int *p)
2、结构体 结构体变量
struct abc{int a;int b;int c};
struct abc buf;
实参:
fun(&buf);
形参:
void fun(struct abc *a);
更多的是用地址传递的方式
void fun(const char *p) //只读空间,只是为了看看
int a = 12;
char buf[100];
sprintf(buf,"%d",a);
sprintf可以把a格式化转换,打印给buf,多用于格式化字符串处理
字符空间操作模板
void fun(char *p)
{
int i = 0;
while(p[i] != 0){
p[i]的各种操作。。
i++;
}
}
实现strlen函数框架
int strlen(const char *p)
{
int i = 0;
/*错误处理,判断输入参数是否合法*/
if(p==NULL){
//return ....
}
/*内存处理,从头到尾逐一处理*/
while(p[i]){
//对p[i]的各种操作。。
i++;
}
}
void strcpy(char *dest,const char *src)
"" ----> 双引号一般用于初始化const char *
char buf[10] ----> 这种则初始化char *
非字符空间操作模板
结束标志:就是数据的大小、数量(B)字节
int *p unsigned char *p short *p struct abc *p 都是非字符空间操作
我们可以使用:void * 就是数据空间的标识符,可以接收任意类型的指针
void 指针作为函数形参时,可以接受任何类型指针传入
void只是个形参化,最终的操作一定要转为具体类型,如下:
void fun(void *buf,int len)
{
unsigned char *tmp = (unsigned char *)buf; //可以自定义一个tmp临时指针,就操作tmp
for(i=0;i<len;i++){
tmp[i] = xx; xx = tmp[i] //对tmp[i]一些类操作
}
}
int main()
{
struct sensor_data abc;
fun(&abc,sizeof(abc)*1)
}
返回值
基本语法
返回值就是拷贝的过程
返回的类型:基本数据类型、指针类型,数组不能返回
函数返回值只能返回一个数据类型
返回基本数据类型
#include <stdio.h>
int fun(void)
{
return 0x123;
}
int main()
{
int ret;
ret = fun();
printf ("the ret is %x\n",ret);
return 0;
}
>>the ret is 123
#include <stdio.h>
char fun(void) //char类型就只返回一个字节,即23
{
return 0x123;
}
int main()
{
int ret;
ret = fun();
printf ("the ret is %x\n",ret);
return 0;
}
>>the ret is 23
#include <stdio.h>
int fun(void)
{
int a = 0x100;
int *p = &a;
return p; //p是地址,*p不行,*p是里面的内容了
}
int main()
{
int ret;
ret = fun();
printf ("the ret is %x\n",ret);
return 0;
}
>>the ret is 48c8360c
#include <stdio.h>
int fun(void)
{
int a = 0x100;
int *p = &a;
int buf[10];
return buf; //不能返回数组,只能返回地址
}
int main()
{
int ret;
ret = fun();
printf ("the ret is %x\n",ret);
return 0;
}
>>the ret is 0
返回连续空间类型
以下两种方式均可以使a的值发生改变:
int fun1(void); main函数中: int a=0; a = fun1();
void fun2(int *p); main函数中: int a=0; fun2(&a);
void fun2(int **p); main函数中: int *p; fun2(&p);
函数输入参数定义成*p是想改p指向的值,定义成**p是想修改p指向的地址,
指针作为空间返回的唯一数据类型
int *fun():返回类型是 * 的话,一定要考虑它的合法性,必须保证函数返回的地址所指向的空间是合法的。
不是局部变量所在的空间就行
#include <stdio.h>
char *fun(void)
{
char buf[] = "hello world!";
return buf; //buf是局部变量,函数return后buf就被回收掉了
}
int main()
{
char *p;
p = fun(); //p就指向了一个消失的空间
printf("the p is %s\n",p);
return 0;
}
会报警告:
warning: function returns address of local variable(函数返回了一个本地变量的地址)
the p is
甚至回车符都没有打印
另一种情况:
#include <stdio.h>
char *fun(void)
{
return "hello world!"; //字符串常量就是个地址值,返回没问题
}
int main()
{
char *p;
p = fun();
printf("the p is %s\n",p);
return 0;
}
""在常量区,并不会因为函数的返回而消失
>>the p is hello world!
对于函数的使用:
int *fun();
int *p = fun(); //定义一个和返回类型一模一样的地址去接收即可
函数内部如何实现返回连续空间类型
1、使用static修饰:
#include <stdio.h>
char *fun(void)
{
static char buf[] = "hello world!";
return buf; //使用static修饰后,buf就在全局变量的空间,属于数据段,函数return后buf还在
}
int main()
{
char *p;
p = fun();
printf("the p is %s\n",p);
return 0;
}
>>the p is hello world!
2、只读区:就是直接返回字符串,但工程中意义不大
3、堆区,使用malloc申请的区域:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *fun (void)
{
char *s = (char *)malloc(100); //malloc一般都得加强制类型转换
strcpy(s,"hello world");
return s;
}
int main()
{
char *p;
p = fun();
printf("the p is %s\n",p);
free(p); //这里释放p,因为s在函数返回后就消失了
return 0;
}
>>the p is hello world!

浙公网安备 33010602011771号