c语言程序设计10第十讲(第五章上)课件_第1页
c语言程序设计10第十讲(第五章上)课件_第2页
c语言程序设计10第十讲(第五章上)课件_第3页
c语言程序设计10第十讲(第五章上)课件_第4页
c语言程序设计10第十讲(第五章上)课件_第5页
已阅读5页,还剩161页未读 继续免费阅读

下载本文档

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

文档简介

不为失败找理由、要为成功找方法!1不为失败找理由、要为成功找方法!1高级语言程序设计主讲教师:贾彩燕计算机与信息技术学院计算机科学与技术系cyjia@2高级语言程序设计主讲教师:贾彩燕2第五章

C程序结构3第五章

C程序结构3本章讨论与C程序整体结构有关的问题。对正确理解C语言/正确书写C程序很重要。学习用C程序设计时应了解的“深层问题”。1)基本数值类型的全面介绍2)函数与C程序结构,函数原型3)变量类,作用域与存在期4)预处理命令5)字位运算符(特殊问题,初步了解,需要时深入)4本章讨论与C程序整体结构有关的问题。1)基本数值类型的全面介主要内容数值类型函数和标准库函数函数定义和程序的函数分解C程序结构与变量预处理命令定义常量字位运算符编程实例5主要内容数值类型55.1数值类型实数类型:float,double,longdouble实数类型外的算术类型都是整数类型。字符类型也看作整数类型,可以作为整数参加运算。每一基本整数类型都有带符号与无符号两种类型,用限定词signed或unsigned说明。无符号类型的值大于等于0。同一基本类型的带符号/无符号类型用同样长度编码。signed可省略,如signedlong简写为long。65.1数值类型实数类型:float,double,lon字符类型:char,signedchar,unsignedchar用一个字节表示,其中存字符编码。ASCII字符集里数字(字母)字符的编码连续排列。char等同于signedchar或unsignedchar(不同系统可能不同)。简单程序只用char,不需要关心有无符号。只有用char参加整数运算时才需要考虑。基本ASCII字符集的编码范围是0-127。7字符类型:char,signedchar,unsigned整数类型

基本:int,shortint,longint总共六个: int unsignedint short unsignedshort long unsignedlongshortint简写为short,longint简写long,unsignedint简写为unsignedshort表示范围不大于int,long不小于int。无符号/有符号类型位数相同。具体表示由C语言系统确定。基本类型是int,一般用计算机的字长表示。16位机器的C系统中,int通常用16位表示;32位机器的C系统中,int通常用32位表示;8整数类型基本:int,shortint,longin整数常量可用十进制八进制(0开头)十六进制(0x或0X开头)长整型加后缀L或lshort无常量写法无符号数加后缀u或U123U,2987654LU,327LU,32014U无符号整数的算术运算按取模方式做(不会溢出),超出表示范围时取模作为计算结果。例:若16位unsignd范围为0~65535。计算超范围时取模65536。234U+65500U的计算结果是198U。9整数常量可用十进制无符号整数的算术运算按取模方式做(混合类型运算前把小类型转换到大类型的值。整数提升:小整数(short、char等)先转为int值再运算。若转换结果超出int范围(unsignedshort提升可能出问题),就提升为unsigned。基本类型相同时,认为无符号类型是比同样的有符号类型更大的类型。例如做下面计算:2365U+18764将先由18764(整型值)转换生成unsigned对应值,再用此新值参与运算。10混合类型运算前把小类型转换到大类型的值。基本类型相同时,认为基本数据类型的选择C语言提供多个浮点类型和整数类型,供编程者选择使用。如无特殊需要,浮点数总用double,因其精度和范围能满足一般要求(float精度过低,longdouble可能低效,一般不用)。如无特殊需要,整数总用是C语言里最基本的类型,能得到硬件基本支持,其效率不会低于任何其他整数类型。有时用long类型。如无特殊需要,字符总采用char。尽量少用unsigned类型,除非服务于特殊目的。11基本数据类型的选择C语言提供多个浮点类型和整数类型,供编程主要内容数值类型函数和标准库函数函数定义和程序的函数分解C程序结构与变量预处理命令定义常量字位运算符编程实例12主要内容数值类型12编写大程序时应特别注意函数分解。没有合理函数分解不可能完成复杂工作/多花时间/程序更难理解/错误更难发现和纠正。开始就应强调好的编程习惯(包括函数分解)。函数的作用:把一段计算抽象出来,封装(包装)成独立实体。这种封装程序段称为函数定义。定义后通过函数名就可以用简便方式要求执行该函数所封装的计算。这种描述片段称为函数调用。5.2函数和标准函数库问题复杂使程序变长。大程序难开发/难阅读理解/难修改;修改时容易破坏完整性,难保证不引进新错误。程序中常出现许多相同/类似片段。使程序更长,增加不同部分间的联系,损害可修改性。13编写大程序时应特别注意函数分解。函数的作用:把一段计算抽象出基本C语言很小,ANSIC定义了标准库,其中提供最常用的与平台无关的功能。每个符合标准的C系统都提供了标准库,通常还提供一些扩充库,以便使用特定硬件/特定系统的功能:DOS上的C系统提供与DOS有关的功能函数Windows上的系统提供与Windows有关的函数UNIX系统上的系统提供与UNIX接口的函数扩充库不标准,使用扩充库的程序依赖于具体系统。库函数实现常用计算,可按规定方式调用,不必自己实现/不必关心怎样实现。开发一次使所有用户受益。C语言的库函数14基本C语言很小,ANSIC定义了标准库,其中提供最常用的与标准库功能包括

输入输出、文件操作、存储管理,其他如数学函数、数据转换函数等。有关介绍散布在各章,后面有详细介绍。对具体C系统的扩充库可查阅系统联机帮助,或查阅有关手册、参考书籍。。下面介绍两组常用标准函数。15标准库功能包括下面介绍两组常用标准函数。15字符分类(<ctype.h>)isalpha(c) c是字母字符isdigit(c)c是数字字符isalnum(c) c是字母或数字字符isspace(c) c是空格、制表符、换行符isupper(c) c是大写字母islower(c) c是小写字母iscntrl(c) c是控制字符isprint(c)c是可打印字符,包括空格isgraph(c) c是可打印字符,不包括空格isxdigit(c) c是十六进制数字字符ispunct(c) c是标点符号inttolower(intc) 转为对应小写字母inttoupper(intc) 转为对应大写字母是返回非零,不是返回零16字符分类(<ctype.h>)isalpha(c) #include<stdio.h>#include<ctype.h>intmain(){intc,cd=0,cu=0,cl=0;while((c=getchar())!=EOF){if(isdigit(c))++cd;if(isupper(c))++cu;if(islower(c))++cl;}

printf("digits:%d\n",cd);

printf("uppers:%d\n",cu);

printf("lowers:%d\n",cl);return0;}用标准库函数完成判断比自己写条件更合适。

