嵌入式c语言鼠标,嵌入式Linux C语言(三)——指针与函数(示例代码)

本文详细介绍了C语言中指针与函数指针的应用,包括程序栈和堆的概念、通过指针传递和返回数据的方法、函数指针的声明和使用,以及如何传递和返回函数指针。强调了正确使用函数指针以避免内存泄漏和数据损坏的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

嵌入式Linux C语言(三)——指针与函数

指针对函数的功能有巨大的贡献,指针能够将数据传递给函数,并且允许函数对数据进行修改。指针对于函数的作用主要有两方面:将指针传递给函数和声明函数指针。

一、程序的栈和堆

程序的栈和堆是C语言程序运行的运行时元素。

1、程序栈

程序栈是支持函数执行的内存区域,通常和堆共享一块内存区域,通常程序栈占据内存区域的下部,堆用内存区域的上部。程序栈存放栈帧,栈帧存放函数参数和局部变量。调用函数时,函数的栈帧被推倒栈上,栈向上长出一个栈帧,当函数终止时,函数的栈帧从程序栈上弹出,栈帧所使用的内存不会被清理,但可能会被推倒程序栈上的另一个函数的栈帧所覆盖。动态分配的内存来自于堆,堆向下生长,随着内存的分配和释放,堆中会布满碎片。尽管堆是向下生长的,但只是一个大体方向,实际内存可能分配在堆上的任意位置。

2、栈帧

栈帧的组成:

A、返回地址

函数完成后要返回的程序内部地址

B、局部数据存储

为局部变量分配的内存

C、参数存储

为函数参数分配的内存

D、栈指针和基指针

运行时系统用来管理栈的指针

栈指针通常指向栈的顶部,基指针(帧指针)通常存在并指向栈帧内部的地址

ARM的栈帧布局如下:

b53d9f45a104741c0ec2e5d5a0022945.png

main stack frame为调用函数的栈帧,func1 stack frame为当前函数(被调用者)的栈帧,栈底在高地址,栈向下增长。图中FP就是栈基址,指向函数的栈帧起始地址;SP则是函数的栈指针,指向栈顶的位置。ARM压栈的顺序依次为当前函数指针PC、返回指针LR、栈指针SP、栈基址FP、传入参数个数及指针、本地变量和临时变量。如果函数准备调用另一个函数,跳转之前临时变量区先要保存另一个函数的参数。

二、通过指针传递和返回数据

1、用指针来传递数据

函数中用指针变量作为参数来传递数据可以在函数中修改数据,如果不需要修改数据,则将指针变量限制为const类型。典型的函数应用如下:

char *strcpy(char *dest, const char *src);

如果函数用值传递数据,则在函数中将无法修改数据。

2、返回指针

返回指针需要返回的类型是某种数据类型的指针。

从函数返回指针存在的问题:

A、返回未初始化的指针

B、返回指向无效地址的指针。

C、返回局部变量的指针

D、返回指针但是没有释放内存

从函数返回动态分配的内存,在使用完内存后必须释放,否则会造成内存泄漏。

函数返回局部数据的指针或局部变量是错误的,函数返回后,局部数据所在的栈帧将会被弹出程序栈,保存在栈帧上的数据极易被后续调用函数的栈帧覆盖。通过将局部变量声明为static类型,可以将局部数据、变量的作用域限定在函数内部,但分配在栈外(data数据段),可以避免局部数据、变量被其他函数的栈帧覆盖。

3、传递指针的指针

将指针传递给函数时,传递的是指针变量的值,如果需要修改原指针而不是指针变量的副本,就需要传递指针的指针。

三、函数指针

函数指针是持有函数地址的指针变量,指向函数地址的指针变量。

1、函数指针的声明

函数指针变量的声明一般格式为;

数据类型(*指针变量名)();

Void * fun(void);//返回void*类型指针的函数

void (*pFun)(void);//函数指针

void *(*pFun)(void *, void *);//函数指针

typedef void(*Fun)(void);//定义一个函数指针类型Fun

Fun pfun = fun;//将函数fun的地址赋值给函数指针pfun

Fun pfun = &fun;//将函数fun的地址赋值给函数指针pfun

void *(*pf[5])(void);//函数指针数组

2、函数指针的使用

调用函数指针的一般流程:

A、定义函数指针变量

B、被调函数的入口地址(函数名)赋予该函数指针变量

C、用函数指针变量形式调用函数

D、函数指针变量形式调用函数的一般形式为:(*指针变量名) (实参列表)

函数调用和函数指针变量形式调用函数方式如下:

fun();//函数调用

(*fun)();//函数指针变量形式调用函数

(**fun)();//函数指针变量形式调用函数

pfun();//函数指针形式调用函数

(*pfun)();//函数指针形式调用函数

(**pfun)();//函数指针形式调用函数

函数指针变量不能进行算术运算,函数指针的偏移是毫无意义的。函数调用中(*指针变量名)的两边的括号不可少,其中的*不应该理解为求值运算,*只是一种表示符号。

3、传递函数指针

将函数指针变量作为函数的参数进行传递,使程序代码变得更加灵活。

int add(int num1, int num2)

{

return num1 + num2;

}

int sub(int num1, int num2)

{

return num1 - num2;

}

typedef int (*pFun)(int, int);

int compute(pFun operation, int num1, int num2)

{

return operation(num1, num2);

}

compute(add, 5, 6);

compute(sub, 10,2);

add、sub函数的地址被传递给compute函数作为参数,compute使用add、sub函数的地址调用对应的操作。

4、返回函数指针

返回函数指针需要把函数的返回类型声明为函数指针。

int add(int num1, int num2)

{

return num1 + num2;

}

int sub(int num1, int num2)

{

return num1 - num2;

}

typedef int (*pFun)(int, int);

pFun select(char opcode)

{

switch(opcode)

{

case‘+’:

return add;

case‘-’:

return sub;

}

}

int evaluate(char opcode, int num1, num2)

{

pFun operation = select(opcode);

return operation(num1, num2);

}

evaluate(‘+’, 5, 6);

evaluate(‘-’, 10, 6);

通过输入一个字符和两个操作数就可以进行相应的计算

5、函数指针数组使用

函数指针数组可以基于某些条件选择要执行的函数,函数指针数组声明如下:

第一种声明:

typedef int (*operation)(int, int);

operation operations[128] = {NULL};

第二种声明:

int (*operations[128]) (int, int) = {NULL};

函数指针数组声明后可以将某一类操作函数赋值给数组。

operations[‘+’] = add;

operations[‘-’] = sub;

int evaluate_array(char opcode, int num1, num2)

{

pFun operation = operations[opcode];

return operation(num1, num2);

}

evaluate_array(‘+’, 6 ,9);

6、函数指针转换

将指向函数的指针变量转换为其它类型的指针变量。无法保证函数指针和数据指针相互转换后正常工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值