函数的由来与好处
——以下摘自陈正冲《C语言深度剖析》
其实在汇编语言阶段,函数这个概念还是比较模糊的。汇编语言的代码往往就是从入口开始一条一条执行,直到遇到跳转指令(比如ARM 指令B 、BL 、BX 、BLX 之类)然后才跳转到目的指令处执行。这个时候所有的代码仅仅是按其将要执行的顺序排列而已。后来人们发现这样写代码非常费劲,容易出错,也不方便。于是想出一个办法,把一些功能相对来说能成为一个整体的代码放到一起打包,通过一些数据接口和外界通信。这就是函数的由来。那函数能给我们带来什么好处呢?简单来说可以概括成以下几点: 1、降低复杂性:使用函数的最首要原因是为了降低程序的复杂性,可以使用函数来隐含信息,从而使你不必再考虑这些信息。 2、避免重复代码段:如果在两个不同函数中的代码很相似,这往往意味着分解工作有误。这时,应该把两个函数中重复的代码都取出来,把公共代码放入一个新的通用函数中,然后再让这两个函数调用新的通用函数。通过使公共代码只出现一次,可以节约许多空间。因为只要在一个地方改动代码就可以了。这时代码也更可靠了。 3、限制改动带来的影响:由于在独立区域进行改动,因此,由此带来的影响也只限于一个 或最多几个区域中。 4、隐含顺序:如果程序通常先从用户那里读取数据,然后再从一个文件中读取辅助数据,在设计系统时编写一个函数,隐含哪一个首先执行的信息。 5、改进性能:把代码段放入函数也使得用更快的算法或执行更快的语言(如汇编)来改进这段代码的工作变得容易些。 6、进行集中控制:专门化的函数去读取和改变内部数据内容,也是一种集中的控制形式。 7、隐含数据结构:可以把数据结构的实现细节隐含起来。 8、隐含指针操作:指针操作可读性很差,而且很容易引发错误。通过把它们独立在函数中,可以把注意力集中到操作意图而不是集中到的指针操作本身。 9、隐含全局变量:参数传递。
函数的意义
模块化程序设计
C语言中的模块化
面向过程的程序设计
面向过程是一种以过程为中心的编程思想
首先将复杂的问题分解为一个个容易解决的问题
分解过后的问题可以按照步骤一步步完成
函数是面向过程在C语言中的体现
解决问题的每个步骤可以用函数来实现
声明和定义
程序中的声明可以理解为预先告诉编译器实体的存在,如:变量,函数,等等
程序中的定义明确指示编译器实体的意义
声明和定义并不相同!
例1:test.c
// global.c // int g_var = 0;#include <stdio.h>extern int g_var; //声明外部全局变量int g_varvoid f(int i, int j); //声明函数fint main(){ int g(int x); //声明函数g g_var = 10; f(1, 2); printf("%d\n", g(3)); //声明后的函数、变量就都合法了 return 0;} void f(int i, int j) //函数定义{ printf("i + j = %d\n", i + j);}int g(int x) //函数定义{ return 2 * x + g_var;}
函数参数函数参数在本质上与局部变量相同,都是在栈上分配空间
函数参数的初始值是函数调用时的实参值
例2:
int f(int i, int j){ printf("%d, %d\n", i, j);}int main(){ int k = 1; f(k, k++); printf("%d\n", k); return 0;}
编译运行得
函数参数的求值顺序依赖于编译器的实现!!!上例中f(k,k++)从右向左的话则能说通
C语言中大多数运算符对其操作数求值的顺序都是依赖于编译器的实现的!!!
程序中的顺序点
程序中存在一定的顺序点
顺序点指的是执行过程中修改变量值的最晚时刻
在程序到达顺序点的时候,之前所做的一切操作必须反映到后续的访问中
C语言中的顺序点
1.每个完整表达式结束时,即遇到;时
2.&&,||,?:,以及逗号表达式的每个运算对象计算之后
3.函数调用中对所有实际参数的求值完成之后(进入函数体之前)
例3:
int main(){ int k = 2; int a = 1; k = k++ + k++; //后置的k++中的+1操作会等到遇到;才会执行,所以先是k=2+2,遇到;,两个++才执行,输出6。但是前置的++k会马上执行生效不会等;。 printf("k = %d\n", k); if( a-- && a ) //a--遇到&&,--操作马上生效,后面的a的值会变为0,所以这个if不执行 { printf("a = %d\n", a); } return 0;}
例2中的 f(k, k++),就是由于顺序点的作用
函数的缺省认定
函数定义时参数和返回值的缺省类型为int