17#include<stdio.h>用标准库函数完成判断比自#include<stdio.h>#include<ctype.h>intmain(){intcount=0,c;while((c=getchar())!=EOF){if(isspace(c))continue;++count;while((c=getchar())!=EOF&&!isspace(c));}

printf("Words:%d\n",count);return0;}统计单词程序:18#include<stdio.h>统计单词程序:18随机数生成函数程序调试:用数据做运行试验,随机数据非常合适。计算机模拟:模拟实际情况/过程,客观事物变化有随机性。最常用的是除余定义:

a0=A an=(B×an-1+C)modDA,B,C,D为常数,0≤A<D。适当选择B、C可产生0到D-1的较好随机数列。计算机只能生成“伪随机数”。常用方法是定义某种递推关系,设法使序列中的数比较具有随机性。19随机数生成函数最常用的是除余定义:计算机只能生成“伪随机数标准库提供随机数功能,需要包含文件<stdlib.h>。随机数生成函数:intrand(void)无参数,得到0和符号常量

RAND_MAX

间的随机整数。不同系统的RAND_MAX可能不同,至少为32767。函数srand用seed值设种子值:voidsrand(unsignedseed)默认初始种子值是1;rand根据当时种子值生成下一随机数并修改种子值。20标准库提供随机数功能,需要包含文件<stdlib.h>。函数根据下面公式可以得到所需范围内的随机数:n=a+rand()%b其中a为位移,是所需连续整数范围的第一个数,b是比例因子,是所需连续整数范围的宽度,则希望产生1--6之间随机数的公式为:n=1+rand()%6希望产生0—1之间随机数的公式为:n=rand()%2伪随机数的产生

21根据下面公式可以得到所需范围内的随机数:伪随机数的产生21例:编写一个投掷骰子的程序,模拟10次,输出每次投掷的点数。#include<stdio.h>#include<stdlib.h>intmain(){inti;printf(“\n”);

for(i=1;i<=10;i++)printf("%3d",1+rand()%6);return0;}结果:6655651153第二次运行:6655651153使用srand函数,通过提供不同的种子产生不同的随机数序列。srand(x);

/*初始化随机数发生器*/

unsignedx;

scanf(“%d”,&x);/*输入一个非负的整数做种子*/16134356526233315356541516134356526222例:编写一个投掷骰子的程序,模拟10次,输出每次投掷的点数。#include<stdio.h>#include<stdlib.h>voidmain(){inti;printf(“\n”);

for(i=1;i<=10;i++)printf("%3d",1+rand()%6);}结果:3453314315再次运行:4432355323

srand(time(NULL));/*使用time函数返回值做种子*/#include<time.h>例:编写一个投掷骰子的程序,模拟10次,输出每次投掷的点数23#include<stdio.h>结果:srand(主要内容数值类型函数和标准库函数函数定义和程序的函数分解C程序结构与变量预处理命令定义常量字位运算符编程实例24主要内容数值类型245.3函数定义和程序的函数分解一个C程序主要是一系列的函数定义。函数定义形式:

函数头部---

返回值类型函数名参数表

函数体库函数有限,编写复杂程序时需要自己定义函数。函数头部:描述函数外部与函数内部的联系。

应该总写返回类型,无返回值用void说明。允许任意多个参数,无参函数用(void)

