《【教学课件】第一讲C语言复习.ppt》由会员分享,可在线阅读,更多相关《【教学课件】第一讲C语言复习.ppt(105页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第一讲 C语言复习C+C+语言程序设计语言程序设计杨万扣杨万扣导航与控制研究所导航与控制研究所东南大学自动化学院东南大学自动化学院1.1.考试说明考试说明2.2.推荐教材推荐教材3.C3.C语言简述语言简述4.VC4.VC编译器编译器5.C5.C程序事例程序事例6.6.注意事项注意事项提纲提纲考试说明考试说明l考核方式考核方式平时过程化考核平时过程化考核40%,一般,一般5个个个人项目个人项目项目项目(团队项目团队项目)30%,通常为,通常为1个个团队项团队项目目期末考试期末考试30%通常为通常为5题题上机题目。前上机题目。前5题选题选4题,注题,注重基本算法和基础能力;最后重基本算法和基础能
2、力;最后2题选题选1题,题,注重考查学生的综合运用能力,多方案注重考查学生的综合运用能力,多方案选择能力。选择能力。推荐教材推荐教材新标准新标准C+程序设计教程程序设计教程C+编程思想编程思想,C+Primer 深度探索深度探索C+对象模型对象模型Effective C+,More effective C+编程规范文档编程规范文档(高质量高质量C+编程编程)数据结构数据结构+算法设计算法设计典型案例典型案例 大数据与机器学习大数据与机器学习C是面向过程的语言它真正提供的只有宏、指针、结构、数组和函数结构化语言重点在于算法和数据结构 首要考虑,是如何通过一个过程,对输入(或环境条件)进行运算处理
3、得到输出 (或实现过程(事务)控制)C C语言概述语言概述C C提供了大量的库函数:提供了大量的库函数:输入输出函数:输入输出函数:printf(),scanf(),printf(),scanf(),动态内存分配函数:动态内存分配函数:malloc(),free(),malloc(),free(),内存管理:内存管理:memset(),memcpy(),memset(),memcpy(),.C C语言概述语言概述C语言知识巩固和补充语言知识巩固和补充l输入输出输入输出l位运算位运算l函数函数l指针和动态内存分配指针和动态内存分配l命令行参数命令行参数lC C语言标准库函数语言标准库函数VCVC
4、编译器编译器VC 6.0VS2010VS2015VS2015使用的是新C标准 C11,#include int main()int i;printf(Hello!n);return 0;C语言程序,由函数和变量组成函数包含一些语句,指定要执行的计算操作变量存储计算过程中使用的值1.编译2.链接3.生成可执行文件.exe C C语言概述语言概述-例子例子1.main 函数,通常函数的命名没有限制,但函数,通常函数的命名没有限制,但main是一个特殊的函数名是一个特殊的函数名-每个程序都从每个程序都从main函数开始执函数开始执行,即每个程序都必须有且仅有一个行,即每个程序都必须有且仅有一个mai
5、n函数函数2.#include 用于告诉编译器在本程序用于告诉编译器在本程序中包含标准输入中包含标准输入输出库的信息输出库的信息#include void main()float len,pi;float lower,upper,step,cur;pi=3.1415;lower=1.0;upper=5.0;step=1.0;cur=lower;while(lower=upper)len=2*pi*cur;printf(“r=%3.0f,len=%6.0fn”,cur,len);cur=cur+step;whilewhile控制语句控制语句常量定义改成宏定义常量定义改成宏定义C C语言例子语言例
6、子#include#define PI 3.1415void main()float len;float lower,upper,step,cur;lower=1.0;upper=5.0;step=1.0;cur=lower;while(lower=upper)len=2*PI*cur;printf(“r=%3.0f,len=%6.0fn”,cur,len);lower=lower+step;C C预处理器预处理器三个常用的预处理器指令是三个常用的预处理器指令是:(1)#include#include#include“文件名文件名”这两种形式查找路径方法不一样这两种形式查找路径方法不一样(2)
7、#define#define 名字名字 替换文本替换文本(3)条件包含条件包含#if#endif(1)不带参数不带参数#define forever for(;)/*无无限循环限循环*/(2)不不带参数的宏定义通常用于为程序中的常量取一带参数的宏定义通常用于为程序中的常量取一个名字,称为符号常量。格式:个名字,称为符号常量。格式:#define 标识符标识符 替换文本替换文本 如如:#define PI 3.14159C C预处理器预处理器-宏定义宏定义含义清楚,提高了程序的可读性。含义清楚,提高了程序的可读性。在需要改变一个常量时能做到在需要改变一个常量时能做到“一改全改一改全改”用用def
8、ine定义宏是定义宏是C语言的习惯语言的习惯,在,在C+中有更好的中有更好的解决方案解决方案.用用#define定义符号常量的定义符号常量的问题问题 所定义的符号常量所定义的符号常量无法无法进行进行类型检查类型检查#define的处理只是简单的字符串的替换,可能会的处理只是简单的字符串的替换,可能会引起一些意想不到的错误引起一些意想不到的错误C+建议用建议用const定义符号常量定义符号常量const =;如:如:const double PI=3.1415926;C C预处理器预处理器-宏定义宏定义(3)带参数带参数#define max(A,B)(A)(B)?(A):(B)使用宏使用宏ma
9、x 看起来象函数调用,但宏调用看起来象函数调用,但宏调用直接直接将文将文本本替换替换文本插入到代码中文本插入到代码中但也存在但也存在问题问题:max(i+,j+);/*错错*/好处好处是:避免函数调用的开销是:避免函数调用的开销#undef 指令取消名字的宏定义,可以避免后续的指令取消名字的宏定义,可以避免后续的宏调用宏调用C C预处理器预处理器-条件包含条件包含(1)使用条件语句对预处理本身进行控制,这种条件语使用条件语句对预处理本身进行控制,这种条件语句的值是在预处理的执行过程中进行计算句的值是在预处理的执行过程中进行计算(2)利利用计算得到的条件值选择性地包含不同的代码用计算得到的条件值
10、选择性地包含不同的代码#if SYSTEM=SYSV#define HDR“sysv.h”#elif SYSTEM=BSD#define HDR“bsd.h”#else#define HDR“default.h”#endif#include HDR#ifndef HDR#define HDR#endif一般预编译器常一般预编译器常量都是大写量都是大写#include using namespace std;#define DEBUGvoid main()#ifdef DEBUG couta;#ifdef DEBUG coutinput int:aendl;#endif (1)如果如果没有定义没
11、有定义DEBUG宏宏实际被编译的程序代码如下:实际被编译的程序代码如下:#include using namespace std;void main()int a;cina;(2)如果如果定义定义DEBUG宏宏实际被编译的程序代码如下:实际被编译的程序代码如下:#include using namespace std;#define DEBUGvoid main()couta;coutinput int:aendl;(1)编编译译C+程序时,编译器自定义了一个预处理器程序时,编译器自定义了一个预处理器名字名字,_cplusplus#ifdef _cplusplus .#endif(2)编编译译
12、C程序时,编译器自定义名字程序时,编译器自定义名字_STDC_(3)_cplusplus 和和 _STDC_ 不会同时定义不会同时定义#include using namespace std;void main()#ifdef _cplusplus couta;#ifdef _cplusplus coutinput int:aendl;#endif 注释注释有两种方式有两种方式(1)/*我爱我家我爱我家*/(2)/我爱我家我爱我家 (C风格风格)(3)注释是写给人看的,而不是写给计算机的注释是写给人看的,而不是写给计算机的。注释注释 可以概括程序算法,标识变量意义,讲解难懂的代可以概括程序算法
13、,标识变量意义,讲解难懂的代码。码。添加注释是一种好的编程习惯添加注释是一种好的编程习惯注释注释 不会增加程序的可执行代码的长度。不会增加程序的可执行代码的长度。在代码生成以前,编译器会将注释从程序中剔除掉在代码生成以前,编译器会将注释从程序中剔除掉输入输入/输出输出(1)C语言输入输出函数:语言输入输出函数:printf(),scanf(),(2)必须包含相关的系统头文件必须包含相关的系统头文件(3)C+采用的是采用的是 cin,cout(4)必须包含相关的系统头文件必须包含相关的系统头文件(5)C语言文本输入输出函数:语言文本输入输出函数:fprintf(),fscanf(),(6)C+文
14、本输入输出,文本输入输出,ofstream outfile(“name-of-file”);ifstream infile(“name-of-file”);需要包含头文件需要包含头文件#include变量变量n变量变量:为我们提供了一个有名字的为我们提供了一个有名字的内存存储内存存储区区,可以通过程序对其进行读、写和处理。,可以通过程序对其进行读、写和处理。C+中每个符号都与一个特定的中每个符号都与一个特定的数据类型数据类型相关联,这个相关联,这个类型类型决定了相关内存的决定了相关内存的大小大小、布局布局、能够存储在该内存中的值得范围以、能够存储在该内存中的值得范围以及可以应用其上的操作集。及
15、可以应用其上的操作集。数据值数据值:(对象的右值,被读取的值对象的右值,被读取的值)地址地址:(在内存中的地址,又称为左值在内存中的地址,又称为左值)C C语言的输入输出语句(教材语言的输入输出语句(教材P282P282)#include#include scanf()scanf()将输入读入变量将输入读入变量 printf()printf()将变量内容输出将变量内容输出scanf()scanf()语句(函数语句(函数)int scanf(const char*,.);int scanf(const char*,.);参数可变的函数参数可变的函数第一个参数第一个参数是格式字符串,是格式字符串,
16、后面的参数后面的参数是变量的地址,是变量的地址,函数作用是按照第一个参数指定的格式,将数据读入函数作用是按照第一个参数指定的格式,将数据读入后面的变量后面的变量参数可变的函数的参考阅读参数可变的函数的参考阅读(不要求掌握)不要求掌握)scanf 返回值返回值 0 成功读入的数据项个数;成功读入的数据项个数;0 没有项被赋值;没有项被赋值;EOF 第一个尝试输入的字符是第一个尝试输入的字符是EOF(结束结束)(对某些题,返回值为(对某些题,返回值为EOF可以用来判断输入可以用来判断输入数据已经全部读完)数据已经全部读完)printf()printf()语句(函数语句(函数)int printf(
17、const char*,.);int printf(const char*,.);参数可变的函数参数可变的函数第一个参数第一个参数是格式字符串,是格式字符串,后面的参数后面的参数是待输出的变是待输出的变量,函数作用是按照第一个参数指定的格式,将后面量,函数作用是按照第一个参数指定的格式,将后面的变量在屏幕上输出的变量在屏幕上输出 返回值返回值:成功打印的成功打印的字符数字符数;返回返回负负值为值为出错出错%d d 读入或输出读入或输出intint变量变量%c c 读入或输出读入或输出charchar变量变量%f f 读入或输出读入或输出floatfloat变量变量%s s 读入或输出读入或输出
18、char*char*变量变量%lflf 读入或输出读入或输出double double 变量变量%e e 以科学计数法格式输出数值以科学计数法格式输出数值%x x 以十六进制读入或输出以十六进制读入或输出 int int 变量变量%I64dI64d 读入或输出读入或输出 _int64 _int64 变量变量(64(64位整数)位整数)%p p 输出指针地址值输出指针地址值%.5lf.5lf 输出浮点数,精确到小数点后输出浮点数,精确到小数点后5 5位位格式字符串里的格式控制符号:#include#include int main()int main()int a;int a;char b;ch
19、ar b;char c20;char c20;double d=0;double d=0;float e=0;float e=0;int n=int n=scanfscanf(%d%c%s%lf%f,&a,&b,c,&d,&e);(%d%c%s%lf%f,&a,&b,c,&d,&e);printfprintf(%d%c%s%lf%e%f%d,a,b,c,d,e,e,n);(%d%c%s%lf%e%f%d,a,b,c,d,e,e,n);return 0;return 0;int n=scanf(%d%c%s%lf%f,&a,&b,c,&d,&e);printf(%d%c%s%lf%e%f%d,a
20、,b,c,d,e,e,n);input:123a teststring 8.9 9.2output:123 a teststring 8.900000 9.200000e+000 9.200000 5input:123ateststring 8.9 9.2output:input:123 a teststring 8.9 9.2output:123 a teststring 8.900000 9.200000e+000 9.200000 5123 a 0.000000 0.000000e+000 0.000000 3#include int main()int a,b;char c;char
21、s20;long long n=9876543210001111LL;scanf(%d%c,%s%x%I64d,&a,&c,s,&b,&n);printf(%d%x%u%s%p%x%d%I64d,a,a,a,s,s,b,b,n);return 0;input:output:#include#include int main()int main()char*s;char*s;scanf(%s,s);scanf(%s,s);return 0;return 0;错在何处?错在何处?常见错误:错在错在 s s 不知道指向何处,往其指向的地方写入数据,不知道指向何处,往其指向的地方写入数据,不安全不安全
22、char*gets(char*s);char*gets(char*s);从标准输入读取一行到字符串从标准输入读取一行到字符串s s如果如果成功成功,返回值就是,返回值就是 s s 地址地址如果如果失败失败,返回值是,返回值是 NULLNULL可以根据返回值是可以根据返回值是 NULLNULL判定输入数据已经读完判定输入数据已经读完调用时要确保调用时要确保 s s 指向的缓冲区足够大,否则可能发生指向的缓冲区足够大,否则可能发生内存访问错误内存访问错误读取一行:C+11标准剔除了gets,替换的是gets_s()#include#include int main()int main()char
23、s200;char s200;char*p =char*p =getsgets(s);/gets_s(s,200);(s);/gets_s(s,200);printf(%s:%s,s,p);printf(%s:%s,s,p);return 0;return 0;input:input:Welcome to Beijing!Welcome to Beijing!读取一行:output:output:Welcome to Beijing!:Welcome to Beijing!Welcome to Beijing!:Welcome to Beijing!int sscanf(const char*
24、buffer,const char*int sscanf(const char*buffer,const char*format,address,.);format,address,.);和和scanfscanf的区别在于,它是从的区别在于,它是从bufferbuffer里读取数据里读取数据int sprintf(char*buffer,const char*format,int sprintf(char*buffer,const char*format,argument,.);argument,.);和和printfprintf的区别在于,它是往的区别在于,它是往bufferbuffer里输
25、出数据里输出数据sscanf 函数和 sprintf函数#include int main()int a,b;char c;char s20;char szDest200;_int64 n=9876543210001111;sscanf(szSrc,%d%c,%s%x%I64d,&a,&c,s,&b,&n);sprintf(szDest,%d%x%u%s%p%x%d%I64d,a,a,a,s,s,b,b,n);printf(%s,szDest);return 0;output:位运算(教材P28)有时我们需要对某个整数类型变量中的有时我们需要对某个整数类型变量中的某一位某一位(bitbit)进
26、行操作)进行操作,比如,判断某一位是否为,比如,判断某一位是否为1 1,或,或只改变其中某一位,而保持其他位都不变。只改变其中某一位,而保持其他位都不变。C/C+C/C+语语言提供了言提供了“位运算位运算”的操作,能够做到类似的操作。的操作,能够做到类似的操作。C/C+C/C+语言提供了六种位运算符来进行位运算操作:语言提供了六种位运算符来进行位运算操作:&按位与按位与|按位或按位或 按位异或按位异或 取反取反 右移右移按位与 按位与运算符“&”是双目运算符。其功能是将参与运算的两操作数各对应的二进制位进行与操作,只有对应的两个二进位均为1时,结果的对应二进制位才为1,否则为0。例如:表达式例
27、如:表达式“21&18”21&18”的计算结果是的计算结果是1616(即二进制数即二进制数10000)10000),因为:,因为:21 21 用二进制表示就是:用二进制表示就是:0000 0000 0000 0000 0000 0000 0001 01010000 0000 0000 0000 0000 0000 0001 0101 18 18 用二进制表示就是用二进制表示就是:0000 0000 0000 0000 0000 0000 0001 0010 0000 0000 0000 0000 0000 0000 0001 0010二者按位与所得结果是:二者按位与所得结果是:0000 000
28、0 0000 0000 0000 0000 0001 00000000 0000 0000 0000 0000 0000 0001 0000 按位与按位与运算通常用来将某变量中的某些位清0或保留某些位不变。例如,如果需要将int型变量n的低8位全置成0,而其余位不变,则可以执行:n=n&0 xffffff00;也可以写成:n&=0 xffffff00;如果n是short类型的,则只需执行:n&=0 xff00;如何判断一个int型变量n的第7位(从右往左,从0开始数)是否是1?只需看表达式“n&0 x80”的值是否等于0 x80即可。按位与 按位或运算符|是双目运算符。其功能是将参与运算的两操
29、作数各对应的二进制位进行或操作,只有对应的两个二进位都为0时,结果的对应二进制位才是0,否则为1。例如:表达式“21|18”的值是2321:0000 0000 0000 0000 0000 0000 0001 0101 18:0000 0000 0000 0000 0000 0000 0001 001021|18:0000 0000 0000 0000 0000 0000 0001 0111 按位或运算通常用来将某变量中的某些位置1或保留某些位不变。例如,如果需要将int型变量n的低8位全置成1,而其余位不变,则可以执行:按位或n|=0 xff;按位异或运算符是双目运算符。其功能是将参与运算的
30、两操作数各对应的二进制位进行异或操作,即只有对应的两个二进位不相同时,结果的对应二进制位才是1,否则为0。例如:表达式“21 18”的值是7(即二进制数111)。21:0000 0000 0000 0000 0000 0000 0001 0101 18:0000 0000 0000 0000 0000 0000 0001 00102118:0000 0000 0000 0000 0000 0000 0000 0111 按位异或异或运算的特点是:如果 ab=c,那么就有 cb=a以及ca=b。此规律可以用来进行最简单的加密和解密。按位非运算符“”是单目运算符。其功能是将操作数中的二进制位0变成1
31、,1变成0。例如,表达式“21”的值是无符号整型数 0 xffffffea21:0000 0000 0000 0000 0000 0000 0001 0101 21:1111 1111 1111 1111 1111 1111 1110 1010而下面的语句:printf(%d,%u,%x,21,21,21);输出结果就是:-22,4294967274,ffffffea按位非 左移运算符“”是双目运算符。其计算结果是将左操作数的各二进位全部左移若干位后得到的值,右操作数指明了要左移的位数。左移时,高位丢弃,低位补0。左移运算符不会改变左操作数的值。左移运算符例如,常数9有32位,其二进制表示是:
32、0000 0000 0000 0000 0000 0000 0000 1001因此,表达式“94”的值,就是将上面的二进制数左移4位,得:0000 0000 0000 0000 0000 0000 1001 0000即为十进制的144。实际上,左移1位,就等于是乘以2,左移n位,就等于是乘以2n。而左移操作比乘法操作快得多。左移运算符#include main()int n1=15;short n2=15;unsigned short n3=15;unsigned char c=15;n1=15;n2=15;n3=15;c=6;printf(n1=%x,n2=%d,n3=%d,c=%x,c4=
33、%d,n1,n2,n3,c,c 4);上面程序的输出结果是:n1=78000,n2=-32768,n3=32768,c=c0,c4=3072n1:0000 0000 0000 0000 0000 0000 0000 1111 n2:0000 0000 0000 1111n3:0000 0000 0000 1111c:0000 1111n1=15:(变成78000)0000 0000 0000 0111 1000 0000 0000 0000 n2=15:,(变成-32768)1000 0000 0000 0000 n3=15:(变成 32768)1000 0000 0000 0000c=6;(
34、变成 c0)1100 0000 c 4 这个表达式是先将 c 转换成整型0000 0000 0000 0000 0000 0000 1100 0000 然后再左移。c”是双目运算符。其计算结果是把“”的左操作数的各二进位全部右移若干位后得到的值,要移动的位数就是“”的右操作数。移出最右边的位就被丢弃。对于有符号数,如long,int,short,char类型变量,在右移时,符号位(即最高位)将一起移动,并且大多数C/C+编译器规定,如果原符号位为1,则右移时高位就补充1,原符号位为0,则右移时高位就补充0。右移运算符 对于无符号数,如unsigned long,unsigned int,uns
35、igned short,unsigned char类型的变量,则右移时,高位总是补0。右移运算符不会改变左操作数的值。实际上,右移n位,就相当于左操作数除以2n,并且将结果往小里取整。-25 4=-2-2 4=-1 18 4=1右移运算符#include int main()int n1=15;short n2=-15;unsigned short n3=0 xffe0;unsigned char c=15;n1=n12;n2=3;n3=4;c=3;printf(n1=%d,n2=%d,n3=%x,c=%x,n1,n2,n3,c);上面的程序输出结果是:n1=3,n2=-2,n3=ffe,c=
36、1n1:0000 0000 0000 0000 0000 0000 0000 1111 n2:1111 1111 1111 0001n3:1111 1111 1110 0000c:0000 1111n1=2:变成3 0000 0000 0000 0000 0000 0000 0000 0011 n2=3:变成-2 1111 1111 1111 1110 n3=4:变成 ffe 0000 1111 1111 1110c=3;变成10000 0001思考题:思考题:有两个int型的变量a和n(0=n n)&1或:(a&(1 n 函数函数1.为什么要用函数为什么要用函数2.函数声明,定义和调用函数声
37、明,定义和调用3.函数参数的默认值函数参数的默认值4.函数参数的传递方式函数参数的传递方式5.内联函数内联函数6.函数重载函数重载7.库函数和头文件库函数和头文件8.小结小结函数函数(1)大的任务分成若干小的任务大的任务分成若干小的任务(函数函数)(2)函数可以把不需要了解的细节隐藏起来函数可以把不需要了解的细节隐藏起来(3)一般一个函数不要超过一般一个函数不要超过50行代码行代码(4)函函数先声明,再调用。数先声明,再调用。定定义可以看做声明义可以看做声明(5)一般定义函数放在一般定义函数放在.cpp中,声明放在中,声明放在.h中中(7)对于每个程序,都要定义一个对于每个程序,都要定义一个m
38、ain()函数,它是函数,它是C/C+程序程序 开始执行时调用的开始执行时调用的第一个函数第一个函数.main()在调用其他的函数来完成程序的任务在调用其他的函数来完成程序的任务(8)程序中函数通信程序中函数通信 通过通过 参数参数、返回值、全局对象返回值、全局对象来来完成完成(6)函数声明函数声明 由返回类型、函数名和参数组成由返回类型、函数名和参数组成重点要掌握:重点要掌握:1.1.参数列表参数列表的作用的作用(编译器会把参数列表和编译器会把参数列表和函数名混合在一起,形成新的名字函数名混合在一起,形成新的名字),正因,正因为最后的函数命不同,为最后的函数命不同,函数重载函数重载才能实现才
39、能实现.(C语言不允许函数同名语言不允许函数同名)2.2.参数传递的过程与实质参数传递的过程与实质3.3.返回值的实际过程返回值的实际过程函数函数函数函数函数声明函数声明(一般写在(一般写在.h头文件中)头文件中)返回值类型返回值类型 函数名函数名(参数参数1类型类型 参数参数1名称名称,参数参数2类型类型 参数名称参数名称,);int YwkMax(int a,int int b);函数定义函数定义(一般写在(一般写在.cpp文件中)文件中)int YwkMax(int a,int b)int c;if(ab)c=a;else c=b;return c;函数函数-默认参数默认参数对于某些函数
40、,程序往往会用一些对于某些函数,程序往往会用一些固定的值固定的值去调用去调用它它.例如对于以某种数制输出整型数的函数例如对于以某种数制输出整型数的函数print:void print(int value,int base);在大多数情况下都是以十进制输出,因此在大多数情况下都是以十进制输出,因此base的的值总是为值总是为10。C+在定义或声明函数时可以为函数的某个参数指在定义或声明函数时可以为函数的某个参数指定默认值。当调用函数时定默认值。当调用函数时没有为它指定实际参数没有为它指定实际参数时时,系统自动将默认值赋给形式参数。例如,可,系统自动将默认值赋给形式参数。例如,可以将以将print
41、函数声明为函数声明为 void print(int value,int base=10);调用调用print(20)等价于等价于 print(20,10)注意事项注意事项n缺省参数无论有几个,都必须放在参数序列的最后,缺省参数无论有几个,都必须放在参数序列的最后,例如:例如:int SaveName(char*first,char second=int SaveName(char*first,char second=“”,char,char*third=*third=“”,char*fouth=,char*fouth=“”););n在函数调用时,若某个参数省略,则其后的参数皆应省在函数调用时,
42、若某个参数省略,则其后的参数皆应省略而取其缺省值略而取其缺省值函数函数-默认参数默认参数对参数默认值的指定只有在函数声明处有意义。对参数默认值的指定只有在函数声明处有意义。因为函数的默认值是提供给调用者使用的。因为函数的默认值是提供给调用者使用的。函数函数-参数默认值参数默认值函数参数的默认值函数参数的默认值int Function(int a=2);int Max(int a,int b);int a,b;void Function2(int x,int y=Max(a,b),int z=a*b)Function2(4);Function2(4,9);Function2(4,2,3);Fun
43、ction2(4,3);等价于等价于Function2(4,Max(a,b),a*b)/错误错误在函数声明时,指定参数的默认值在函数声明时,指定参数的默认值默认值的顺序,从右往左的顺序定义默认值的顺序,从右往左的顺序定义调用时,默认值的顺序?调用时,默认值的顺序?函数函数-参数默认值参数默认值为什么要默认值?l所有的函数都使用程序运行栈中分配的存储区。所有的函数都使用程序运行栈中分配的存储区。该存储区一直保持与该函数相关联,直到函数该存储区一直保持与该函数相关联,直到函数结束为止。那时,存储区将自动释放以便重新结束为止。那时,存储区将自动释放以便重新使用。该函数的整个存储区称为使用。该函数的整
44、个存储区称为活动记录活动记录.l系统在函数的活动记录中为函数的每个参数都系统在函数的活动记录中为函数的每个参数都提供了存储区。参数的存储区长度由它的类型提供了存储区。参数的存储区长度由它的类型来决定。来决定。参数传递参数传递是指用函数调用的实参值初是指用函数调用的实参值初始化函数参数存储区的过程。始化函数参数存储区的过程。lC+中参数传递的缺省初始化方法是把中参数传递的缺省初始化方法是把实参的实参的值拷贝到参数的存储区中值拷贝到参数的存储区中。这种称为按值传递。这种称为按值传递(pass-by-value)函数函数-参数传递参数传递函数函数-参数传递参数传递n三种形式三种形式l传值调用传值调用
45、l传地址传地址(本质也是传值本质也是传值)l引用传递引用传递函数函数-变量生命周期变量生命周期/作用域作用域int Max(int a,int int Max(int a,int b)b)int c;int c;if(ab)c=a;if(ab)c=a;else c=b;else c=b;return c;return c;void test()void test()int a,b,c;int a,b,c;c=Max(a,b);c=Max(a,b);参数传递方式?变量生命周期参数传递方式?变量生命周期?n不适合不适合按值传递的情况包括:按值传递的情况包括:当当大型的类对象大型的类对象必须作为参数
46、传递时。对必须作为参数传递时。对实际的应用程序而言,分配对象并拷贝到实际的应用程序而言,分配对象并拷贝到栈中的时间和空间开销往往过大。栈中的时间和空间开销往往过大。当当实参的值必须被修改时实参的值必须被修改时。例如:交换。例如:交换 void swap1(int a,int b)int tmp=b;b=a;a=tmp;函数函数-参数传递参数传递 void main()int x=1,y=2;swap1(x,y);Swap1(a(x),b(y);void swap(int a,int b)int c;c=a;a=b;b=c;void main()int x,y;x=3;y=4;swap(x,y)
47、;3 4xyabc 3 4 3 4xy a b c 4 3 3进入进入swap 从从swap出出考虑函数返回值考虑函数返回值的实际过程的实际过程考虑函数引用类考虑函数引用类型参数传递的实型参数传递的实际过程际过程 void swap2(int*a,int*b)int tmp=*b;*b=*a;*a=tmp;Swap2(a(&x),b(&y);void main()int x=1,y=2;swap2(&x,&y);比较函数swap1 和 swap2的参数传递过程函数函数-参数传递参数传递传地址方式传地址方式分析参数生命周期void swap(int *a,int*b)int c;c=*a;*a=
48、*b;*b=c;1 2xyab交换交换x x和和y y的值,可以调用的值,可以调用swap(&x,&y)swap(&x,&y)用指针作为参数可以在函数中修改主调程序的用指针作为参数可以在函数中修改主调程序的变量值,即实现变量传递。必须小心使用!变量值,即实现变量传递。必须小心使用!函数函数-参数传递参数传递函数函数-参数传递参数传递引用引用引用定义的方式如下:引用定义的方式如下:类型名类型名&引用名引用名=同类型的某变量同类型的某变量int n;int&r=n;引用是变量的另一个别名(参照绰号)定义引用时,一定要初始化#include using namespace std;int main(
49、)int n=4;int&r=n;r=4;cout r endl;cout n endl;n=5;cout r endl;int&r2=r;cout r2(B)?(A):(B)在调用内联函数时,编译器直接用内联函数的在调用内联函数时,编译器直接用内联函数的代码代码替换函数调用替换函数调用,于是省去了函数调用的开销。,于是省去了函数调用的开销。缺点:产生函数代码的多个副本并分别插入到程序中每一格调用该函数的位置上,使程序更大。#includeusing namespace std;inline float cube(float s)return s*s*s;int main()float sid
50、e;cin side;cout cube(side)endl;return 0;内联函数内联函数-例子例子n内联以代码内联以代码复制复制(膨胀膨胀)为代价,省去了函数调用的为代价,省去了函数调用的开销,提高函数的执行效率。如果相比于执行函数开销,提高函数的执行效率。如果相比于执行函数体内代码的时间,函数调用的开销可以忽略不计,体内代码的时间,函数调用的开销可以忽略不计,那么效率的收获会很小。那么效率的收获会很小。n以下情况不宜用内联以下情况不宜用内联:l如果函数体内的如果函数体内的代码比较长代码比较长,使用内联将导致内,使用内联将导致内存消耗代价较高。存消耗代价较高。l如果如果函数体内出现循环