目录
上一篇复习了字符数组,这一篇我们来复习函数。
说明:我们学过单片机的一般都是有C语言基础的了,网上关于C语言的资料有很多,大家如果对C语言不熟悉的话可以先去详细学一下,再以这篇博文作为复习资料学习。
这篇博文的目的是复习C语言,我们会陆续以30多个编程题作为复习要点,这30多个编程题基本涵盖了C语言所有的内容了,只要你掌握了这30多个编程题,那么你的C语言基本就没什么问题了。
注意:由于本专栏是嵌入式全栈开发专栏,为了我们能熟悉以后实际工作中的开发环境,我们写C语言全部在Linux中的vim编辑器中写,这么做事为了我们能够熟练掌握Linux系统的常用命令以及Linux上的vim编辑器的常用工作命令,以达到对口训练的目的!
vim编辑器的一些工作命令在上一篇博文中已经详细介绍过了,如果不了解可以先去看看。
我们正式开始:
函数
函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。
库函数
别人已经实现好的函数,我们只要安装了对应的库可以直接拿过来用,比如printf strlen等等。
自定义函数
很多时候我们需要实现的功能并没有对应的函数,于是需要自己来实现
函数的格式
函数类型 函数名(形式参数类型说明表)
{
声明部分
执行部分
返回部分
}
例:
int func(int a, int b)//int是函数的类型 func是函数名 a b是形式参数
{
int sum; //声明部分
sum = a + b; //执行部分
return sum; //返回部分
}
参数
形参:即形式参数,定义函数时函数名后面括号中的变量;如果没有定义形参,则表示函数可以接收任意个数的参数,而并非是没有形参。
实参:即实际参数,调用函数时函数名后面括号中的表达式。
实参--传递-->形参(值传递和地址传递)
注意:函数名就是地址,这个地址就是函数的入口地址。
函数调用过程
思考:函数调用过程是在怎么样的?
第一步:通过函数名找到函数的入口地址,然后程序就跳到函数的入口地址;
第二步:给形参分配空间;
第三步:传参(值传递和地址传递(如果是传一维数组,则传递数组名,传的只是首元素的地址,如果是传二维数组名,传的只是数组首行的地址));
第四步:执行函数体;
第五步:返回数据;
第六步:释放空间(栈空间:局部变量)
宏函数
可以把函数定义为宏,在编译的预处理阶段对函数直接展开。
#define PRINT printf(“helloworld\n”) //无参宏函数
调用:PRINT;
#define PRINT(S) printf(“%s\n”, S) //有参宏函数
调用:PRINT(“this is test...”);
宏函数和普通函数的优缺点
宏函数
优点:节省空间、执行效率高;
缺点:编译时间长、没有语法检查、不安全。
比如,#define PRINT(S) printf(“%s\n”, S) 调用:PRINT(1);这样会报警告,因为1和int型,不是字符。如果我们强制转换成char型PRINT((char)1);这样也能编译(没有语法检查),但是运行的时候会报警告:段错误,因为宏函数只是做一个简单的替换,将S替换成1,但是%s获取的空间是给字符串的,它会去1这个地方找字符串,但其实并没有1的地址,因为1的类型是char字符,也就是说内存中根本没有开辟1的空间,所以产生了段错误。
普通函数
优点:节省编译时间、有语法检查、执行更安全;
缺点:需要更多的空间、执行效率不高。
笔试题16
问:以下程序输出的结果是什么?
#define SQR(X) X * X
int main()
{
int m = 1, n = 2;
printf(“%d\n”, SQR(m + n));
return 0;
}
答案是:5
很多人以为是3*3等于9,但并不是,因为宏函数替换的结果是1+2*1+2,由于运算符有优先级,编译器会优先编译2*1=2,,最终输出1+2+2=5。
结论:宏函数最好能加括号尽量加括号,如果#define SQR(X) X * X 加上括号的话就是#define SQR(X) (X) *(X),这样替换后括号还是存在的,结果是(1+2)*(1+2)这样输出才是9。
以上就是这篇内容,如想了解更多,欢迎订阅本专栏!
如有问题可评论区或者私信留言,如果想要进交流群请私信!