(早期C语言对ANSIC的影响),定义无参函数时也可用()。255.3函数定义和程序的函数分解一个C程序主要是一系列的函数主函数mainmain的返回值规定为int。这个返回值在程序结束时送给外部,程序外部(如操作系统)可用这个值。一般返回0表示程序正常结束,其他值表示出错main以外的函数只有被调用时才会执行不允许调用mainintmain(){/*一般写法*/......return0;}26主函数mainintmain()262727程序的函数分解什么样的程序片段应该定义为函数:重复出现的相同/相似计算片段,可设法抽取性定义为函数。长计算过程中有逻辑独立性的片段,即使出现一次也可定义为函数,以分解复杂性。经验原则:可以定义为函数的内容,就应该定义为函数;一个函数一般不超过一页。往往存在很多可行的分解,寻找合理有效的分解是需要学习。28程序的函数分解什么样的程序片段应该定义为函数:经验原则:可以实例研究:字符图形写程序打印下面这类字符图形最“简单”的方式:用一系列putchar调用打印星号和空格(数清字符个数,就可以写出程序)。29实例研究:字符图形写程序打印下面这类字符图形最“简单”的方式方法二:程序里写一系列printf调用。例:intmain(){/*打印菱形*/printf("*");printf("**");printf("***);....../*下略*/}不好!若要修改图形大小或形式,程序需全部重写如果需要画出新图形,已做工作对新工作毫无价值应考虑画这类图形的“基本动作”,定义为函数。30方法二:程序里写一系列printf调用。例:不好!若要修改图分析:图形由以下部分组成1)一段连续字符;2)在两个特定位置的字符;字符图形未必用星号,可推广,引进一个字符参数voidline(charc,intbegin,intend)voidpoints(charc,intfst,intsnd)

可考虑定义两个函数,其头部分别为:

voidline(intbegin,intend)voidpoints(intfst,intsnd)line从begin到end输出*,points在fst和snd输出*。

31分析:字符图形未必用星号,可推广,引进一个字符参数可考虑定义如函数已经定义,画菱形程序段可写为:

for(i=10,j=10;i>4;--i,++j)points('*',i,j);

for(i+=2,j-=2;i<=j;++i,--j)points('*',i,j);

/*10是常量,确定菱形的位置和大小*/画其他空心或实心的规范图形也不难。函数使用者只需考虑函数的使用形式和功能,无需考虑函数实现32如函数已经定义,画菱形程序段可写为:函数使用者只需考虑函数的voidline(charc,intbegin,intend){inti;for(i=0;i<begin;++i)putchar('');for(;i<=end;++i)putchar(c);putchar('\n');}voidpoints(charc,intfirst,intsecond){inti;for(i=0;i<first;++i)putchar('');putchar(c);for(++i;i<second;++i)putchar('');if(first<second)putchar(c);putchar('\n');}做好了一个图形后,修改其大小或形状也比较容易。两个函数是输出一些空格和字符后换行:33voidline(charc,intbegin,i也可引入附加参数,将两个函数合而为一:voidline(charc,intbegin,intend,intfill){......}在fill为0值时在两端点输出,非0时连续输出字符。还可基于它们定义画各种基本几何图形的函数。设计函数时需要选定合适参数。例如画矩形的函数:voidrect(charc,intbegin,intlen,inthigh){......}这些函数又形成另一层抽象层次。定义好这样一组函数后,就可以在新的层次上写字符图形程序了。34也可引入附加参数,将两个函数合而为一:还可基于它们定义画各种封装把函数内外隔成两个世界。不同世界形成了对函数的两种观点。函数头规定了两个世界的交流方式。对函数的两种视点35封装把函数内外隔成两个世界。不同世界形成了对函数的两种观点。函数是独立的逻辑实体。定义后可以调用执行。由此形成对函数的两种观察方式:1)从函数外(以函数使用者的角度)看函数;2)在函数内(以函数定义者的角度)看函数。计划函数时,分析确定函数头部,定好公共规范。写函数定义时应站在内部观点思考/解决问题;使用函数时应站在外部立场上思考/解决问题。功能描述清楚,接口定义好以后,函数定义和使用可由不同人做。要求双方遵循共同规范,对函数功能有一致理解。36函数是独立的逻辑实体。定义后可以调用执行。由此形成对函数的两函数定义解决实现函数的算法问题和语言问题。参数是局部变量,调用时对应实际参数赋初值,然后开始执行函数体。参数像其他局部变量一样可以赋值。return语句的执行导致函数结束。return语句的两种形式: return;/*无返回值*/return表达式;函数体里可有多个return语句。在带不带表达式/所带表达式的类型方面必须与函数头部一致。执行到函数体末端时函数结束(无返回值的函数)。37函数定义return语句的执行导致函数结束。函数体里可有多个函数调用调用函数时必须提供数目正确/类型合适的实参。调用无参函数时也需要写圆括号。无返回值函数用在独立的函数调用语句里:pc_area(x+3);有返回值的函数通常用在表达式里。返回值也可不用。例:printf返回int。工作正常时返回实际输出的字符数,出错时返回负值。38函数调用38C语言的参数机制称为值参数(简称值参)f内对a和b的操作与m和n没有任何关系39C语言的参数机制称为值参数(简称值参)f内对a和b的操作与m值传递与赋值和初始化类似,可能出现转换。要求实参值可转换到形参类型,否则是类型错。语言没有规定调用时的实参求值顺序,对求值顺序敏感的函数调用是错误(与二元运算类似)。例: n=...; m=gcd(n+=15,n);另一错误调用: printf("%d,%d",n++,n);C函数的参数是值参数函数调用时先计算实参表达式的值,把值复制给对应形参,而后执行函数体。函数内对形参的操作与实参无关。40值传递与赋值和初始化类似,可能出现转换。要求实参值可转换到形命名对象(变量/函数等):基本规则是先定义后使用。保证正确编译的基本原则:从每个对象的每个使用点向前看,能得到使用该对象的完备信息。局部变量:变量定义在语句前,保证了先定义后使用。后面变量定义可引用前面已经定义的变量。函数:使用点所需信息就是函数的类型特征,包括函数名/参数个数和类型/返回值类型等。调用位置要检查参数个数和类型,是否需要以及能否转换。返回值类型是否匹配。函数原型41命名对象(变量/函数等):基本规则是先定义后使用。调用位置要longfact(longn){returnn<=1?1:n*fact(n-1);}典型例子:inth(intx) intg(inty){.... { ......g(...).. ..h(...)...... ....} }这是引进函数原型说明的一个原因。更重要的是使人能自由安排函数定义位置,支持大型程序开发。将主函数写在最后就是为保证函数定义与使用的关系。递归定义的函数也能保证定义与使用的关系。有些情况无法通过安排函数定义位置解决。42longfact(longn)典型例子:这是引进函数原原型说明的形式与函数头部类似,加分号。参数名可省略,可与函数定义用的名字不同。任何可以写定义的地方都可以写原型说明。提倡把原型说明都放在程序文件最前面:1)使文件里所有调用能看到同一个原型说明。2)使函数的定义点也能看到同一个原型说明。原型说明是保证函数定义/使用间一致性的媒介。为保证原型能起作用,应给出完整的类型特征voidline(charc,intbegin,intend);voidpoints(charc,intfst,intsnd);43原型说明的形式与函数头部类似,加分号。任何可以写定义的地方都过时的函数定义形式/原型形式C标准化时保留了一些过时东西,以保证老程序合法。这里介绍老形式只是为能读别人写的老程序。过时函数定义形式。例:doublef1(x,y,n)doublex,y;intn;{/*函数体*/}/*早期高级程序语言中常见的形式*/过时原型形式:设完整原型为doublef(double);intg(double,int);intmain(void){intg(),n;doublef(),x;....x=f(3);n=g(n);....}/*错,编译程序不会发现!*/不要使用过时函数定义和原型形式44过时的函数定义形式/原型形式不要使用过时函数定义和原型形式4不写函数原型为宽容老程序,C语言容许不写原型。遇到调用f(...),若此前无f定义或原型就做默认处理,方式是假设有一个原型说明:intf();出现在包含该函数调用的最内层复合语句的最前面,按此假设对函数调用进行编译和处理。只有f确实返回int,调用的实参个数和类型都与f的要求完全相同(不需转换)时才能产生正确结果。不写原型可能引起许多问题。是极危险的编程习惯!45不写函数原型不写原型可能引起许多问题。是极危险的编程习惯!4为避免函数使用的隐含错误,应坚持正确编程原则:如果使用标准库,必须#include必要的库文件所有使用前未给出定义的函数(无论实际上在哪里定义),都必须给出正确完整的原型说明应把原型说明写在源文件最前面基本原则:使函数的定义点和所有使用点都能“看到”同一个原型说明。坚持这些原则,就能避免函数调用与定义不一致的错误(常常是编译程序检查不到的隐含致命错误)。简单地说“用C语言编程序容易出错”并不合理。许多错误是由于人们没按正确地方式做事情。46为避免函数使用的隐含错误,应坚持正确编程原则:简单地说“用C程序实例(求函数的根)求函数根是典型数值计算问题,这里讨论弦线法。解题思路:选定区间,两端点函数值异号;做过端点弦线;求弦线与坐标轴交点;缩小区间,重复操作;直到交点函数值充分接近0(满意为止)。47程序实例(求函数的根)解题思路:47求弦线与坐标轴交点的公式:1、输入x1和x2,求f(x1)和f(x2),若f(x1)*f(x2)>0,转1;否则转22、根据x1和x2求x(定义函数crossp),求f(x)(定义函数f);3、检查f(x)与f(x1)和f(x2)谁同号,重新选定x1或x2若f(x1)*f(x)>0则x1=x,否则,x2=x,4、检查f(x)>=1E-6是否满足,满足转2不满足,结束,输出x,为根。48求弦线与坐标轴交点的公式:1、输入x1和x2,求f(x1#include<stdio.h>#include<math.h>doublef(doublex){/*例子,根据需要定义*/returnx*((2*x-4)*x+3)-6;}doublecrossp(doublex1,doublex2){doubley1=f(x1),y2=f(x2);return(x1*y2-x2*y1)/(y2-y1);}49#include<stdio.h>49doubleroot(doublex1,doublex2){doublex,y,y1=f(x1);do{x=crossp(x1,x2);y=f(x);if(y*y1>0){/*y与y1同符号,新区间[x,x2]*/x1=x;y1=y;}elsex2=x;/*异号,新区间[x1,x]*/}while(fabs(y)>=1E-6);/*继续*/returnx;}50doubleroot(doublex1,doubleintmain(){doublex1,x2,x;do{printf(“Inputdoublex1,x2”);scanf(“%lf%lf”,&x1,&x2);}while(f(x1)*f(x2)>0);

