main() { intm,n; int k,sum1=0,sum2=0; scanf(\"%d,%d\for(k=1;k<=m;k++) { sum1 += k; } for(k=1;k<=n;k++) { sum2 += k; } printf(\"%d,%d\\n\}这段代码的核心代码是两个for循环,这两个for循环结构完全相同,只是参数不同,运算结果不同,而在这里我们就要把这段几乎相同的代码写两遍 这里就提出了“函数”,函数就是把一些实现一定功能的代码封装起来,一次封装,可以多次调用——重用
二。函数的定义
把实现一定功能的代码封装起来 1).要能描述代码结构
1
C语言重要资料范浩
2).接收外面给它的参数 3).把运算结果返回 4).要给封装起一个名字 1. 函数定义的格式:
返回值类型函数名(形式参数列表) {
函数体 }
标红色的部分叫:函数头
返回值类型:描述函数要返回的运算结果的数据类型
如果函数不需要返回值,返回值类型描述可以用void,也可以直接省略
如果函数有返回值,函数体中就要用return语句,return语句后面要有返回的实际数据(return **;)
Return语句后面返回的实际数据的类型要与描述类型兼容(实际返回的数据可以直接转换成返回值类型描述的类型)
如果函数没有返回值,return语句后面可以什么都不加,直接return;,或者连return语句直接省略
函数名:符合标识符的命名规则 形式参数列表:
形式参数是用来说明函数的参数的形式:参数的类型,参数的个数 格式:参数1的类型参数1的名称,参数2的类型参数2的名称,… 如果函数不需要形式参数,可以用void,也可以直接省略 三。函数调用 1.格式:
函数名(实际参数)
函数名:就是要调用的封装起来的代码所起的名字 实际参数:要传递给函数的实际的数据
可以是变量、常量、表达式、可以是一个函数的调用 实参的个数要和形参的个数一致 类型要兼容(后面解释) 2.调用方式
1)直接作为语句调用,(一般用来调用么有返回值的函数) 2)把函数放入表达式
3)把函数作为另外要给函数的实际参数 函数的定义要放在被调用之前,否则要声明
四。函数声明
样式同函数头,后面直接加分号
作用:告诉编译器,程序中有这么一个函数的定义,但是不在这里 案例:
#include /*2
C语言重要资料范浩
函数声明 */ Print(); /*
函数定义 */
int Add(inta,int b) {
returna+b; } /*
定义函数,求1+2+...+某个整数
某个整数:是需要外界给定的,这就是参数 形式:1个参数,int类型 返回结果:运算结果 什么类型:int */
int Sum(int n) { int k;
int *p=&k; /*定义验证返回值*/ int sum=0;
for(k=1;k<=n;k++) {
sum += k; }
/*如果返回的是char,会直接返回,因为可以直接进行类型转换
如果返回的是一个浮点数,会提示有数据丢失,也可以返回,因为类型兼容*/ return sum; /*会报错
返回的是一个指针int *,无法直接转换成int*/ //return p; }
void main(void) { intm,n; int k,sum1=0,sum2=0,sum3; scanf(\"%d,%d\ /* 调用函数: 调用形式:表达式 把函数的运算结果(返回值)按照表达式完成运算,再赋值给变量
3
C语言重要资料范浩
*/ sum1 = Sum(m); sum2 = Sum(n); sum3 = 2*Sum(n); printf(\"%d,%d,%d,%d\\n\ /* 调用无返回值的方法,直接作为一个语句,后面要加上; */ Print(); } /*
定义无参数的函数 */ Print() {
printf(\"abcd-----------\"); //return; }
练习:课后练习8 #include /*如果题目规定在主函数中显示转换的结果 我们需要把字符数组返回
但是,函数一般不会把在函数内定义的数组以指针的形式返回 函数一般不返回指针或者数组 */
voidPrintStr(int k) {
char s[10]; s[0] = k/1000+0x30; s[1] = ' '; s[2] = k%1000/100+0x30; s[3] = ' '; s[4] = k%100/10+0x30; s[5] = ' '; s[6] = k%10+0x30; s[7] = '\\0'; /* --> s[7] = 0,'\\0'的值就是0*/ printf(\"%s\\n\ }
void main(void) {
4
C语言重要资料范浩
int k; char *p;
scanf(\"%d\PrintStr(k); }
五。函数调用过程中的参数传递
实参传递给形参
函数定义:
Intfun1(inta,intb,int c) 调用的时候: fun1(a1,b1,c1);
实参是按照顺序,逐个传递给形参的
A1的值传递给了a: a1实参要能直接转换成形参a的类型,或者可以兼容 B1的值传递给了b: b1的类型要能转换成形参b的类型,或者可以兼容 C1的值传递给了c:。。。
六。函数的调用过程
函数的调用过程其实是代码的跳转
5
C语言重要资料范浩
当代码中调用一个函数的时候,就是跳转(步骤2,5)到这个函数的第一条语句开始执行,
当函数执行完毕(碰到了return语句,执行到函数的最后一条语句(即使没有return))函数会返回(步骤4,7)调用主调函数,继续执行 函数的内部定义的变量和函数的形参变量,都是在函数被调用的时候分配存储空间。
七、变量的作用域
案例:
#include /*定义全局变量
变量不属于任何函数
全局变量位于程序的全局区域
程序的全局区,是任何函数都可以访问的 全局变量的声明周期:
从程序开始运行开始,到程序运行结束终止 */
int m=10,n=20; /*
函数内定义的变量是局部变量 函数的形参是作为局部变量
6
C语言重要资料范浩
形参的名称可以与实参变量相同,但是不能与函数局部变量名称相同 局部变量的生命周期:
从函数被调用开始,到函数执行结束终止 */
int Sum(intnum) { int k;
int sum=0;
for(k=0;k<=num;k++) { sum+=k; } /*
打印的全局变量*/
printf(\"Sum: %d,%d\\n\return sum; }
intMul(intnum) { int k; intmul=1; for(k=1;k<=num;k++) { mul *= k; } returnmul; }
main() { /* 局部变量与全局变量重名,局部变量在函数内会覆盖全局变量 */ intnum,m,n; scanf(\"%d\ m = Sum(num); n = Mul(num); /*这里输出的是main的局部变量m和n的值,也就是求阶乘和连续加的值,而不是全局变量的值*/ printf(\"main: %d,%d\\n\}
1. 主函数运行到调用Sum之前
7
C语言重要资料范浩
蓝色的区域为Main函数的空间 2.调用Sum期间存储分配
蓝色的区域是main的存储空间,绿色的区域是Sum的存储空间,他们彼此是不能互相访问的,因此变量即使重名,也没有关系,不冲突
主函数中有两个变量与全局变量重名了,在函数内部定义的变量(局部变量)与
8
C语言重要资料范浩
全局变量重名时,会覆盖全局变量
3.调用Sum结束,返回主函数时,存储空间变为:
调用Sum之前的存储空间,Sum所占的绿色的区域被释放了 4. 调用Mul期间的存储
橙色的空间实Mul的存储空间,其实覆盖了刚才Sum的存储空间,这时main的存储空间不变
5.Mul执行结束,回到
6.主函数执行结束
9
C语言重要资料范浩
整个存储空间,包括代码区、常量区、全局区、栈、堆,都被释放掉。
八、函数的参数传递
参数的传递其实是把实参的值复制到形式参数(变量)的空间里 实参传递给形参,函数的返回值的传递 函数能否返回多个值?不行
1.执行完scanf后,用户输入了5;main函数空间内的变量num里面存储了5;
2. 调用Sum函数时,为sum分配存储空间,图中紫色的部分,这时,会把主函数的num的值复制到sum函数的num变量空间中
3.Sum函数执行完毕,还没返回的时候
10
C语言重要资料范浩
4. Sum返回,因为Sum里面有return sum语句
所以程序会在一个临时的存储空间里面存储sum的值(绿色的区域),然后释放Sum的存储空间,根据主函数的语句,把临时空间里面的值赋值给变量m。
九、指针做函数参数
案例:
#include /*指针做函数参数 */
void fun1(int *p,int length) { int k;
for(k=0;k*p = (*p)*2; p++; /*下面的代码也是可行的 */ //p[k] = p[k]*2; } }11
C语言重要资料范浩
/*
用数组做函数形参,也需要传送一个地址过来 但是其实这里的a也是一个变量,也可以做运算, */
void fun2(int a[],int length) { int k;
for(k=0;ka[k] = a[k]*2; /*下面的代码也是可行的*/ //*a = (*a)*2; //a++; } }main() { int a[5] = {1,2,3,4,5}; int k; for(k=0;k<5;k++) { printf(\"%d,\ } printf(\"\\n\"); fun1(a,5); for(k=0;k<5;k++) { printf(\"%d,\ } printf(\"\\n\"); fun2(&a[0],5); for(k=0;k<5;k++) { printf(\"%d,\ } printf(\"\\n\"); }
12
C语言重要资料范浩
十。返回值为指针的函数:
案例: /*
函数返回值为指针的时候,不要试图用指针返回一个局部变量的值 函数一旦执行完毕,局部变量都释放了
即使返回了地址,也已经无法访问这块存储区域 */
int *fun1(int k) {
int b[5] = {8,4,6,8,10}; int m; for(m=0;m<5;m++) { b[m] = b[m]+k; } return b; }
main() { int *p; int k; p = fun1(2); /* 调用函数之后打印结果, */ for(k=0;k<5;k++)
13
C语言重要资料范浩
}
{
printf(\"%d,\}
练习:
统计字符串长度和统计字符串中字母和数字的个数 #include intnumC=0,numN=0; /*
定义一个函数,统计字符串的长度 */
intstrLen(char *ch) {
int length=0; while(*ch !='\\0') {
length++; ch++; } return length; } /*
统计字符串中字母和数组的个数
函数要给出两个结果:字母的个数、数字的个数 因此不能用函数的返回值给出
把主函数的变量以地址的形式传递给函数 在函数中改变变量的值 */
voidstrNandC(char *ch,int *n1,int *n2) {
*n1 = 0; *n2 = 0; while(*ch !='\\0') { if(*ch>='0'&&*ch<='9') { (*n1)++; } else { (*n2)++;
14
C语言重要资料范浩
} ch++; } } /*
当函数需要给出多个结果的时候 还可以使用全局变量 */
voidstrLL(char *ch) {
while(*ch !='\\0') { if(*ch>='0'&&*ch<='9') { numN++; } else { numC++; } ch++; } }
main() {
char c[20]; int l;
int num1,num2; scanf(\"%s\ //gets(c); l = strLen(c); printf(\"%d\\n\
strNandC(c,&num1,&num2); printf(\"%d,%d\\n\strLL(c);
printf(\"%d,%d\\n\}
15