重新学习 c 语言(3)- c语言特性(三)函数和程序结构
(三)函数和程序结构
1.函数
函数调用非常依赖编译实现,函数的参数和返回值一般存放在线程堆栈中.
对于c语言,函数都是外部的!(函数中不能包含函数)
重要的一条,函数的参数传递统一为值传递
这一点很重要!
一般来说,在调用一个函数时,参数是放在栈里的(有时候编译器会把参数放到寄存器中,不影响我们讨论),值传递的意思是,编译器会将传递给函数的参数(我这里不打算引入形参和实参的概念,其实或许无助于理解)的值赋值到栈中,这样的处理会使编译简单,也使程序员容易理解.
int AddTen(int aNum)
{
return aNum + 10;
}
int a =100;
int main()
{
int b =AddTen(a);
return 0;
}
调用函数AddTen 时 变量a的值 100 被赋值到栈中,也就是在函数AddTen中 aNum是一个局部变量,值是100.
传值的缺点是明显的,如果参数尺寸很大,则复制会影响性能,而且大多数复制是没有必要的!
另外,如果一个函数有多个返回值怎么办?
有经验的C程序员在传递尺寸大的参数或者需要多个返回值时,会采用传递指针的方法:
比如上面定义的struct String
int getStringLen(struct String *str);
需要注意的一个问题是数组,在c语言中,数组名其实就是数组第一个元素的地址!
数组名作为参数传递,在函数的局部变量中引用的是一个地址,其实该局部变量就是一个指针.
比如 int a[]={1,2,3,4,5};
对a的引用其实是相当于&a[0];仅仅如此而已;
比如函数
int sum(int a[],int aLen)
{
int result = 0;
for (int i=0 ;i<aLen;i++)
{
result +=a[i]
}
return result;
}
调用是这样的 int total = sum(a,5);
对于一个数组,知道其元素类型(int),第一个元素地址&a[0],还有数组长度(5),就能完全操作一个数组了,结合前面讨论的指针的运算特性,就可以用指针方便的操作数组了.
2 程序结构
先简单的说说程序的控制流,
一个程序的运行只有三种控制流:
-
顺序
-
选择
-
循环
其实,只要有if 和goto (汇编里的jmp),就可以实现上面的三种程序控制流.
C语言里表示选择的除了if else 语句 还有 switch case 语句
循环也只有 while for 和 do while 三种语句.(break 和 continue 只是限制性的goto)
因为简单所以K&R中也只是讲了10页的内容
由于c语言是严格的将声明和定义分开的,甚至使用.h来表示声明(不是绝对的),.c文件表示定义.但这样做的优点是明显的.尤其是对于编译器来说.Pascal程序虽然没有明显的区分.h和.c两个文件中,但也通过一个文件中interface和implementation关键字来区分.
一个c程序,就是若干.h的头文件(声明文件)和若干个.c的文件(定义文件)里包含若干个函数和外部变量.就是这样简单.