x=root(x1,x2);printf(“rootis%lf”,x);return0;}51intmain()51主要内容数值类型函数和标准库函数函数定义和程序的函数分解C程序结构与变量预处理命令定义常量字位运算符编程实例52主要内容数值类型52变量定义:1)定义特定类型的变量;2)为变量命名。还确定了:变量定义的作用域:变量定义起作用的范围。由定义位置确定,在此范围可通过该名字使用该变量变量的存在期:确定变量建立和销毁时间。各种变量的存在期可能不同。变量实现的基础是内存单元,存在期就是变量被分配内存存储到撤消的期间作用域与生存期变量的作用域决定了其生存期。5.4程序结构与变量53变量定义:1)定义特定类型的变量;2)为变量命名。作用域与生作用域是静态概念,一个变量的作用域是一段源程序。如在函数体开始定义的变量,作用域是整个函数体。生存期是动态概念,程序执行的一段时间。变量在生存期中保持其存储单元,不经赋值那里的值就不变。在作用域和生存期方面,外部变量和局部变量性质不同。外部变量:在所有的函数之外定义的变量称为外部变量(或叫做全局变量).其作用范围是从变量定义的位置开始,直到本源文件的结束。局部变量:在一个函数内部定义或复合语句内定义的变量,其作用范围为函数体内部或复合语句内。从作用域的角度:54作用域是静态概念,一个变量的作用域是一段源程序。如在函数体开1、一个源文件可以包含一个或几个函数.2、外部变量可以被本源文件的所有函数共享.3、外部变量的设置增强了函数间数据的联系.一个函数对外部变量的值的改变将会影响到其他的函数中.4、建议在只有必要时才设置外部变量.5、外部变量在文件的开头定义,则它的有效范围是整个源文件,但如果全局变量不是在开头定义的,则它有效范围是从定义点到源文件的结束.6、外部变量可以后定义先使用,或在一个源文件里定义在其他文件使用。使用前应给出外部变量说明(该变量一定在其它地方有定义)。形式:前面加关键词extern。例:externintn,m;本程序可以使用该变量。外部变量的要点:外部说明通常放在源文件最前面,供整个文件参照。更重要的:保证整个程序参照同一说明,保证一致性。551、一个源文件可以包含一个或几个函数.外部变量的要点:外部说intp=1,q=1;/*定义外部变量p,q*/voidfloatf1(inta)/*定义函数f1*/{intb,c;…}charc1,c2;/*定义外部变量c1,c2*/voidcharf2(intx,inty)/*定义函数f2*/{inti,j;…}voidmain()

