C程序设计第四章ppt西工大.ppt_第1页
C程序设计第四章ppt西工大.ppt_第2页
C程序设计第四章ppt西工大.ppt_第3页
C程序设计第四章ppt西工大.ppt_第4页
C程序设计第四章ppt西工大.ppt_第5页
已阅读5页,还剩136页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1 第4章 函数 2 第4章 函数 4.1 函数定义 4.2 函数参数 4.3 函数原型与调用 4.4 内联函数 4.5 函数调用形式 4.6 作用域和生命期 4.7 对象初始化 4.8 声明与定义 3 第4章 函数 4.9 变量修饰小结 4.10 程序组织结构 4.11 函数应用程序举例 C程序各函数之间的关系 1) 不管主函数的书写位置如何,C程序总是从主函 数开始运行、并在主函数结束; 2) 主函数可调用所有自定义函数,但不能被任何函 数调用; 3) 一个自定义函数除了可被主函数调用外,还可被 其它自定义函数调用; 4) 自定义函数可调用除主函数之外的其它自定义函 数,甚至可直接或间接地自己调用自己; 5) 在main函数、自定义函数中都可调用库函数。 main 自定义f1 自定义f2 自定义fn 函数调用关系图示: 库函数 3. 函数调用的执行流程 嵌套调用: maina b a c 开始 结束 f2f1 调用 返回 调用 返回 间接递归调用: 直接递归调用 : 调用 返回 f 4. C函数的分类 从用户使用的角度分类: 库函数由系统(或第三方)提供,包括:常用数学 库、标准I/O库、图形库、科学计算库 等;API、SDK属系统函数范畴。 用户自定义函数根据特定需求自行编制; 从函数的形式分类: 无参函数调用时不需要任何参数; 有参函数调用时必须给出实参,函数依据实参 进行相应处理。 空函数调试时使用的临时占位函数 8 4.1 函数定义 函数定义的一般形式为: 函数定义本质上就是函数的实现,包括: 确定函数名; 确定形式参数列表;确定返回类型; 编写函数体代码。 返回类型 函数名(形式参数列表) 函数体声明部分 函数体执行语句 9 4.1.1 函数定义的一般形式 1函数名 实现函数需要确定函数名,以便使用函数时能够按名引 用。 2形式参数列表 实现函数需要确定有无形式参数、有多少形式参数、有 什么类型的形式参数。形式参数列表是函数与调用者进 行数据交换的途径,一般形式为: 类型1 参数名1,类型2 参数名2, 类型3 参数名3 , 10 4.1.1 函数定义的一般形式 多个参数用逗号(,)分隔,且每个参数都要有自己的 类型说明,即使类型相同的参数也是如此。例如: int fun(int x, int y, double m) return m12.5 ? x : y; 11 4.1.1 函数定义的一般形式 函数可以没有形式参数,定义形式为: 返回类型 函数名() 函数体声明部分 函数体执行语句 返回类型 函数名(void) 函数体声明部分 函数体执行语句 12 4.1.1 函数定义的一般形式 3返回类型 实现函数需要确定有无返回数据、返回什么类 型的数据。返回值是函数向调用者返回数据的 途径之一, 返回类型可以是C语言除数组之外的内置数据类 型或自定义类型。C语言规定一个函数如果没有 给出返回类型,则默认是int型 13 4.1.1 函数定义的一般形式 函数可以不返回数据,此时返回类型应写成void,表示 没有返回值,其形式为: void 函数名(形式参数列表) 函数体声明部分 函数体执行语句 14 4.1.1 函数定义的一般形式 4函数体 实现函数最重要的是编写函数体。函数体(function body)包含声明部分和执行语句,是一组能实现特定功 能的语句序列的集合。 编写函数体是为了实现函数功能。故称函数定义为函数 实现,简称实现。 而函数头简称接口。 15 4.1.1 函数定义的一般形式 例4.1 1 #include 2 int IsPrime(int m) /求素数函数 3 /枚举法求m是否素数 4 int i; 5 for (i=2 ; ib ? a : b; 4 第1行a和b就是形参。 使用说明: 1) 自定义函数可有一个以上的return语句;这常用 于分支结构的不同出口,但只能有一个被执行。 如:int max(int x, int y) if (xy) return x; else return y; 2) 若函数不用return语句返回值,其类型应为空类 型void;此时返回语句形式为:return; 或省略 如:void PrintStar( ) printf(“*n“); return; /或省略 3) return后表达式值的类型一般应与定义函数的类 型一致;若不一致,则以定义函数时的类型为准 自动转换。 如: int average( ) return(sum/4.0); /值为实型,自动转为int型返回 4) C99规定main函数返回值必需是int类型,函数体 中最后一个return 0表示程序正常退出。 25 4.2.1 形式参数 函数定义时指定的形参,在未进行函数调用前, 并不实际占用内存中的存储单元,这也是称它为形 式参数的原因,即它们不是实际存在的。 只有在发生函数调用时,形参才分配实际的内存 单元,接受从主调函数传来的数据,此刻形参是真 实存在的,因而可以对它们进行各种操作。 当函数调用结束后,形参占用的内存单元被自动 释放。此后,形参又是未实际存在的。 26 4.2.2 实际参数 实际参数 函数调用时提供给被调函数的参数称为实际参数 (arguments),简称实参。 实参必须有确定的值,因为调用函数会将它们传 递给形参。实参可以是常量、变量或表达式,还可 以是函数的返回值。例如: x = max(a,b); /max函数调用,实参为a,b y = max(a+3,128); /max函数调用,实参为a+3,128 z = max(max(a,b),c); /max函数调用,实参为max(a,b),c 总结: 函数参数 形式参数定义函数时的参数,在未发生函数调 用时并不实际占用存储单元,仅是形 式符号。 实际参数调用函数时的参数 参数传递机制C采用单向的值传递 28 4.2.3 参数传递机制 值传递时,实参数据传递给形参是单向传递,即 只能由实参传递给形参,而不能由形参传回给实参 ,这也是实参可以是常量和表达式的原因(这些数 据不是左值)。 【例】利用自定义函数,找出三个数中的最大数。 #include int main( ) int a, b, c, d, max(int, int); scanf(“%d,%d,%d“, d=max(a, b); /a、b的值作为实参/ d=max(d, c); /d、c的值作为实参/ printf(“Max is %dn“, d); return 0; int max(int x, int y) /动态分配与释放 int z; z=xy? x:y; return z; /z值作为返回值 Lianxi4-1 85 形式参数和实际参数说明: 1) 编译时并不为形参分配存储单元,在程序运行中 发生函数调用时,才动态地为形参分配存储单元, 并接受实参传递的值(单向值传递);函数调用结束 ,形参占用的存储单元将被释放; 如例中第一次调用: 实参:a b d=max(a, b); 形参: x y 第二次调用: 实参:d c d=max(d, c); 形参: x y 85 812 812 5 85 08 0 2) 由于实参和形参各有各的存储单元,因此在被调 函数中对形参变量赋值,不会对实参造成任何影 响。 如例中主调函数: d=max(a, b); 实参:a b 被调函数: 形参:x y z=xy? x: y; x=y=0; return z; 换句话说:C参数传递机制是单向值传递 4) 由于实参和形参各有各的存储单元,因而实参和 形参可以同名,且互不干扰; 5) 若主调函数采用了函数原型声明法,在实、形参 类型不一致时将按赋值规则自动转换再传递。 如: d=max(7.8, 10.2); /实、形参类型不一致 7 10 6) 实参与形参在个数、类型、顺序上要对应一致; 如:d=max(a, b, 10); /个数不一致编译出错 原型声明法: 类型标识符 函数名(参数类型标识符表); 其中:在参数类型标识符表中,按顺序指明所调函 数的各个参数类型。 特点:此方法在编译时将依据声明,校验函数调用 的参数类型、个数是否匹配。个数不匹配则 编译出错;类型不匹配则以形参类型为准自 动转换(赋值兼容)。 建议:采用原型声明法,可充分利用系统检查能力; 2) 声明的位置 各主调函数内单独声明 若函数f1仅被少数(一两个)函数调用,则选择在主调 函数内单独声明f1,此时对f1的调用只能在这些带 有声明的函数内调用; 源文件开头集中声明 若f1被若干函数调用,则选择在源文件开头对f1集 中声明,此时所有函数都可调用f1且不必再行声明 。 3) 下列情况主调函数中的声明可省略 被调函数书写在主调函数之前; 函数声明集中书写在源文件开头; 【例】有关函数声明 void ps( ); /声明ps float f1() ; ps( ); /ps在开头说明 ; int main( ) ; /省略所有被调函数声明 x=f1(); /f1书写在前 ps( ); /ps在开头说明 ; void ps( ) printf(“*“); return; 标准函数的声明: 调用scanf、printf、getchar、gets等I/O函数需包 含stdio.h头文件,该文件中包含了这些函数的原 型声明,用户不必再声明。 而调用sin、fabs等数学函数时需包含math.h头文 件,该文件中包含了这些函数的原型声明,用户 不必再声明。 。 3. 函数调用的一般形式 函数名(实参表) 当被调函数形参是变量时,实参形式: 可是常量、变量、下标变量、表达式、函数调用 等;多个实参逗号分隔。 注意: 1) 实参在个数、类型、顺序上应与形参对应。 2) 不同编译系统对实参的求解顺序可能不同, Turbo C:自右而左;Visual C+:自左而右 如:i=2; x=fun1( i, i+); 4. 函数调用的位置 1) 对有返回值函数的调用位置,可以是表达式的运 算元素、函数的参数; 如:c=2*max(a,b)+10; 如:m=max(a, max(7,c) ); 如:printf(“MAX=%d“, max(a, b+10) ); 2) 对void空类型函数的调用位置,只能是独立的函 数调用语句; 如:PrintStar( ); 如:delay( ); 5. 函数调用过程 1) 申请存储空间,保存返回地址、当前现场; 2) 参数结合,实参值对应传递到形参存储单元; 3) 程序流程转至被调函数; 4) 被调函数碰到return语句或函数结束标志时, 取返回地址、恢复现场,流程返回至主调函数; 5) 继续主调函数调用点后面的操作。 图示: 【例】利用自定义函数,找出三个数中的最大数。 #include int main( ) int a, b, c, d, max(int, int); scanf(“%d,%d,%d“, d=max(a, b); /a、b的值作为实参/ d=max(d, c); /d、c的值作为实参/ printf(“Max is %dn“, d); return 0; int max(int x, int y) /动态分配与释放 int z; z=xy? x:y; return z; /z值作为返回值 Lianxi4-1 【例】用字符*打印一个梯形。 int main( ) void pstar(int); int i, n; printf(“Enter line number:“); scanf(“%d“, for(i=1; i0; j-) printf(” ”); for(j=i*2-1; j0; j-) printf(”*”); printf(”n”); for(i=1; i0; j-) printf(” ”); for(j=7-i*2; j0; j-) printf(”*”); printf(”n”); return 0; SX03-34 【例】已知双曲正弦 ,输入x, 利用ex幂级数的前21项求出sinh(x)的值。 设计分析: 1) 定义函数计算ex,调用实参值分别取 x、-x; 2) 利用循环和迭代公式:t=t*x/i 计算某项; i取值: 1, 2, 3 t初值: 1 程序:#include int main( ) double myexp(double), x, y; printf(“Enter x:“); scanf(“%lf“, y=(myexp(x)-myexp(-x)/2.0; printf(“sinh(%4.2f)=%fn“, x, y); return 0; double myexp(double x) int i; double sum=1.0, t=1.0; for(i=1; i 几个库函数原型: 获取日历时间:time_t time(time_t * timer); 日历时间转为本地时间: struct tm *localtime(const time_t * timer); 伪随机函数:int rand(void); 随机化函数:void srand(unsigned int); 终止运行函数:void exit(int); time.h中定义的tm结构体: struct tm int tm_sec; /seconds after the minute - 0,59 int tm_min; /minutes after the hour - 0,59 int tm_hour; /hours since midnight - 0,23 int tm_mday; /day of the month - 1,31 int tm_mon; /months since January - 0,11 int tm_year; /years since 1900 int tm_wday; /days since Sunday - 0,6 int tm_yday; /days since January 1 - 0,365 int tm_isdst; /daylight savings time flag ; 时间函数举例: #include #include /tm结构、time、ctime int main( ) struct tm *local; /local结构体变量 time_t t; /typedef long time_t; t=time(NULL); /1970.1.1日0:0:0开始的秒数 local=localtime( /日历时间转换为tm结构时间 printf(“LocalTime is:“ “%d年%d月%d日 %d:%d:%d 星期%dn“, local-tm_year+1900, local-tm_mon+1, local-tm_mday, local-tm_hour, local-tm_min, local-tm_sec, local-tm_wday); return 0; LocalTime is: 2012年4月16日 22:51:27 星期1 SX04-5 随机函数举例: 计算机模拟 模拟是计算机的一项重要应用,其意义是比建 立实物系统省时、省钱、容易、无危险;另外在实 物系统中各种变化因素是很难控制和滤除的,而计 算机模拟可以很方便地调整或滤除参数并得到相应 的结果。 计算机模拟又分为确定性模拟和随机性模拟, 确定性模拟是指被模拟对象的模型中各参数都是确 定的值;随机性模拟是指模型中有未确定的参数, 这个参数需要由随机数函数产生。 随机数函数: 函数原型:int rand( void); 该函数返回至少为032767之间的随机整数,反 复调用将产生随机数序列,但每次执行程序所产生 的序列是重复的,因此这是个伪随机数序列,在利 用计算机模拟某些实验时恰恰需要这一特性。 VC stdlib.h中: #define RAND_MAX 0x7fff 随机化函数: 函数原型:void srand(unsiged int seed); 为rand函数设置随机数种子,其参数是065535 范围的整数,参数不同种子也就不同;这将使rand 产生不同的随机数序列。 【例】用随机数函数rand模拟投掷一个六面骰子, 共投掷1000次,分别统计六种点数出现的次数。 #include #include /srand、rand原形声明 #include /time原形声明 int main( ) int i, rnum, f1, f2, f3, f4, f5, f6; srand(100); /随机化处理 f1=f2=f3=f4=f5=f6=0; for(i=1; i 2 #include /可变参数函数需要用到va_*的宏定义 3 double avg(int first, .) /返回若干个整数平均值的函数 4 5 int count=0 ,sum=0, i; 6 va_list arg_ptr; /定义变参数列表指针 7 va_start(arg_ptr, first); /初始化 8 i=first; /取第1个参数 61 4.2.6 可变参数函数 例4.2 9 while( i!=-1 ) /调用时最后一个参数必须是-1,作为结束标记 10 11 sum += i; /累加多个整数值 12 count+; /计数 13 i = va_arg(arg_ptr, int); /取下一个参数 14 15 va_end(arg_ptr); /清空参数列表 16 return (count0?(double)sum/count:0); 17 62 4.2.6 可变参数函数 例4.2 18 int main() 19 20 printf(“%lfn“, avg(1,2,3,-1); /返回1-3的平均值 21 printf(“%lfn“, avg(7,8,9,10,-1); /返回7-10的平均值 22 printf(“%lfn“, avg(-1); /没有计算返回0 23 return 0; 24 63 4.5 函数调用形式 嵌套调用 在调用一个函数的过程中,又调用另一个函数, 称为函数嵌套调用,C语言允许函数多层嵌套调用 ,只要在函数调用前有函数声明即可。 4.5 函数调用形式 1. 嵌套调用 在一个函数被调用的过程中,又发生了对另一 个函数的调用,这种现象称为函数嵌套调用;嵌套 的层次可是多层的。 【例】用函数求m个元素中取n个的组合。 公式: 定义函数: main: 实现I/O、调用comp函数; comp: 描述组合计算公式、调用阶乘函数fact; fact: 阶乘函数; 调用关系: main comp fact #include int main( ) int n, m; long c; long comp(int, int); /原形声明 printf(“Enter m,n:“); scanf(“%d,%d“, c=comp(m, n); /调用函数 printf(“C(%d,%d)=%ldn“, m, n, c); m、n 组合数阶乘值 int main( ) c=comp(m, n); long comp(int m, int n) long s; long fact(int); /函数声明 s=fact(m)/(fact(n)*fact(m-n); /嵌套调用 return s; long fact(int x) int i; long f=1; for(i=1; i 2 #include 3 double f(double x) 4 /所要求解的函数公式,可改为其他公式 5 return x*x*x-3*x-1; 6 7 double point(double a,double b) 8 /求解弦与x轴的交点 9 return (a*f(b)-b*f(a)/(f(b)-f(a); 10 69 4.5.1 嵌套调用 例4.8 11 double root(double a, double b) 12 /弦截法求方程a,b区间的根 13 double x,y,y1; 14 y1=f(a); 15 do 16 x=point(a,b); /求交点x坐标 17 y=f(x); /求y 18 if (y*y10) y1=y, a=x; 19 else b=x; 20 while (fabs(y)=0.00001); /计算精度E 21 return x; 22 70 4.5.1 嵌套调用 例4.8 23 int main() 24 25 double a,b; 26 scanf(“%lf%lf“, 27 printf(“root=%lfn“,root(a,b); 28 return 0; 29 71 4.5.2 递归调用 4.5.2 递归调用 函数直接或间接调用自己称为递归调用。C语言允 许函数递归调用,如图4.6(a)所示为直接递归调 用,如图4.6(b)所示为间接递归调用。 图4.6 递归调用示意 2. 函数的递归调用 一个函数被调用的过程中,又发生了直接或间 接地自己调用自己,这种现象称为函数递归调用; 递归是算法设计中的常用技术,是采用分治策 略解决复杂问题的有效手段。 分治法的设计思想是:将一个难以直接解决的 大问题分割成一些规模较小的相同子问题,以便各 个击破,分而治之。反复应用分治手段,可使子问 题与原问题类型一致而其规模却不断缩小,最终使 子问题缩小到很容易求出其解。再回来解决它上层 的问题,最终解决所有问题。 递归调用需要占用大量时间和内存空间,应综合考 虑后决定是否选用递归方法。 【例4-14】用递归法求阶乘 可用迭代法和递归法定义阶乘: 迭代法:n!= 12 (n-1)(n-2) n 递归法:n!=n*(n-1)! (n1) 递归过程: 5!=5*4! 24 回 递 4!=4*3! 6 归 归 3!=3*2! 2 过 过 2!=2*1! 1 程 程 1!=1 int main( ) long fact(int), y ; int num; printf(“Enter n:“); scanf(“%d“, if(num=1 /全局变量 int main() int a,b,c; double aver,f1(int, int, int); scanf(“%d%d%d“, aver=f1(a,b,c); printf(“Aver=%.2f Max=%d Min=%dn“, aver,max,min); /引用全局变量 return 0; double f1(int a, int b, int c) double aver; max=min=a; /全局变量引用、赋值 if(bmax) max=b; if(cmax) max=c; if(bb? a:b; return c; int main( ) int a=8; 全局 a失效 printf(“%d“, max(a, b); return 0; 8 4) 若全局变量p定义点之前的函数f1想引用p,一 是将定义点提前,或在函数f1内做外部变量说 明,使p的有效范围扩展到f1中; 例:int f1(int a) extern int p; /外部变量声明 ; if(pa); ; p有效 int p, q; p, q 5) 结构化程序设计思想强调函数间的偶合性越小 越好,实际编程中应尽量少用或不用全局变量。 91 4.6.4 程序映像和内存布局 C源程序经过编译、连接后,成为二进制形式的可 执行文件,称为程序映像。 可执行文件采用ELF格式(可执行连接格式)存储 ,内容包含程序指令、已初始化的静态数据和其他 一些重要信息,例如未初始化的静态数据空间大小 、符号表(symbol table),调试信息( debugging information)、动态共享库的链接表 (linkage tables for dynamic shared libraries)等 。 92 4.6.4 程序映像和内存布局 运行程序时,由操作系统将可执行文件载入到计 算机内存中,成为一个进程(process)。程序在 内存中的布局由5个段(segment)组成。 93 4.6.4 程序映像和内存布局 图4.9 可执行文件映像与内存映像 94 4.6.4 程序映像和内存布局 1代码段 代码段(text segment)存放程序执行的机器指令 (machine instructions)。通常情况下,text段是 可共享的,使其可共享的目的是对于频繁被执行的 程序,只需要在内存中有一份副本即可。text段通 常也是只读的,使其只读的原因是防止一个程序意 外地修改了它的指令。 95 4.6.4 程序映像和内存布局 2已初始化数据段 已初始化数据段(data segment)用来存放C程序 中所有已赋初值的全局和静态变量、对象,也包括 字符串、数组等常量,但基本类型的常量不包含其 中,因为这些常量被编译成指令的一部分存放于 text段。 96 4.6.4 程序映像和内存布局 2已初始化数据段 程序运行时由操作系统从程序映像中取出data段 ,布局在程序内存地址较低的区域。程序结束后由 操作系统收回这段内存区域,即释放data段。 显然,data段的存储单元有与程序代码相同的生 命期,它们的初始值实际在编译时就已经确定了。 即使程序没有运行,这些存储单元的初始值也固定 下来了,当程序开始运行时,这些存储单元是没有 初始化的动作。 在程序运行中,data段的存储单元数据会一直保 持到改变为止,或保持到程序结束为止。 97 4.6.4 程序映像和内存布局 3未初始化数据段 未初始化数据段(bss segment)用来存放C程序 中所有未赋初值的全局和静态变量。 在程序映像中没有存储bss段,只有它的空间大小 信息;程序运行前由操作系统根据这个大小信息分 配bss段,且数据值全都初始化为0,布局在与data 段相邻的区域。程序结束后由操作系统收回这段内 存区域,即释放bss段。 98 4.6.4 程序映像和内存布局 3未初始化数据段 显然,bss段的存储单元也有与程序代码相同的生 命期,但与data段不同的是如果程序没有运行, bss段的存储空间是不存在的,因而也就不会有初 始值。在程序运行前,这些存储单元会初始化为0 。此后,bss段的存储单元的性质与data段完全相 同。 99 4.6.4 程序映像和内存布局 data段和bss段的存储特点,决定了C程序中所有 全局和静态变量、对象的存储空间在main函数运 行前就已经存在,就有了初始值。程序运行到这些 变量和对象的定义处时,是不会再有初始化动作的 。在程序运行中这些变量和对象的存储空间不会被 释放,一直保持到程序运行结束。期间如果数据被 修改,则修改会一直保持。 100 4.6.4 程序映像和内存布局 4栈 栈(stack)用来存放C程序中所有局部的非静态型 变量、临时变量,包含函数形参和函数返回值。 101 4.6.4 程序映像和内存布局 4栈 程序映像中没有栈,在程序开始运行时也不会分 配栈。每当一个函数被调用,程序在栈段中按函数 栈框架入栈,就分配了局部变量存储空间。如果这 些变量有初始化,就会有赋值指令给这些变量送初 值,否则变量的值就呈现随机性。当函数调用结束 时,函数栈框架出栈,函数局部变量释放存储空间 。 栈的存储特点,决定了C程序中所有局部的非静态 型变量,其存储方式是动态的。函数调用开始时得 到分配,赋予初值,函数调用结束时释放空间,变 量不存在。下次函数调用时再重复。 102 4.6.4 程序映像和内存布局 5堆 堆(heap)用来存放C程序中动态分配的存储空间 。 103 4.6.4 程序映像和内存布局 5堆 程序映像中没有堆,在程序开始运行时不会分配 堆,函数调用时也不会分配堆。堆的存储空间分配 和释放是通过指定的程序方式来进行的,即由程序 员使用指令分配和释放,若程序员不释放,程序结 束可能由操作系统回收。 C语言中可以通过使用指针、动态内存分配和释放 函数来实现堆的分配和释放,详见第7章。程序可 以通过动态内存分配和释放来使用堆区,堆区有比 栈更大的存储空间、更自由的使用方式。 104 4.6.4 程序映像和内存布局 堆和栈的共同点是动态存储,处于这两个区域的 存储单元可以随时分配和释放,所以这些存储单元 的使用特点呈现临时性的特点。 105 4.6.4 程序映像和内存布局 堆和栈的区别是分配方式的不同 栈是编译器根据程序代码自动确定大小,到函 数调用时有指令自动完成分配和释放的;堆则 完全由程序员指定分配大小、何时分配、何时 释放。 堆的优点是分配和释放是自由的,缺点是需要 程序员自行掌握分配和释放时机,特别是释放 时机,假如已经释放了还要使用堆会产生引用 错误,或者始终没有释放产生内存泄漏( memory leak)。 总结 一个C程序所占内存可分为: 栈:编译器分配存储函数参数, 函数局部变量等 在程序开始时不分配,当函数调用时分配局部变量存储空间 堆:由程序的指定方式分配和回收, 例如动态分配和释放、 指针进行。malloc,free函数 在程序开始时不分配,当函数调用时不分配。不释放 就一直存在程序运行期间, 全局区:存放全局变量和静态变量 文字常量区: char * p = “12345” 程序代码区:存放程序的二进制代码 程序结束后由系统释放 程序结束后由系统释放 程序结束后由系统释放,可共享 107 4.6.5 生命期 3自动对象 默认情况下,函数或复合语句中的对象(包含形 参)称为自动对象(automatic objects),其存储 方式是自动存储,程序中大多数对象是自动存储。 auto 类型 变量名=初值, 108 4.6.5 生命期 4寄存器变量 C语言允许用CPU的寄存器来存放局部变量,称为 寄存器变量。在局部变量前加上register存储类别 修饰来定义的,其形式为: register 类型 变量名=初值, 109 4.6.5 生命期 5静态局部对象 在局部对象的前面加上static存储类别修饰用来指 明对象是静态局部对象(static local object),一 般形式为: static 类型 变量名=初值 , 110 4.6.5 生命期 auto:对局部变量无特殊要求时采用;特点是函 数被调用时动态分配、释放,可节省内存资源; static:若函数调用结束后,希望能保留已有值 以便下次调用时继续引用,采用该类别可达目的; 因为: 静态局部变量在程序的整个运行期间始终在静 态存储区占据着固定的存储单元,但只有发生函数 调用时才可对其引用或赋值,函数调用结束它仍然 保存其值和存储单元,函数再次被调用时又可继续 引用。 注:全局变量也可达此目的,但有效范围内的函数 都可使用,因此尽量少用。 如: int fun(int a) auto int b, c=3; /调用时分配单元并赋初值 static int x, y=1; /编译时分配单元并赋初值 说明: 静态局部变量x、y存储单元的分配和y赋初值 是一次性的,函数调用结束不会释放。 x, y a, b, c 静态存储区 动态存储区 【例】求1+2

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论