引言
1.c程序结构
c程序有很多源程序文件
源程序文件中有预处理命令,全局变量声明和很多函数(一个程序文件只能有一个main函数,程序总是从main函数开始执行的)(在程序运行过程当中,由主函数调用其他函数,其他函数可以相互调用)
函数又有函数首部和函数体
函数体又有局部变量和执行语句
2.函数的分类
(1)系统函数,即库函数(标准函数):可直接使用
(2)用户自己定义的函数(自定义函数)
库函数
C++常用的有数学计算i函数,字符串函数,标准输入输出函数等
如:sin(alpha) strlen("Hello") getchar() putchar() scanf() time()
当用户使用任一库函数时 ,在程序中必须包含相应的头文件,如#include<iostream> #include<cmath> #include<cstring> #include<time,h>
自定义函数
可以用于定义也重用的代码以及组织和简化编码
例如需要分别计算1-10,20-35,100-130的整数的和,可以编写以下代码
重复
int z=0,i,q=0,a=0;
for(i=1;i<=10;i++){
z+=i;}
for(i=20;i<=35;i++){
q+=i;}
for(i=100;i<=130;i++){
a+=i;}
函数的定义和调用
通过定义和调用函数使得函数不必重复编写
1.函数的定义:函数名称,参数,返回值类型以及函数的组成
定义函数的语法: 类型说明 函数名(形式参数列表说明,,,,) //函数头
{
函数体
}
看一个例子如何定义函数并调用一个函数
int sum(int n1,int n2){
int result=0;
for(i=n1;i<=n2;i++)
result+=i;
return result;
}
int main()
{
cout<<"输出1-10的和"<<sum(1,10)<<endl;
cout<<"输出20-35的和"<<sum(20,35)<<endl;
cout<<"输出100-130的和"<<sum(100,130)<<endl;
return 0;
}
函数可以返回一个值,返回值的类型是函数返回值的数据类型:有些函数只是完成某些要求的操作,而不返回值,在这种情况下返回类型是void。
形参:函数参数列表称为形式参数。
实参:当调用函数时,就给参数传一个值,这个值称为实际参数。
参数列表:指明函数中参数的类型,顺序和个数。
函数类型说明:是指函数返回值的数据类型。
参数是可选的,也就是说函数可以不包含参数的(无参函数)(有参函数)
函数中包括一个函数体,是执行函数语句的集合,定义了该函数该干什么。
注意:在函数头中,如果是有参函数,需要对每个函数进行独立的数据类型声明。
int max(int n1,int n2) //正确
int max (int n1,n2) //错误
2.函数的调用
根据函数是否有返回值,调用函数有两种途径。
如果返回一个值:int larger=max(3,4)
int max(int n1,int n2){
int result;
if(n1>n2)
result=n1;
else
result=n2;
return result;
}
large==result n1=3 n2=4
如果函数返回void(不带返回值的函数,不需要return语句,但return语句能用于终止函数执行并返回到函数的调用处),对函数的调用必须是一条语句。
void printfmarker(char c,int count)
{
for(int i=0;i<count;i++)
cout<<c;
cout<<'\n';
}
void printgrade(double cj){
if(cj>100||cj<0)
return; //没有返回值
else if(cj>=90)
cout<<cj<<'A'<<endl;
else if(cj>=80)
cout<<cj<<'B'<<endl;
else if(cj>=70)
cout<<cj<<'C'<<endl;
else if(cj>=60)
cout<<cj<<'D'<<endl;
else
cout<<cj<<'F';
}
int main(){
printgrade(68);
return 0;
}
提醒(1)在函数调用时,无论有无参数传递,调用函数时函数名后面一定要有括号
(2)实参前面不需要参数类型说明,形参前面必须有类型说明。
当程序调用一个函数时,程序控制就转移到被调用的函数。当执行到return语句或者时执行到表示这个函数结束的右括号那里时,被调用函数将程序控制返还给被调用者。
注意:对于带返回值的函数来说,return语句是必须的。一个函数中可以有一个以上的return语句,执行到哪一个return语句,哪一个return语句起作用。return语句可以是一个表达式,函数先计算表达式后再返回值。
为了更好的区分void和带返回值的函数
void函数
void printgrade(double cj){
if(cj>100||cj<0)
return; //没有返回值
else if(cj>=90)
cout<<cj<<'A'<<endl;
else if(cj>=80)
cout<<cj<<'B'<<endl;
else if(cj>=70)
cout<<cj<<'C'<<endl;
else if(cj>=60)
cout<<cj<<'D'<<endl;
else
cout<<cj<<'F';
}
int main(){
printgrade(68);
return 0;
}
带返回值的函数
char getgrade(double cj){
if(100>=cj&&cj>=90)
return 'A';
else if(cj>=80)
return 'B';
else if(cj>=70)
return 'C';
else if(cj>=60)
return 'D';
else
return 'E';
}
int main()
{ cout<<getgrade(95);
return 0;
}
通过传值进行参数传递
通过传值的方式将实参传递给形参
调用函数时,需要提供实参,它们必须与函数定义中所对应的形参次序和数量上匹配,在类型上兼容。(类型兼容是指不需要经过显式的类型转换,实参的值可以传给形参,如int型的实参传给double型实参。)
按值传递:实参的值传给形参。无论形参在被调用函数中是否改变,其对应的实参变量在调用函数中都不受影响。
按值传递例子
void zj(int n){
n++;
cout<<"输出n的值"<<n;
}
int main(){
int x=1;
cout<<"输出x的值"<<x<<endl;
zj(x);
cout<<"输出x的值"<<x<<endl;
return 0;
}
即使将main函数中的变量x改名为n,结果仍不受影响。实参和形参是否同名没有任何区别。
形参是函数中具有自己存储空间的局部变量,局部函数是在调用函数时分配的,当函数返回到调用者后它就消失了。
说明:(1)在未出现函数调用时,形参并不占内存的存储单元,只有在函数开始调用时,形参才被分配内存空间,并且调用结束后,形参占用的内存单元被释放。
(2)实参对形参的传递是“值传递”,单向传递,在内存中实参和形参分别占不同的单元。
(3)形参只作用于被调函数,可以在其他的函数中使用相同的变量名。
函数先定义后使用
1.被调用函数的定义在主调函数之前的情况
2.被调用函数的定义在主调函数之后的情况
int main()
{float a,b,c;
float max(float n1,float n2);
cin>>a>>b;
c=max(a,b);
cout<<c;
return 0;}
float max(float n1,float n2){
float m;
m=(n1>n2)?n1:n2;
return m;
}
定义是一个完整的函数单元,而原型说明仅仅是说明函数返回值及形参的类型。
3.使用库函数,必须在使用之前包括相应的头文件,一般在文件一开始之处。
模块化代码
使用函数减少冗杂的代码,提高代码的复用性。
#include<iostream>
using namespace std;
int gys(int n1, int n2) {
int k = 1;
int t = 2;
while (t <= n1 && t <= n2) {
if (n1 % t == 0 && n2 % t == 0)
k = t;
t++;
}
return k;
}
int gbs(int n1, int n2) {
int t = 1;
while (t % n1 != 0 || t % n2 != 0) {
t++;
}
return t;
}
int main() {
int x, y;
cin >> x >> y;
cout << gys(x, y) << " " << gbs(x, y);
return 0;
}
该程序体现(1)模块化编程思想,每个函数具有一个独立的功能,而不是将所有的代码都写在主函数中。(2)将其他函数和主函数中的其他代码分隔开,这样会使得函数逻辑更加清晰而且也增加了程序的可读性。(3)每个函数的错误就限定在该函数中,这样缩小了调试的范围。(4)其他程序中可以重复使用这些功能函数。
阶段性提醒
1.形参前面不要忘记类型说明。
2.带返回值的函数必须通过return返回一个于函数类型兼容的值。
3.return语句可以是一个值或者是一个表达式,函数先计算表达式后再返回值。
4.void类型函数return可有可无。
5.调用函数时,需要提供实参,它们必须与函数定义中所对应的形参次序和数量上匹配,在类型上兼容。
6.函数要先定义后使用,如果出现被调用函数的定义在主调函数之后的情况,要在调用前添加函数声明。
变量的定义域
变量的定义域是指程序中的变量在哪一个区间内有效,即在哪一个区间内可以使用或者引用该变量。
变量的定义域取决于变量定义的位置。
在函数中定义的变量称为局部变量,在函数外定义的变量称为全局变量。
在一般意义上,在块内定义的变量称为局部变量。局部变量的作用域从声明变量的地方开始,直到包含该变量的块结束为止。
函数的形参也是局部变量,其作用域覆盖整个函数。
全局变量的作用域从声明变量的地方开始,直到该文件结束为止(一个文件一般是由一个或很多个函数构成的)。
{}之间语句就称为一个块。
局部变量的定义域
一个块内的变量
不同函数的同名变量没有任何关系,各自占有独立的内存空间。
具有块作用域的变量在其作用域内,将屏蔽包含在本块中其它块中的同名标识符,即:变量名相同,局部更优先。
同一作用域不能重复定义同名变量。
文件作用域(全局变量作用域)
当局部变量与全局变量同名时,局部变量优先。
全局变量和静态局部变量如果未初始化,系统自动赋值为0。
在块作用域内可通过作用域运算符::来引用与局部变量同名的全局变量。
存储类型
外存:程序
内存:程序区(存放程序代码),静态存储区,动态存储区。(存放变量)
如果变量存储在静态存储区,那么变量一直保存到程序结束。
动态存储:在程序运行期间根据需要分配存储空间,函数结束后立即释放空间。若一个函数在程序中被调用多次,则每次分配单元有可能不同。 动态局部变量
静态存储:在程序运行期间有固定的存储空间,直到程序运行结束。 全局变量和静态局部变量
局部变量:
(1)动态局部变量(auto):其作用域的函数或复合语句结束时,空间被程序收回。动态局部变量未赋值时,其值为随机值。
(2)静态局部变量(static):其作用域的函数或复合语句内,程序执行到静态局部变量时,为其在静态区开辟存储空间,该空间将一直被保留,直到程序结束。静态局部变量未赋值时,系统自动赋值为0。
在函数中的定义形式 :static int a;只赋一次初值,内存一旦开辟空间,就不会释放,控件之一直保留。
函数的嵌套调用
C语言中,所有函数都是平行独立的,无主次,相互包含。函数可以嵌套调用,不可嵌套定义。
定义过程中也可以调用函数。(直接递归和间接递归)
必须要有递归结束条件(函数用if ,else)
举例:计算1+2+3+......+i;
#include<iostream>
using namespace std;
int main() {
int sum(int);
int i = 5;
cout << sum(i) << endl;
return 0;
}
int sum(int i) {
int a;
if (i == 1)
return 1;
else
a = i + sum(i - 1);
return a;
}