{intm,n;…}外部变量p,q的有效范围外部变量c1,c2的有效范围56intp=1,q=1;/*定义外部变量p,q*/外部外部5……intnum;externintexnumber;intf(intn){intn;….n…num…extnumber……….}intexnumber;intmain(){…f(…)…….num…extnumber……….}外部变量定义外部变量说明如果一个函数定义用到外部变量,它就依赖这些变量,不再独立。注意:定义和说明不同。定义要求创建被定义的对象;说明只指明其存在,必须另有定义,否则该说明无效。外部变量可在整个程序用,在一个完整程序里不能有重名外部变量。否则连接时会出问题不要与函数库里内容重名(标准库定义了一批外部名字)。57……外部变量定义外部变量说明如果一个函数定义用到外部变量,它1、主函数(main函数)中定义的变量也只在主函数中有效;2、不同的函数中可使用相同的变量名,它们代表不同的含义;3、形参也是局部变量;4、在一个函数内部可以使用复合语句来定义变量,这样的变量只在本复合语句中有效.5、当外部变量名与局部变量名相同时,则在局部变量的有效范围内外部变量不起作用.局部变量的要点581、主函数(main函数)中定义的变量也只在主函数中有效;局inta=13,b=-8;intplus(intx,inty){intz;z=x+y;a=a+b;printf(“%d\n”,a)returnz;}intmian()

{intz;inta=6;z=plus(a,b);printf(“%d\n”,z);printf(“%d\n”,a)return0;}例分析下面的程序写出结果.5-2659inta=13,b=-8;例分析下面的程序写出结变量的存储类别从变量存在时间(生存期)角度来区分:1、静态存储变量:在程序运行期间分配固定的存储空间的方式。2、动态存储变量:在程序运行期间根据需要进行动态的分配存储空间的方式。60变量的存储类别从变量存在时间(生存期)角度来区分:60内存中用户区的划分程序区静态存储区动态存储区1.程序区:存放程序的代码;2.静态存储区:存放全局变量和静态的局部变量;3.动态存储区:存放局部变量,函数调用时的现场保护和返回地址;存放在静态存储区中的变量的生存周期是程序的整个执行过程。存放在动态存储区中的变量的生存周期是函数或复合语句的执行期间。61内存中用户区的划分程序区静态存储区动态存储区1.程序区:存放1、含义:指数据在内存中的存储方法。2、划分:在c语言中将变量和函数的属性划分为:数据类型数据的存储类别.如:staticinta,b;3、存储类别:自动变量(auto)静态变量(static)寄存器变量(register)外部变量(extern)分别放在静态存储区和动态存储区.变量和函数的存储类别存贮类别数据类型621、含义:指数据在内存中的存储方法。变量和函数的存储类别存贮1、含义:函数或复合语句中定义的变量不作特殊说明都为自动局部变量,存储在动态存储区。2、用法:用关键字auto进行说明,可以省略auto关键字。intf(inta){autointb=0,c=10;..}3、要点:当函数调用结束或复合语句结束后,它们所占用的存储空间即被释放.自动变量631、含义:函数或复合语句中定义的变量不作特殊说明都为自动局部1、含义:函数中的局部变量的值在函数调用结束后不消失而保留原值。(即所占用的存储单元并不释放,下次直接使用)2、用法:用static说明。静态局部变量intf(inta){autointb=0;staticintc=3;b+=1;c+=1;return(a+b+c);}intmain(){inta=2,i;for(i=0;i<3;i++)printf(“%3d”,f(a));return0;}运行结果:7 89641、含义:函数中的局部变量的值在函数调用结束后不消失而静态局1.静态局部变量存储在静态存储区,在程序的整个运行期间都不释放;2.静态局部变量是在编译时赋初值的,即只赋值一次。3.静态局部变量在定义时不赋初值,编译时系统自动赋初值0;而对于自动变量,如果不赋初值则它的值是一个不确定的值.4.静态局部变量在函数调用结束后仍然存在,但只能被这个函数再次使用,不能被其他函数使用.说明:651.静态局部变量存储在静态存储区,在程序的整个运行期间都不释静态局部变量实例假设需要一个函数,调用时通常输出空格,调用第10次时输出换行符。取名format,无参。可用它改造打印完全平方数程序,使每行输出10个数:

for(n=1;n*n<=200;n++){printf("%d",n*n);

format();}许多地方都可能用它。初看这个函数可能很简单。66静态局部变量实例初看这个函数可能很简单。66voidformat(void){

intm=0;if(++m==10){putchar('\n');m=0;}elseputchar('');}这个函数无论调用多少次都不输出换行。m是自动变量,每次调用重新建立并初始化为0。无论调用format多少次,m也不可能等于10。67voidformat(void)这个函数无论调用多少次都可采用外部变量,存在期长,能保持值不变,可在任何函数(包括format)里使用。

