【文档说明】课件-C语言高级语言程序设计一第二章C程序设计基.ppt,共(79)页,1.284 MB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-44677.html
以下为本文档部分文字说明:
高级语言程序设计(一)(CProgramming)第二讲:C程序设计基础(二)本章目标◼掌握函数的定义及调用方式◼掌握函数参数传递方式◼掌握switch多路选择◼掌握一维数组的定义和使用;◼掌握简单的文件输入/输出模块化程序设计◼将复杂问题分解为简单问题的程序设计方法称为结构
化程序设计,其特点为:⚫自顶向下(top-downdesign);⚫逐步细化(stepwiserefinement);⚫模块化(modularprogramming);◼模块化的好处:⚫功能分解的需要;⚫代码重用
;#include<stdio.h>main(){doubleradius,area,perimeter;scanf(“%lf”,&radius);area=3.1415929*radius*radius;perimeter=2*rad
ius*3.1415926;printf(“%6.2f%6.2f”,area,perimeter);}C程序设计基础4常量定义◼所有常量可以用#define来定义,即可以给一个常量命名。如:#definePI3.1415926◼使用常量定义的好处:⚫可提高程序的可读性⚫程序的
可移植性更好,可维护性更好#include<stdio.h>#definePI3.1415926main(){doubleradius,area,perimeter;scanf(“%lf”,&radiu
s);area=PI*radius*radius;perimeter=2*radius*PI;printf(“Perimeter=%6.2f”,,perimeter);}实验C程序设计基础5常量定义(续)在ANSIC中,类型修
饰符:const----其变量值在程序执行中不可以通过赋值等方法对它进行修改(是定义常量的另一种方法,用#define定义的常量无类型,而用const定义的常量有类型)。如:constfloatPI=3.14159;#include<stdio.h>constfloatPI=3
.14159;main(){doubleradius,area,perimeter;scanf(“%lf”,&radius);area=PI*radius*radius;perimeter=2*radius*PI;printf(“Perimeter=%6.2f”
,perimeter);}#include<stdio.h>main(){inta,b,sum;scanf(“%d+%d”,&a,&b);sum=a+b;printf(“Sum=%d\n”,sum);}tmainmainmainscanfprintf标准输入/输出库函数标准
(库)函数❑标准I/O库函数#include<stdio.h>(scanf,printf,getchar,putchar…)❑标准数学函数#include<math.h>(sin,cos,sqrt…)❑
…问题2.1◼问题:已知一组三角形的三边(如(2.0,2.0,2.0)、(3.0,4.0,5.0)、(2.5,3.1,3.8)),计算其面积。计算三角形面积的公式为:#include<stdio.h>#include<math.h>main(){doubles;s=(
2.0+2.0+2.0)/2;printf(“%f\n”,sqrt(s*(s-2.0)*(s-2.0)*(s-2.0)));s=(3.0+4.0+5.0)/2;printf(“%f\n”,sqrt(s*(s-3.0)*(s-4.0)*(s-5.0)));s=
(2.5+3.1+3.8)/2;printf(“%f\n”,sqrt(s*(s-2.5)*(s-3.1)*(s-3.8)));}对于这样的有规律的重复计算,可以用更好的方法:函数来解决)(21,))()((cbascsbsassS++=−−−=其中doublesqrt(d
oublex)为标准数学库中函数,使用前应加上#include<math.h>定义求三角形面积函数tri_area()doublea,doubleb,doublecdouble{}•函数名•需要传递给函数的数据(参数):数据类型、数据名称•函数计算
结果(返回)类型double•函数是如何对数据进行计算(函数体)doublea,doubleb,doublectri_areatri_area函数定义doubletri_area(doublea,doubleb,doubl
ec){doubles,area;s=(a+b+c)/2.0;area=sqrt(s*(s-a)*(s-b)*(s-c));returnarea;}函数定义头部,其中double为函数类型tri_area为函数名a,b,c为函数参数函数体
局部变量函数返回(return)语句,返回计算结果函数定义◼在ANSIC标准中,函数定义形式为:类型函数名(参数说明){[局部变量定义或说明]语句}0个、一个或多个参数,多个参数以逗号,分隔称为形参,格式:数据类型参数名函数定义(续)◼函数名一般是标识符,一个程序只有一个ma
in函数,其它函数名可随意取,当然最好是有助于记忆的名字。◼局部变量定义或说明可有可无,在ANSIC标准中,局部变量定义或说明应放在函数体的最前面。◼在ANSIC标准中,函数(返回值)类型不允许省略,即使是返回整型值(int),当函数无返
回值时,应其类型说明为void类型。若需要返回值:return表达式;若不需要返回值:return;或者没有return语句函数定义(续)*在C语言中,函数不能嵌套定义。如,下面定义在C语言中是不充许的:f(){g(){…}…}问题2.1:代码
实现#include<stdio.h>#include<math.h>doubletri_area(doublea,doubleb,doublec){doubles,area;s=(a+b+c)/2.0;area=sqrt(s*(s-a)*(s-b)*(s-c));return(area
);}intmain(){doublearea;area=tri_area(2.0,2.0,2.0);printf(“%f\n”,area);area=tri_area(3.0,4.0,5.0);printf(“%f\n”,area)
;area=tri_area(2.5,3.1,3.8);printf(“%f\n”,area);return0;}函数调用实验或者:intmain(){printf(“%f\n”,tri_area(2.0,2.0,2.
0));printf(“%f\n”,tri_area(3.0,4.0,5.0));printf(“%f\n”,tri_area(2.5,3.1,3.8));return0;}函数调用函数调用形式:函数名([实
参表])其中实参个数、类型、排列次序应和形参定义时一致。函数通过return语句将值返回给调用函数。它有两种使用形式:1)returnexpr;2)return;注意:使用return语句只能返回一个值。函数
调用可以作为单独语句,也可以出现在表达式中函数定义与调用(续)*注意:当一个函数带有返回值时,应保证函数每个可能执行路径上应有返回值。如下面将大写字母转换为小写字母函数:chartoLower(charc){if(c>=‘A’&&c<=‘Z’)/
*error!*/returnc+‘a’–‘A’;}正确写法:chartoLower(charc){if(c>=‘A’&&c<=‘Z’)returnc+‘a’–‘A’;returnc;}问题2.1:代码实现#include<stdio.
h>#include<math.h>intmain(){printf(“%f\n”,tri_area(2.0,2.0,2.0));printf(“%f\n”,tri_area(3.0,4.0,5.0));printf(“%f\n”,tri_
area(2.5,3.1,3.8));return0;}doubletri_area(doublea,doubleb,doublec){doubles,area;s=(a+b+c)/2.0;area=sqrt(s*(s-a)*(s-b)*(s-c));return(area);}do
ubletri_area(doublea,doubleb,doublec);函数原型实验函数原型说明(prototype):◼在ANSIC标准中,所有函数调用之前必须要有函数定义或原型说明,函数原型用以说明函数的返回值类
型、函数参数类型、个数及次序。函数原型说明有两种形式:⚫直接使用函数的头部(函数头部后加分号)。如,doubletri_area(doublea,doubleb,doublec);⚫在原型说明中仅给出类型、个数及次序,无形参变量名。如,doubletri_area(
double,double,double);注意:函数原型说明的类型、参数类型、个数及次序必须与函数定义时一致,否则会产生错误。函数参数voidswap(intx,inty){inttemp;temp=x;x=y;y=temp;}int
main(){inta=2,b=3;swap(a,b);return0;}请问a和b是否交换?不能!调用swap后调用swap(a,b)如何通过函数调用改变参数的值将在后续章节中介绍。拷贝:传值调用23ab23xy32xy实验函数参数(续)◼注意:C函数
的参数传递全部采用传值。传值调用实际上重新拷贝了一个副本给形参。传值的好处是传值调用不会改变调用函数实参变量的内容,因此,可避免不必要的副作用。问题2.2:求素数◼读入一个整数,求该整数范围内的所有素数。◼解题步骤:读入一个整数到n;f
or(m=2;m<=n;i++)if(m是素数)输出m;可定义一个函数intisprime(intn)来判断一个整数是否为素数,若是返回1,否则返回0。问题2.2:代码实现intisprime(intn){intm;if(n<=1)ret
urn0;for(m=2;m*m<=n;m++)if(n%m==0)/*存在因子,不是素数*/return0;return1;}主函数#include<stdio.h>intisprime(intn);intmain(){intn,m;scanf(“%d”,&n);for(
m=2;m<=n;m++)if(isprime(m))printf(“%d“,m);return0;}实验局部变量◼局部变量(localvariable),又称自动变量:在函数(或块结构)中定义的变量。⚫使用范围:只在定义它
的函数或块结构内有效。⚫定义时可加auto关键字,也可省略:autointindex;等同于:intindex;⚫编译程序不对局部(自动)变量给予隐含的初值,故其初值不确定。因此,每次使用前,必须明确地置初值。⚫局部(自动)
变量随函数的调用而存在,函数返回后将消失,由一次调用到下一次调用之间不保持值,每次调用函数时都重新初始化。⚫形参是自动变量,使用范围仅限于相应函数内。计算x的幂:#include<stdio.h>doublepower(doublex,intn);intmain(){intn,m,i;double
f;scanf(“%d”,&m);for(i=0;i<m;i++){scanf(“%lf%d”,&f,&n);printf(“%f\n”,power(f,n));}return0;}doublepower(doublex,
intn){doublef;f=1;while(n>0){f=f*x;n--;}return(f);}doublef;doublef;f=1;实验如何划分函数◼程序中可能有重复出现的相同或相似的计算片段,可以考虑从
中抽取出共同的东西,定义为函数。这样可以缩短程序代码,提高程序的可读性和易修改性。◼程序中具有逻辑独立的片段定义为函数。这样做主要用于分解程序的复杂性。#include<stdio.h>doublepower(doublex,intn){inti;doublep;p=1;f
or(i=1;i<=n;++i)p=p*x;return(p);}intmain(){floatx;scanf(“%f”,&x);printf(“Xpower2=%f\n”,power(x,2));printf(
“Xpower3=%f\n”,power(x,3));printf(“Xpower4=%f\n”,power(x,4));return0;}#include<stdio.h>voidprintPower(doublex,intn
){inti;doublep;p=1;for(i=1;i<=n;++i)p=p*x;printf(“Xpower%d=%f\n”,n,p);}intmain(){floatx;scanf(“%f”,&x);printPower(x,2);prin
tPower(x,3);printPower(x,4);return0;}实验27问题2.3:简易计算器【问题描述】编程实现简单的交互式计算器,能进行整数的+-*/运算。【输入形式】从键盘读入如下形式的输入行,数据与运算符之间可以用一个空格分隔:120350+52/【输出形式】若是/运算,小数点后
保留两位有效数字4702.5028问题2.3:问题分析◼如何读入数据及运算符?intdata1,data2;charop;scanf(“%d%d%c”,&data1,&data2,&op);29问题2.3:算法设计intdata1,
data2,result1;floatresult2;charop;从标准输入中读入整数data1,整数data2及运算符op判断op:若为‘+’,则result1=data1+data2;若为‘-’,则result1=data1-
data2;若为‘*’,则result1=data1*data2;若为‘/’,则result2=data1/data2;若op为‘+’,‘-’或’*’,输出结果result1;若op为‘/’,输出结果resu
lt2;op值加运算‘+’减运算乘运算除运算‘-’‘*’‘/’多路选择注意:由于data1和data2为整数,结果仍为整数。要用强制类型转换才能得到小数位。result2=(float)data1/data2;多路选择,可使用if-elseif语句实现。在此,更适合sw
itch语句。第三讲:程序设计方法-问题分析30多路选择:switch语句◼基本形式:switch(表达式){case常量表达式1:语句1或空;case常量表达式2:语句2或空;…case常量表达式n:语句n或空;default:语句n+1或空
;}◼语义动作为:①先计算表达式的值;②该值与每一个case后的常量进行比较;③若匹配,则控制就转向该常量后的语句;④若不匹配,若有default,则转向default后的语句,否则什么也不做;S1S2SnSn+
1EC1C2…Cndefault因此,switch语句特别适合于依据一组常量值来进行判断的多路选择。第三讲:程序设计方法-问题分析31多路选择:switch语句(续)注意:1.常量表达式必须是整型(if_elseif可能根据任意条件来进行多路选择);2.在同一个swi
tch中不应出现两个具有同样的常量;3.default语句如果有,只允许出现一次,default可出现在switch中的任何位置,通常放在最后;4.case和default本身不改变控制流(这与pascal中的case语句不同),中断离开switch
要用break;5.case后的语句可以是单个语句,也可以是复合语句(但不带开头和结尾的花括号)32#include<stdio.h>intmain(){intdata1,data2,result1;floatresult2;charop;
scanf(“%d%d%c”,&data1,&data2,&op);switch(op){case'+':result1=data1+data2;case'-':result1=data1-data2;case'*':result1=data1*da
ta2;case'/':result2=(float)data1/data2;default:printf("Inputerror!\n");}if(op==‘+’||op==‘-’||op==‘*’)prin
tf("%d“,result1);elseif(op==‘/’)printf(“%.2f\n“,result2);return0;}测试数据:120350+1212-352*32/break;break;break;break;break;33问题2.3:常见问题◼在sw
itch中遗漏break#include<stdio.h>intmain(){intdata1,data2,result1;floatresult2;charop;scanf(“%d%c%d”,&data1,&op,&data2);switc
h(op){case'+':result1=data1+data2;break;case'-':result1=data1-data2;break;case'*':result1=data1*data2;break;case'
/':result2=(float)data1/data2;break;default:printf("Inputerror!\n");break;}if(op==‘+’||op==‘-’||op==‘*’)printf("%d%c%d
=%d\n“,data1,op,data2,result1);elseif(op==‘/’)printf("%d%c%d=%.2f\n“,data1,op,data2,result2);return0;}测
试数据为:120+350结果为:120+350=-230Why?问题2.4◼问题:“在一行上输入10个整数,在下一行上反序输出”。◼输入样例:233245556778910467323◼输出样例:233467109
786754552332问题2.4:问题分析◼首先遇到的问题是如何保存输入的数据?◼以目前所学的知识,我们可以设置10个变量来存储输入如:intdata1,data2,…,data10;◼这样做的缺点:⚫程序处理数据非常烦琐,如我们必须依次读入每个数据(不
能用循环);⚫程序不具扩展性,如果我们要处理100个、1000个甚至更多的数据,怎么办?◼如何存储类型相同并且紧密相关的一组数据?使用数组数组的定义与初始化◼数组是变量的有序集合,数组的所有成员(数组元素)都具有相同的数据类型。◼数组定义一般采用如
下格式:类型数组名[长度];--长度为常量表达式数组的定义与初始化(续)◼例如:inta[50];a[0]~a[49]…a[0]a[1]数组元素的下标是从0开始,即数组中第一个元素的下标为0数组的定义与初始化(续)注
意:C语言不支持动态数组,即数组的长度必须在编译时确定下来,而不是在运行中根据需要临时决定。但C语言提供了动态分配存贮函数,利用它可实现动态申请空间。intlength;scanf(“%d”,&length);doubles[length];长度必须是常量表达
式实验数组的定义与初始化(续)◼数组初始化:可以在定义时初始化一个数组。下面是一些数组初始化实例:doublesales[5]={12.25,32.50,16.90,23,45.68};doublesales[]={12.25,32.50,16.90,23,45.68};intlist[5]={
6,5,12};相当于:intlist[5]={6,5,12,0,0}以实际元素的个数决定数组的大小实验charstring[10]={‘h’,‘e’,‘l’,‘l’,‘o’,‘\0’}charstring[10]=“hello”;charstring[]=“hello”;注
意:用字符串常量初始化一个字符数组时,其长度应至少比字符个数多1。数组的定义与初始化(续)hlel\0o0124359实验数组元素的访问◼初始化数组intarray[10],i;for(i=0;i<10;i++)array[i]=1;◼读入
数组元素intarray[10],i;for(i=0;i<10;i++)scanf(“%d”,&array[i]);注意:不要将循环条件写为i<=10。这是初学者常犯的错误。如果一个数组的长度为N,则遍历数组的循环常写为:for(i=0;i<N;i++)
或for(i=0;i<=N-1;i++)编译器不提供数组下标越界检查,下标越界时可以通过编译,但运行时会出错格式:数组名[下标]实验数组元素的访问(续)◼求数组中最大元素maxIndex=0;/*maxIndex记录最大元素的下标*/for(i=0;i<N;i+
+)if(array[maxIndex]<array[i])maxIndex=i;maxElement=array[maxIndex];实验或者:maxElement=array[0];for(i=1;i<N;i++)if(maxElement<array[i])maxE
lement=array[i];数组处理的限制◼在C中不允许对数组进行整体操作。下面用法是错误的:intx[10],y[10];scanf(“%d”,x);y=x;if(x==y)…y={1,2,3,4,5};比较数组正确做法是
:for(i=0;i<10;i++)if(x[i]!=y[i])…正确做法是:for(i=0;i<10;i++)scanf(“%d”,&x[i]);正确做法是:for(i=0;i<10;i++)y[i]=x[i];复制数组只能在定义数组时整体初始化,不能整体赋值。实验问
题2.4◼问题:“在一行上输入10个整数,在下一行上反序输出”。◼输入样例:233245556778910467323◼输出样例:233467109786754552332问题2.4:解题步骤1、定义保存
数据的数组data[10]和下标变量index;2、index设为数组第一个元素的下标;3、Whileindex小于103.1、读入数据并保存到下标为index的数组元素中;3.2、index增1;4、index设为最后一个元素的下标;5、Wh
ileindex大于等于05.1、打印下标为index的数组元素;5.2、index减1;问题2.4程序实现:#include<stdio.h>intmain(){intdata[10];intindex;fo
r(index=0;index<10;index++)scanf("%d",&data[index]);printf("\n");for(index=9;index>=0;index--)printf("%d",data[index]);return0;}实验问题2.5◼问题
:统计输入中每个数字字符的出现次数◼分析:⚫方法一:显然可以使用10个int型变量来分别存储每个数字字符的出现次数。然后在程序中,使用if_elseif来分别统计每个数字字符的出现次数。(该方法太笨拙)问题2.5:分析(续)◼方法二⚫可以使用数组来存储每个数字字符
的出现次数。如:intdigit[10];⚫如何将输入的数字字符与相应数组下标对应?表达式:c–‘0’可将数字字符c转换为相应整数。因此,下面语句可统计每个数字字符的出现次数:digit[c-‘0’]++;问题2.5:代码实现#incl
ude<stdio.h>intmain(){inti,c,digit[10]={0,0,0,0,0,0,0,0,0,0};while((c=getchar())!=EOF)if(c>=‘0’&&c<=‘9’)digit[c-‘0’]++;for(i=0;i<10;i++)pri
ntf(“Numberof%d:%d\n”,i,digit[i]);return0;}如何将打印整数数组封装成一个函数?实验例:打印整数数组函数voidprint(inta[10]){inti;for(i=0;i<10;i++)printf(“%d\n”,a[i]);}voi
dprint(inta[],intlength){inti;for(i=0;i<length;i++)printf(“%d\n”,a[i]);}数组长度一般作为单独参数传递给函数注意:1、数组长度一般不写在一
维数组形参内,因为编译器不作检查。2、该函数不能打印任意长度的整数数组。intmain(){inti,c,digit[10]={0,0,0,0,0,0,0,0,0,0};while((c=getchar())!=EOF)if(c>=‘0’&&
c<=‘9’)digit[c-‘0’]++;print(digit,10);return0;}数组作为实参,只写数组名,千万不要写成digit[10]#include<stdio.h>voidprint(inta
[],intlength){inti;for(i=0;i<length;i++)printf(“%d\n”,a[i]);}能否将统计功能也封装成函数呢?实验voidcount(inta[]){intc;while((c=getchar())!=EOF)if(c>=‘0’&&c<=‘9’
)a[c-‘0’]++;}intmain(){intdigit[10]={0};count(digit);print(digit,10);return0;}例:统计数字出现次数函数数组中的值能传递回来吗?01……9digita实验数组作为函数参数◼数组可以
作为参数传递给函数。实际上传递的是数组的首地址(即数组第一个元素的地址,将在指针部分说明),我们可以这样理解数组作为参数传递:形参数组与实参数组是一对共享同一数据区的数组,即它们是同一个数组,而不是对实参数组的拷贝。◼数组作为参数时,函数的定义形式:voidfun(intar
ray[],intsize){…}◼数组作为参数时,函数的调用形式:main(){inta[10];….fun(a,10);….}注意:定义数组形参时,数组长度可省略,同时,还应在形参中指定数组元素个数。注意:函数调用时,用数组名作实参。字符数组数组元素的类型是char。charmes
[]=“CLanguage”;charline[100]=“Programming”;◼字符数组有如下特点:⚫数组元素跟一般变量一样可赋值、比较、计算等。⚫数组下标也是从0~N-1(N为数组长度)。⚫字符数组长度可以显式给出,也可以隐式得到。⚫由双引号括起来的的字符串常量具有
静态字符串数组类型。⚫对数组初始化时,编译程序以\0作为结束符添加到字符串最后。因此,数组长度要比字符串长度多1。问题2.6:将数字字符串转换成整数n=0whiles[i]为数字字符n=10*n+s[i]–‘0’;“123”‘1’-‘0’=11*10+‘2’-
‘0’=1212*10+‘3’-‘0’=123方法分析问题2.6:代码实现intatoi(chars[]){inti,n,sign;for(i=0;s[i]==‘‘||s[i]==‘\n’||s[i]==‘\t’;i++);/*skipwh
itespace*/sign=1;if(s[i]==‘+’||s[i]==‘-‘)sign=(s[i++]==‘+’)?1:-1;for(n=0;s[i]>=‘0’&&s[i]<=‘9’;i++)n=10*n+s[i]–‘0’;return(sign*n);}字符
数组。空语句条件运算符:<表达式1>?<表达式2>:<表达式3>先计算表达式1,若其值为非零,则整个表达式结果为表达式2的值,否则就为表达式3的值。#include<stdio.h>intatoi(chars[]);m
ain(){chars[20];scanf(“%s”,s);printf(“%d\n”,atoi(s));}实验问题2.7:将字符串颠倒“…………”方法分析交换问题2.7:代码实现voidreverse(chars[]){intc,i,j;
for(i=0,j=str_len(s)-1;i<j;i++,j--){c=s[i];s[i]=s[j];s[j]=c;}}intstr_len(chars[]){inti=0;while(s[i]!=‘\0
’)++i;return(i);}#include<stdio.h>intreverse(chars[]);intstr_len(chars[]);main(){chars[20];scanf(“%s”,s);reverse(s);printf(“%s\n”,s);}
当有多个循环变量时,要用逗号隔开。逗号表达式:如e1,e2顺序求e1和e2,以e2值作为整个表达式结果的值。如,a=(t=3,t+2);结果为5字符数组作为函数参数传递时,不需要同时传递数组长度。因为字符数组中字符串是以’\0’结束的。实验问题2.8:将文件in.txt拷
贝至新文件out.txt中。问题分析:如何读取、保存文件内容?将标准输入拷贝到标准输出非常简单:#include<stdio.h>intmain(){intc;while((c=getchar())!=EOF)putch
ar(c);return0;}文件文件操作◼文件操作基本过程打开文件读写文件关闭文件首先在程序文件的头部应有如下语句:#include<stdio.h>stream(流,读写通道)程序结束前应该关闭文件!程序文
件文件打开文件FILE*fp;fp=fopen(文件名,文件使用方式);FILE是<stdio.h>文件中定义的结构数据类型,包含文件有关信息:读或写工作方式;当前读/写位置等等。一般用户不必关心。若成
功打开指定文件,则fopen返回指向该文件的FILE类型指针;若打开文件失败,则返回NULL。文件指针:与打开的文件绑定在一起,以后将使用该指针实现对文件的所有操作文件打开文件(续)fp=fopen(文件名,文件使用方式);文件名:字符串,可以
只写文件名,也可以包含路径。只写文件名时,表示文件在当前目录下,当前目录是指:➢从VC运行时,工程文件和源程序所在目录。➢双击*.exe程序运行时,该*.exe程序所在目录。包含路径实例:“c:\temp\t
ext.txt”“c:\\temp\\text.txt”文件打开文件(续)fp=fopen(文件名,文件使用方式);使用方式也是字符串,表示打开文件的方式,字符流方式包括:“r”:表示读;“w”:表示写;“a”:表示添加;“r+”:表示读写已有文件
;“w+”:表示读写新文件;“a+”:表示读及添加;文件打开文件(续)◼用“w”或“a”方式调用fopen打开一个不存在的文件,系统会首先自动创建该文件。然后再把它打开。◼用“w”方式打一个已存在的文件,则该文件
原有内容全部消失。◼用“a”方式打开一个已存在的文件,则原文件内容保留不变,新添加的内容将加到它的后面去。◼用“r”方式打开一个已存在的文件是正常的使用文件,若用“r”方式而打开一个尚未存在的文件,则会出错,此时返回NULL。因此,一个好的程序设计风格,应判断打开文件的返回值,并进行处理。一个打开
文件的典型用法:…if((fp=fopen(filename,“r”))==NULL){printf(“Can’topenfile%s!\n”,filename);return-1;}…文件◼“r+”是对一个已存在的
文件进行读和写操作。◼“w+”同样对一个已存在的文件打开时,原数据消失,因此,修改一个已有文件的内容时,必须以“r+”方式打开。◼“a+”写入的数据均在文件最后,而数据却可由文件任何位置上读取。打开文件(续)注意:文件必须打开
后,才可进行读写。文件打开文件(续)◼例如:以只读方式打开一个文件“hello.c”。fp=fopen(“hello.c”,“r”);◼例如:以写方式打开一个文件“output.dat”,该将文件位于C:盘根目录下。fp=fopen(“c:\\output.dat”,“w”);
文件读写文件◼字符输入函数:intfgetc(FILE*fp);从fp所指向的文件中读取一个字符并返回。若文件结束或调用失败,返回EOF◼字符输出函数:intfputc(intch,FILE*fp);将字
符ch写入fp所指向的文件。若成功,则返回写入的字符;若失败,返回EOF文件关闭文件关闭文件函数:intfclose(FILE*fp);关闭fp文件指针所指向的文件,并释放fp文件指针。若成功关闭,返回0,否则返回EOF注意:◼fp
必须是fopen返回的指针,并且调用关闭函数后,fp被释放掉,不能再利用fp进行读写文件操作。◼若文件不再使用,应及时关闭文件。在程序结束前,应该关闭所有打开的文件(否则有可能丢失数据)。问题2.8:将文件in.
txt拷贝至新文件out.txt中。算法分析:1.打开文件in.txt。2.打开文件out.txt。3.从文件in.txt读取一个字符保存到ch中。4.是否到达文件尾部?4.1将ch保存到out.txt中。4.2再从in
.txt读取一个字符保存到ch中。5.关闭文件。文件#include<stdio.h>intmain(){charch;FILE*in,*out;if((in=fopen("in.txt","r"))==NULL
){printf("Can'topenin.txt!");return-1;}if((out=fopen("out.txt","w"))==NULL){printf("Can'topenout.txt!");return-1;}while((ch=fgetc(in))!=EOF)fputc(ch,
out);fclose(in);fclose(out);return0;}问题2.8:测试◼首先在该程序工程文件(即.dsp文件)目录下准备一个包含一定内容的input.txt文件。◼程序正确运行后,将在同一目录下生成一个output.txt文件。◼检查文件input.txt和ou
tput.txt内容是否完全一样。实验常见问题◼程序风格◼如何从循环嵌套中跳出◼continue与while、for循环◼数组元素未赋值就使用(通过调试解决)模块化程序设计程序风格比较:#include<stdio.h>main
(){inta[1000],b[1000];inti,j,m;for(i=0;i<1000;i++){scanf("%d",&a[i]);if(a[i]==-1)break;}for(j=0;j<1000;j++){scanf("%d",&b[j]);if(b[j]==-1)break;}f
or(i=0;i<1000;i++){for(j=0;j<1000;j++){m=0;if(a[i]==b[j]){m=1;break;}}if(m==0)printf("%d",a[i]);}}#include<stdio.h>main()
{inta[1000],b[1000];inti,j,m;for(i=0;i<1000;i++){scanf("%d",&a[i]);if(a[i]==-1)break;}for(j=0;j<1000;j++){scanf("%d",&b[j]);if(b[
j]==-1)break;}for(i=0;i<1000;i++){for(j=0;j<1000;j++){m=0;if(a[i]==b[j]){m=1;break;}}if(m==0)printf("%d",a[i]);}}程序设计实践:
程序设计风格(StyleorConvention)(一)◼为什么要强调程序设计风格:可以改善软件的可读性,帮助程序员理解代码。模块化程序设计如何从嵌套循环中跳出输入两组正整数a、b,都以-1作为结束标志,从数组a中找到第一个与数组b相同的元素并输出,若找不到则输出Noanswer。输入:34569
102-126967567506-1输出:56解题步骤:1、输入两组数分别存储在数组a、b中;2、对于数组a中的每一个元素a[i],分别与数组b中的每一个元素b[j]进行比较,若a[i]==b[j],则输出a[i]3、若都找不到,输出Noanswer。#include<std
io.h>main(){inta[100],b[100];inti,j;intfound=0;for(i=0;i<100;i++){scanf("%d",&a[i]);if(a[i]==-1)break;}for(j=0;j<100;j++){scanf("%d",&b[
j]);if(b[j]==-1)break;}for(i=0;a[i]!=-1;i++){for(j=0;j<b[j]!=-1;j++){if(a[i]==b[j]){found=1;printf(“%d”,a[i]);break;}}if
(found)break;}if(!found)printf(“Noanswer”);}如何从嵌套循环中跳出变量found表示是否找到相同元素通过再次判断跳出两重循环#include<stdio.h>main(){inta
,b;for(a=1,b=1;a<=100;a++){if(b>=20)break;if(b%3==1){b+=3;continue;}b-=5;}printf("%d,%d\n",a,b);}continue与while、for循环#include<stdio.
h>main(){inta,b;a=1,b=1;while(a<=100){if(b>=20)break;if(b%3==1){b+=3;a++;continue;}b-=5;a++;}printf("%d,%d\n",a,b);}◼如何调试函数?◼如何查看字符数据?◼如何查看数组中的数
据?(问题2.5颠倒字符串程序为例)◼如何测试文件操作?(2.6拷贝文件为例)◼数组元素未赋值就使用(通过调试解决)程序设计实践:调试程序(2)数组调试示例:#include<stdio.h>voidmain(){inta[1000],b[1000];inti,j,m;for
(i=0;i<1000;i++){scanf("%d",&a[i]);if(a[i]==-1)break;}for(j=0;j<1000;j++){scanf("%d",&b[j]);if(b[j]==-1)break;}for(i
=0;i<1000;i++){for(j=0;j<1000;j++){m=0;if(a[i]==b[j]){m=1;break;}}if(m==0)printf("%d",a[i]);}}