intm=0;voidformat(void){if(++m==10){putchar('\n');m=0;}elseputchar('');}/*功能正确*/问题:程序其他部分可能不当心修改了m(例如把局部变量n写成m),导致计数错误。信息隐蔽/保护很重要,小到程序的组织,大到关系国家安全的重要系统,都必须关注这个问题。68可采用外部变量,存在期长,能保持值不变,可在任何函数(包括f需要一种变量:局部作用域,限制在函数内,防止越权访问;全程存在期和一次初始化,以便在函数调用之间传递信息,值在不同调用之间保持不变。静态局部变量:定义时加static。voidformat(void){

staticintm=0;if(++m==10){putchar('\n');m=0;}elseputchar('');}需要局部作用域/全程存在期的变量,应使用static。69需要一种变量:局部作用域,限制在函数内,防止越权访问;全程存典型应用:随机数生成函数。生成随机数需要前次递推值(种子值),可选择静态局部变量intrandom(){

staticunsignedlongseed=1;returnseed=(seed*1103515245+12345)%32768;}无参函数头部:intrandom()… 或者intrandom(void)…原型必须用intrandom(void);70典型应用:随机数生成函数。无参函数头部:701、含义:寄存器是计算机CPU的重要组成部分,在c语言中允许将一些频繁使用的变量存放在计算机的寄存器中,以节省运算时间,提高效率.2、用法:用register说明。3、要点:只有局部自动变量和形参可以作为寄存器变量,其它变量不允许。一个计算机系统中的寄存器数目是有限的,不能定义任意多个寄存器变量。不同系统对register变量的处理方法不同。如:MSC和TC对register只当作自动变量处理。局部静态变量不能定义为register变量。寄存器变量711、含义:寄存器是计算机CPU的重要组成部分,在c语言中允intfac(intn){

registerinti,f=1;for(i=1;i<=n;i++)f=f*i;returnf;}intmain(){inti;for(i=1;i<=5;i++)printf(“%d!=%d\n”,i,fac(i));return0;}72intfac(intn)72内部函数与外部函数一、内部函数格式:在函数定义时加上static.

static类型标识符函数名(形参表)要点:内部函数又称为静态函数,这样的函数只限在所在的文件中.二、外部函数

格式:在函数定义时加上extern即:

extern类型标识符函数名(形参表)要点:函数被冠以extern说明函数为外部函数,可以被其他文件中的函数所调用,当一个函数在定义时,未说明static时隐含的类型为extern.73内部函数与外部函数一、内部函数二、外部函数73file1.cinta;/*外部变量定义*/externintpower();

/*外部函数说明*/intmain(){intb=3,c,d,m;printf(“enterthenumberaanditspower:\n”);scanf(“%d,%d:,&a,&m);c=a*b;printf(“%d*%d=%d\n”,a,b,c);d=power(m);printf(“%d**%d=%d\n”,a,m,d);}file2.cexterninta;/*外部变量说明*/intpower(n)

/*外部函数定义*/{inti,y=1;for(i=1;i<=n;i++)y*=a;return(y);return0;}74file1.cfile2.c741)从作用域角度看,main也是普通函数,其中的定义是局部定义,作用域是main函数的体。2)复合语句里定义的变量,存在期是该复合语句的一次执行。复合语句开始时创建,结束时撤消。复合语句再次执行时重建,新变量与撤消的变量无关,自动变量。for(n=0;n<10;n++){intm;if(n==0)m=2;/*循环第二次到这里时m的值未定*/}变量的几个问题751)从作用域角度看,main也是普通函数,其中的定义是局部定3)变量定义的嵌套函数定义只出现在全局作用域中,不可能嵌套。变量定义可出现在复合语句里,可能出现嵌套定义。规定:同一作用域里不允许定义多个同名变量。不同作用域中可以定义同名变量,不同作用域里定义的同名变量互不相干.例:intf(...){doublex,

n;....}intmain(){doublex,z;intn,m;....}763)变量定义的嵌套例:76嵌套作用域里可能出现同名变量定义,例:intf(intn){intx=2,y;....while(....){doublex=4;

x=x+1;....}

x=x+1;....}规定:内层作用域里的同名变量定义(在此局部)遮蔽外层同名变量定义。77嵌套作用域里可能出现同名变量定义,例:77用关键字const定义的变量。是变量,但不允许赋值,只能初始化,其存在期中总代表同一个值:

constintnum=10;4)常变量若出现在局部作用域里,那么也动态建立和初始化,每次初始化的值可以不同:for(i=2;i<=200;i+=2){constintn=i*i;......}可用const定义常参数,函数体里不能重新赋值。78用关键字const定义的变量。是变量,但不允许赋值,只能初始静态动态存储方式程序整个运行期间函数调用开始至结束生存期编译时赋初值,只赋一次每次函数调用时赋初值自动赋初值0或空字符不确定未赋初值静态存储区动态区存储区寄存器局部变量外部变量作用域定义变量的函数或复合语句内本文件其它文件局部变量默认为auto型register型变量个数受限,且不能为long,double,float型局部static变量具有全局寿命和局部可见性局部static变量具有可继承性extern不是变量定义,可扩展外部变量作用域register局部staticauto外部static外部存储类别变量存储类型79静态动态存储方式程序整个运行期间函数调用开始至结束生存期编译作业1.读程序写结果#include<stdio.h>intf1(int),f2(int);voidmain(){inti;for(i=2;i<5;i++)printf("f1(%d)=%d\t",i,f1(i));printf("\n");for(i=2;i<5;i++)printf("f2(%d)=%d\t",i,f2(i));printf("\n");}intf1(intx){intf=1;f*=x;returnf;}intf2(intx){staticintf=1;f*=x;returnf;}80作业1.读程序写结果intf1(intx)80作业2.阅读下列程序写结果#include<stdio.h>inta=3,b=5;intmax(inta,intb){intc;c=a>b?a:b;returnc;}voidmain(){inta=8;printf(“%d”,max(a,b));}81作业2.阅读下列程序写结果#include<stdio.h>作业3:P173第10题f(x)=sin(x)-1/4*xf’(x)=cos(x)-1/4xn+1=xn-f(xn)/f’(xn)82作业3:P173第10题82Q&A!83Q&A!83

不为失败找理由、要为成功找方法!84不为失败找理由、要为成功找方法!1高级语言程序设计主讲教师:贾彩燕计算机与信息技术学院计算机科学与技术系cyjia@85高级语言程序设计主讲教师:贾彩燕2第五章

C程序结构86第五章

C程序结构3本章讨论与C程序整体结构有关的问题。对正确理解C语言/正确书写C程序很重要。学习用C程序设计时应了解的“深层问题”。1)基本数值类型的全面介绍2)函数与C程序结构,函数原型3)变量类,作用域与存在期4)预处理命令5)字位运算符(特殊问题,初步了解,需要时深入)87本章讨论与C程序整体结构有关的问题。1)基本数值类型的全面介主要内容数值类型函数和标准库函数函数定义和程序的函数分解C程序结构与变量预处理命令定义常量字位运算符编程实例88主要内容数值类型55.1数值类型实数类型:float,double,longdouble实数类型外的算术类型都是整数类型。字符类型也看作整数类型,可以作为整数参加运算。每一基本整数类型都有带符号与无符号两种类型,用限定词signed或unsigned说明。无符号类型的值大于等于0。同一基本类型的带符号/无符号类型用同样长度编码。signed可省略,如signedlong简写为long。895.1数值类型实数类型:float,double,lon字符类型:char,signedchar,unsignedchar用一个字节表示,其中存字符编码。ASCII字符集里数字(字母)字符的编码连续排列。char等同于signedchar或unsignedchar(不同系统可能不同)。简单程序只用char,不需要关心有无符号。只有用char参加整数运算时才需要考虑。基本ASCII字符集的编码范围是0-127。90字符类型:char,signedchar,unsigned整数类型

基本:int,shortint,longint总共六个: int unsignedint short unsignedshort long unsignedlongshortint简写为short,longint简写long,unsignedint简写为unsignedshort表示范围不大于int,long不小于int。无符号/有符号类型位数相同。具体表示由C语言系统确定。基本类型是int,一般用计算机的字长表示。16位机器的C系统中,int通常用16位表示;32位机器的C系统中,int通常用32位表示;91整数类型基本:int,shortint,longin整数常量可用十进制八进制(0开头)十六进制(0x或0X开头)长整型加后缀L或lshort无常量写法无符号数加后缀u或U123U,2987654LU,327LU,32014U无符号整数的算术运算按取模方式做(不会溢出),超出表示范围时取模作为计算结果。例:若16位unsignd范围为0~65535。计算超范围时取模65536。234U+65500U的计算结果是198U。92整数常量可用十进制无符号整数的算术运算按取模方式做(混合类型运算前把小类型转换到大类型的值。整数提升:小整数(short、char等)先转为int值再运算。若转换结果超出int范围(unsignedshort提升可能出问题),就提升为unsigned。基本类型相同时,认为无符号类型是比同样的有符号类型更大的类型。例如做下面计算:2365U+18764将先由18764(整型值)转换生成unsigned对应值,再用此新值参与运算。93混合类型运算前把小类型转换到大类型的值。基本类型相同时,认为基本数据类型的选择C语言提供多个浮点类型和整数类型,供编程者选择使用。如无特殊需要,浮点数总用double,因其精度和范围能满足一般要求(float精度过低,longdouble可能低效,一般不用)。如无特殊需要,整数总用是C语言里最基本的类型,能得到硬件基本支持,其效率不会低于任何其他整数类型。有时用long类型。如无特殊需要,字符总采用char。尽量少用unsigned类型,除非服务于特殊目的。94基本数据类型的选择C语言提供多个浮点类型和整数类型,供编程主要内容数值类型函数和标准库函数函数定义和程序的函数分解C程序结构与变量预处理命令定义常量字位运算符编程实例95主要内容数值类型12编写大程序时应特别注意函数分解。没有合理函数分解不可能完成复杂工作/多花时间/程序更难理解/错误更难发现和纠正。开始就应强调好的编程习惯(包括函数分解)。函数的作用:把一段计算抽象出来,封装(包装)成独立实体。这种封装程序段称为函数定义。定义后通过函数名就可以用简便方式要求执行该函数所封装的计算。这种描述片段称为函数调用。5.2函数和标准函数库问题复杂使程序变长。大程序难开发/难阅读理解/难修改;修改时容易破坏完整性,难保证不引进新错误。程序中常出现许多相同/类似片段。使程序更长,增加不同部分间的联系,损害可修改性。96编写大程序时应特别注意函数分解。函数的作用:把一段计算抽象出基本C语言很小,ANSIC定义了标准库,其中提供最常用的与平台无关的功能。每个符合标准的C系统都提供了标准库,通常还提供一些扩充库,以便使用特定硬件/特定系统的功能:DOS上的C系统提供与DOS有关的功能函数Windows上的系统提供与Windows有关的函数UNIX系统上的系统提供与UNIX接口的函数扩充库不标准,使用扩充库的程序依赖于具体系统。库函数实现常用计算,可按规定方式调用,不必自己实现/不必关心怎样实现。开发一次使所有用户受益。C语言的库函数97基本C语言很小,ANSIC定义了标准库,其中提供最常用的与标准库功能包括

输入输出、文件操作、存储管理,其他如数学函数、数据转换函数等。有关介绍散布在各章,后面有详细介绍。对具体C系统的扩充库可查阅系统联机帮助,或查阅有关手册、参考书籍。。下面介绍两组常用标准函数。98标准库功能包括下面介绍两组常用标准函数。15字符分类(<ctype.h>)isalpha(c) c是字母字符isdigit(c)c是数字字符isalnum(c) c是字母或数字字符isspace(c) c是空格、制表符、换行符isupper(c) c是大写字母islower(c) c是小写字母iscntrl(c) c是控制字符isprint(c)c是可打印字符,包括空格isgraph(c) c是可打印字符,不包括空格isxdigit(c) c是十六进制数字字符ispunct(c) c是标点符号inttolower(intc) 转为对应小写字母inttoupper(intc) 转为对应大写字母是返回非零,不是返回零99字符分类(<ctype.h>)isalpha(c) #include<stdio.h>#include<ctype.h>intmain(){intc,cd=0,cu=0,cl=0;while((c=getchar())!=EOF){if(isdigit(c))++cd;if(isupper(c))++cu;if(islower(c))++cl;}

printf("digits:%d\n",cd);

printf("uppers:%d\n",cu);

printf("lowers:%d\n",cl);return0;}用标准库函数完成判断比自己写条件更合适。

100#include<stdio.h>用标准库函数完成判断比自#include<stdio.h>#include<ctype.h>intmain(){intcount=0,c;while((c=getchar())!=EOF){if(isspace(c))continue;++count;while((c=getchar())!=EOF&&!isspace(c));}

printf("Words:%d\n",count);return0;}统计单词程序:101#include<stdio.h>统计单词程序:18随机数生成函数程序调试:用数据做运行试验,随机数据非常合适。计算机模拟:模拟实际情况/过程,客观事物变化有随机性。最常用的是除余定义:

a0=A an=(B×an-1+C)modDA,B,C,D为常数,0≤A<D。适当选择B、C可产生0到D-1的较好随机数列。计算机只能生成“伪随机数”。常用方法是定义某种递推关系,设法使序列中的数比较具有随机性。102随机数生成函数最常用的是除余定义:计算机只能生成“伪随机数标准库提供随机数功能,需要包含文件<stdlib.h>。随机数生成函数:intrand(void)无参数,得到0和符号常量

RAND_MAX

间的随机整数。不同系统的RAND_MAX可能不同,至少为32767。函数srand用seed值设种子值:voidsrand(unsignedseed)默认初始种子值是1;rand根据当时种子值生成下一随机数并修改种子值。103标准库提供随机数功能,需要包含文件<stdlib.h>。函数根据下面公式可以得到所需范围内的随机数:n=a+rand()%b其中a为位移,是所需连续整数范围的第一个数,b是比例因子,是所需连续整数范围的宽度,则希望产生1--6之间随机数的公式为:n=1+rand()%6希望产生0—1之间随机数的公式为:n=rand()%2伪随机数的产生

104根据下面公式可以得到所需范围内的随机数:伪随机数的产生21例:编写一个投掷骰子的程序,模拟10次,输出每次投掷的点数。#include<stdio.h>#include<stdlib.h>intmain(){inti;printf(“\n”);

for(i=1;i<=10;i++)printf("%3d",1+rand()%6);return0;}结果:6655651153第二次运行:6655651153使用srand函数,通过提供不同的种子产生不同的随机数序列。srand(x);

/*初始化随机数发生器*/

unsignedx;

scanf(“%d”,&x);/*输入一个非负的整数做种子*/161343565262333153565415161343565262105例:编写一个投掷骰子的程序,模拟10次,输出每次投掷的点数。#include<stdio.h>#include<stdlib.h>voidmain(){inti;printf(“\n”);

for(i=1;i<=10;i++)printf("%3d",1+rand()%6);}结果:3453314315再次运行:4432355323

srand(time(NULL));/*使用time函数返回值做种子*/#include<time.h>例:编写一个投掷骰子的程序,模拟10次,输出每次投掷的点数106#include<stdio.h>结果:srand(主要内容数值类型函数和标准库函数函数定义和程序的函数分解C程序结构与变量预处理命令定义常量字位运算符编程实例107主要内容数值类型245.3函数定义和程序的函数分解一个C程序主要是一系列的函数定义。函数定义形式:

函数头部---

返回值类型函数名参数表

函数体库函数有限,编写复杂程序时需要自己定义函数。函数头部:描述函数外部与函数内部的联系。

应该总写返回类型,无返回值用void说明。允许任意多个参数,无参函数用(void)

(早期C语言对ANSIC的影响),定义无参函数时也可用()。1085.3函数定义和程序的函数分解一个C程序主要是一系列的函数主函数mainmain的返回值规定为int。这个返回值在程序结束时送给外部,程序外部(如操作系统)可用这个值。一般返回0表示程序正常结束,其他值表示出错main以外的函数只有被调用时才会执行不允许调用mainintmain(){/*一般写法*/......return0;}109主函数mainintmain()2611027程序的函数分解什么样的程序片段应该定义为函数:重复出现的相同/相似计算片段,可设法抽取性定义为函数。长计算过程中有逻辑独立性的片段,即使出现一次也可定义为函数,以分解复杂性。经验原则:可以定义为函数的内容,就应该定义为函数;一个函数一般不超过一页。往往存在很多可行的分解,寻找合理有效的分解是需要学习。111程序的函数分解什么样的程序片段应该定义为函数:经验原则:可以实例研究:字符图形写程序打印下面这类字符图形最“简单”的方式:用一系列putchar调用打印星号和空格(数清字符个数,就可以写出程序)。112实例研究:字符图形写程序打印下面这类字符图形最“简单”的方式方法二:程序里写一系列printf调用。例:intmain(){/*打印菱形*/printf("*");printf("**");printf("***);....../*下略*/}不好!若要修改图形大小或形式,程序需全部重写如果需要画出新图形,已做工作对新工作毫无价值应考虑画这类图形的“基本动作”,定义为函数。113方法二:程序里写一系列printf调用。例:不好!若要修改图分析:图形由以下部分组成1)一段连续字符;2)在两个特定位置的字符;字符图形未必用星号,可推广,引进一个字符参数voidline(charc,intbegin,intend)voidpoints(charc,intfst,intsnd)

可考虑定义两个函数,其头部分别为:

voidline(intbegin,intend)voidpoints(intfst,intsnd)line从begin到end输出*

温馨提示

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

评论

0/150

提交评论