第2章资料C语言第二章.docx

上传人:b****5 文档编号:3574102 上传时间:2022-11-24 格式:DOCX 页数:44 大小:41.84KB
下载 相关 举报
第2章资料C语言第二章.docx_第1页
第1页 / 共44页
第2章资料C语言第二章.docx_第2页
第2页 / 共44页
第2章资料C语言第二章.docx_第3页
第3页 / 共44页
第2章资料C语言第二章.docx_第4页
第4页 / 共44页
第2章资料C语言第二章.docx_第5页
第5页 / 共44页
点击查看更多>>
下载资源
资源描述

第2章资料C语言第二章.docx

《第2章资料C语言第二章.docx》由会员分享,可在线阅读,更多相关《第2章资料C语言第二章.docx(44页珍藏版)》请在冰豆网上搜索。

第2章资料C语言第二章.docx

第2章资料C语言第二章

2.4小结与习题

2.4.1输出技巧

首先是输出技巧。

通过对程序2-1进行小小的改动来实现输出2,4,6,8,…,2n,每个一行。

为了方便,现把程序复复制如下:

1#include

2intmain()

3{

4inti,n;

5scanf("%d",&n);

6for(i=1;i<=n;i++)

7printf("%d\n",i);

8return0;

9}

任务1:

修改第7行,不修改第6行。

解答:

修改第7行的如下:

7printf("%d\n",2*i);

任务2:

修改第6行,不修改第7行。

解答:

修改第6行的如下:

6for(i=2;i<=2*n;i+=2)

2.4.2浮点数陷阱

“!

=”运算符表示“不相等”,则下面的程序的运行结果是什么?

#include

intmain()

{

doublei;

for(i=0;i!

=10;i+=0.1)

printf("%.1lf\n",i);

return0;

}

说明:

对于i可以达到10.0,但永远不会与10相等,所以for循环是一个死循环。

对于float和dobule类型的数据不能直接用==和!

=来比较大小,即不要测试精确的浮点型数值,需要用精度比较,来测试一个可接受的数值范围。

如:

for(i=0;fabs(10-i)>1e-5;i+=0.1)

2.4.5小结

现在对本章介绍的循环总结如下:

(1)介绍了在编程中的一些经验,如使用计算器、累加器、以及“当前最小/最大值”这样的中间变量。

使用printf输出一些关键的中间变量能有效地帮助我们了解程序执行过程、发现错误。

(2)遇到问题需要自己分析和设计,可以先写出“伪代码”,然后转换成程序。

伪代码是为了让思路更清晰,突出主要矛盾。

(3)编写好程序后,测试显得相当重要。

如前面的例子中几乎都有陷阱:

运算结果溢出、运算时间过长等。

(4)再次强调:

编程不是看书看会的,也不是听课听会的,而是练会的。

2.4.6上机练习

习题2-1位数(digit)

输入一个不超过109的正整数,输出它的位数。

例如12735的位数是5。

请不要使用任何数学函数,只用四则运算和循环语句实现。

【分析】

采取的策略是不断地整除10,检查商是否大于10。

程序如下:

习题2-2水仙花数(daffodil)

输出100~999中的所有水仙花数。

若3位数ABC=A2+B2+C2,则称其为水仙花数。

例如153=13+53+33,所以153是水仙花数。

【分析】

采取的策略是穷举100~999之内的所有数据,检查是否满足题目的要求。

程序如下:

/*ShineCheng注:

以下程序a,b,c变量名字取的不是很好,建议大家用更清晰的方法,如bai,shi,ge。

*/

#include

intmain(){

intn,a,b,c;/*n的百、十、个位*/

for(n=100;n<=999;n=n+1){

a=n/100;

b=(n-a*100)/10;/*也可以写成b=(n%100)/10;*/

c=n%10;

if(n==a*a*a+b*b*b+c*c*c)/*算术运算的优先级要高于逻辑运算*/

printf("%d\n",n);

}

Return0;

}

习题2-3韩信点兵(hanxi)

相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排、五人一排、七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。

输入3个非负整数a,b,c,表示每种队形排尾的人数(a<3,b<5,c<7),输出总人数的最小值(或报告无解)。

已知总人数不小于10,不超过100。

样例输入:

216

样例输出:

41

样例输入:

213

样例输出:

Noanswer

【分析】

采取的策略是用穷举法解题;总人数(10,100]。

程序如下:

#include

intmain(){

inta,/*三人一排,余a人*/

b,/*五人一排,余b人*/

c,/*七人一排,余c人*/

sum;/*总人数*/

scanf("%d%d%d",&a,&b,&c);

for(sum=10;sum<=100;sum=sum+1){

if((sum%3==a)&&(sum%5==b)&&(sum%7==c)){

printf("%d",sum);

break;

}

}

if(sum>100)printf("Noanswer");

return0;

}

习题2-4倒三角形(triangle)

输入正整数n≤20,输出一个n层的倒三角形。

例如n=5时输出如下:

#########

#######

#####

###

#

【分析】

该图形一共有n行,这次要考虑每行中,先输出若干个空格,所以,其外循环为:

for(i=1;i<=n;i++){

输出若干个空格

输出若干#

换行

}

下面列出在第i行,其空格数,#字符数与i的关系为:

行i空格数#字符数

102n-1

212n-3

ii-12n-2i+1

n-1n-23

nn-11

即第i行的空格数为i-1个,#字符个数为2n-2i+1。

#字符个数为2n-2i+1是如何得来的呢?

如果将行从第n行记为第1行,第n-1行记为第2行,…,则原第i行现在记为第n-i+1行。

现在行号为第1行的#字符的个数为1,现在行号为第2行的#字符的个数为3=2*2-1,所以原第i行现在记为第n-i+1行,输出的#字符的个数为2(n-i+1)-1=2n-2i+1。

所以在第i行输出空格和输出#字符的内循环分别为:

for(j=1;j<=i-1;j++)

printf("");

for(j=1;j<=2n-2i+1;j++)

printf("%c",'#');

合起来,构成一个完整程序。

程序如下:

#include

intmain(){

intn,/*输出n行;n<=20*/

i,/*打印第i行*/

j;

scanf("%d",&n);

for(i=1;i<=n;i=i+1){

/*在第i行,打印(i-1)个空格*/

for(j=1;j<=i-1;j=j+1)printf("");

/*在第i行,打印(2*n-2*i+1)个#*/

for(j=1;j<=(2*n-2*i+1);j=j+1)printf("#");

printf("\n");/*输出结束后换行,否则所有的#号在同一行输出*/

}

return0;

}

引申1:

用for循环编程画出下列图形:

M

MM

MMM

MMMM

MMMMM

MMMMMM

MMMMMMM

MMMMMMMM

MMMMMMMMM

MMMMMMMMMM

【分析】

该图形一共有10行,每一行增加一个字符,所以,应循环10次,每次输出一行,其循环模式为:

for(i=1;i<=10;i++){

输出第i行

换行

}

“输出第i行”是在for循环中的一个小循环。

每次执行“输出第i行”,其长度都是不一样的,但长度的变化正好与循环变量i同步,故可以依赖于i。

注意到第i行的M字符数与i的关系。

行iM数

111

222

333

101010

所以,可以得到“输出第i行”的循环为:

for(j=1;j<=i;j++)printf(“%c”,’M’)

完整的程序如下:

#include

intmain(){

inti,j;

for(i=1;i<=10;i++){

for(j=1;j<=i;j++)

printf("%c",'M');

printf("\n");

}

return0;

}

说明:

对付这种字符图形,一般用两重循环,外循环遍历所有行,内循环遍历行中每个字符。

引申2:

输出下列图形:

MMMMMMMMMMMMMMMMMMM

MMMMMMMMMMMMMMMMM

MMMMMMMMMMMMMMM

MMMMMMMMMMMMM

MMMMMMMMMMM

MMMMMMMMM

MMMMMMM

MMMMM

MMM

M

【分析】

该图形一共有10行,这次要考虑每行中,先输出若干个空格,所以,其外循环为:

for(i=1;i<=10;i++){

输出若干个空格

输出若干M

换行

}

下面列出在第i行,其空格数,M数与i的关系为:

行iM数

1019

2117

3215

4313

1091

即第i行的空格数为i-1个,M个数为21-2i。

即在第i行输出空格和输出M字符的内循环分别为:

for(j=1;j<=i-1;j++)

printf(“”);

for(k=1;k<=21-2i;k++)

printf(“%c”,’M’);

合起来,构成一个完整程序。

完整程序如下:

#include

intmain()

{

inti,j,k;

for(i=1;i<=10;i++)

{

for(j=1;j<=i-1;j++)

printf("");

for(k=1;k<=21-2*i;k++)

printf("%c",'M');

printf("\n");

}

return0;

}

引申3:

输出下列图形:

A

ABC

ABCDE

ABCDEFG

ABCDEFGHI

ABCDEFGHIJK

ABCDEFGHIJKLM

ABCDEFGHIJKLMNO

ABCDEFGHIJKLMNOPQ

ABCDEFGHIJKLMNOPQRS

【分析】

该图形一共有10行,这次要考虑每行中,先输出若干个空格,所以,其外循环为:

for(i=1;i<=10;i++){

输出若干个空格

输出若干字符

换行

}

如果要输出A起头依序的n(n<27)个字母,可以为:

for(ch='A';ch<'A'+n;++ch)

printf("%c",ch);

下面分析每一行中的空格数与字符数与第i行之间的关系:

行iM数

191

283

375

467

10019

即第i行的空格数据为10-i个,字符数为2i-1。

因此,输出空格数和字符数的内循环分别为:

for(j=1;j<=10-i;++j)/*输出空格数*/

printf("");

for(ch='A';ch<'A'+2*i-1;++ch)

printf("%c",ch);

合起来,构成一个完整程序。

完整程序如下:

#include

intmain()

{

inti,j;

charch;

for(i=1;i<=10;i++)

{

for(j=1;j<=10-i;++j)/*输出空格数*/

printf("");

for(ch='A';ch<'A'+2*i-1;++ch)/*输出字符*/

printf("%c",ch);

printf("\n");

}

return0;

}

引申4:

输出下列图形:

*

***

*****

*******

*****

***

*

上面的图形可以分成两部分:

(1)

*

***

*****

*******

与引申3的分析一样,输出空格数和字符数的内循环分别为:

for(j=1;j<=4-i;++j)/*输出空格数*/

printf("");

for(k=1;k<=2*i-1;++k)/*输出“*”号*/

printf("*");

(2)

*****

***

*

与引申2的分析一样,输出空格数和字符数的内循环分别为:

for(j=1;j<=i;++j)/*输出空格数*/

printf("");

for(k=1;k<=7-2*i;++k)/*输出“*”号*/

printf("*");

合起来,构成一个完整程序。

完整程序如下:

#include

intmain()

{

inti,j,k;

for(i=1;i<=4;i++)

{

for(j=1;j<=4-i;++j)/*输出空格数*/

printf("");

for(k=1;k<=2*i-1;++k)/*输出“*”号*/

printf("*");

printf("\n");

}

for(i=1;i<=3;i++)

{

for(j=1;j<=i;++j)/*输出空格数*/

printf("");

for(k=1;k<=7-2*i;++k)/*输出“*”号*/

printf("*");

printf("\n");

}

return0;

}

习题2-6调和级数(harmony)

输入一个正整数n,输出H(n)=

的值,保留3位小数。

例如n=3时答案为1.833。

【分析】

本题主要考察循环语句的使用。

秘诀是要从绝对值最小的项开始向绝对值大的项累加。

程序如下:

#include

intmain(){

unsignedintn;/*我们认为int已经足够表达所谓的“正整数”范围*/

doublesum=0;

scanf("%u",&n);

for(;n>=1;n=n-1){

sum=sum+1.0/n;

}

printf("%.3f",sum);

return0;

}

习题2-7近似计算(approximation)

计算

,直到最后一项小于10-6。

【分析】

本题主要考察循环语句的使用。

秘诀是要从绝对值最小的项开始向绝对值大的项累加。

程序如下:

#include

intmain(){

intn;

doublesum=0;

intsymbol;

n=1000001;/*显然,1/1000001小于0.000001*/

for(;n>=1;n=n-2){

if((n+1)/2%2==1)symbol=1;

elsesymbol=-1;

sum=sum+symbol*(1.0/n);

}

printf("%.20lf",sum);

return0;

}

习题2-8子序列的和(subsequence)

输入两个正整数n

,保留5位小数。

例如,n=2,m=4时答案是0.42361;n=65536,m=655360时答案为0.00001。

注意:

本题有陷阱。

【分析】

本题主要考察循环语句的使用。

秘诀是要从绝对值最小的项开始向绝对值大的项累加。

所谓的陷阱,是指m的平方可能会导致整数溢出。

所以,另一个秘诀是,把m和n定义为double。

程序如下:

#include

intmain(){

doublem,n;

doublesum=0;

scanf("%lf%lf",&n,&m);/*假设用户输入的n总是不大于m*/

for(;m>=n;m=m-1){

sum=sum+1.0/(m*m);/*注意,不能写成sum=1/m*m*/

}

printf("%.5lf",sum);

return0;

}

习题2-9分数化小数(decimal)

输入正整数a,b,c,输出a/b的小数形式,精确到小数点后c位。

a,b≤106,c≤100。

例如a=1,b=6,c=4时应输出0.1667。

【分析】

注意到a,b,c均为正整数,所以输出结果的小数点后至少会有1位。

另外,从本题的示例输出中可以感知到,小数的最后一位,是要考虑到四舍五入进位的。

采取的策略是模拟整数除法的过程,利用整除所得的余数,不断地对目标结果求精。

程序如下:

#include

intmain(){

inta,b,c;

scanf("%d%d%d",&a,&b,&c);

printf("%d.",a/b);//先输出整数和小数点

for(inti=1;i<=c;i++)//按照除法规则进行相除运算

{

a=(a%b)*10;//确定下次被除数

if(i!

=c)

printf("%d",a/b);

else{//确定第c位小数是否需要进行四舍五入

a=(a%b)*10;

if(a/b>=5)

printf("%d",a/b+1);

else

printf("%d",a/b);

}

}

printf("\n");

return0;

}

2.4.7ACM题目中的输入输出

1.ACM题目特点

由于ACM竞赛题目的输入数据和输出数据一般有多组(不定),并且格式多种多样,所以,如何处理题目的输入输出是对大家的一项最基本的要求。

这也是困扰初学者的一大问题。

经常有刚接触ACM在线测试系统的同学抱怨:

“为什么我在OJ(OnlineJudge)上连简单的A+B也通不过?

先给一个竞赛样例:

题目名称:

A+BforInput-OutputPractice(I)

链接地址:

TimeLimit:

1Seconds    MemoryLimit:

32768K

ProblemDescription

YourtaskistoCalculatea+b.

Tooeasy?

!

Ofcourse!

Ispeciallydesignedtheproblemforacmbeginners.

Youmusthavefoundthatsomeproblemshavethesametitleswiththisone,yes,alltheseproblemsweredesignedforthesameaim.

Input

Theinputwillconsistofaseriesofpairsofintegersaandb,separatedbyaspace,onepairofintegersperline.

Output

Foreachpairofinputintegersaandbyoushouldoutputthesumofaandbinoneline,andwithonelineofoutputforeachlineininput.

SampleInput

15

1020

SampleOutput

6

30

初学者很常见的一种写法:

#include

intmain()

{

inta,b;

scanf(“%d%d”,&a,&b);

printf(“%d”,a+b);

return0;

}

但上述代码提交上述到OJ上不能通过,是什么原因呢?

这就是下面需要解决的问题。

下面来分类进行介绍。

2.基本输入

(1)第一类输入

输入不说明有多少个InputBlock,以EOF为结束标志,例如上面的例子。

源代码如下:

#include

intmain()

{

inta,b;

while(scanf("%d%d",&a,&b)!

=EOF)printf("%d\n",a+b);

}

本类问题的输入方案为:

①C语法

while(scanf("%d%d",&a,&b)!

=EOF)

{

 ....

}

②C++语法

while(cin>>a>>b)

{

  ....

}

说明:

①scanf函数返回值就是读出的变量个数,如:

scanf("%d%d",&a,&b);,如果只有一个整数输入,返回值是1;如果有两个整数输入,返回值是2;如果一个都没有,则返回值是-1。

②EOF是一个预定义的常量,等于-1。

(2)第二类输入

输入一开始就会说有n个InputBlock,下面接着是输入n个InputBlock。

参见:

HDOJ_1090(

源代码如下:

#include

intmain()

{

intn,i,a,b;

scanf("%d",&n);

for(i=0;i

{

scanf("%d%d",&a,&b);

printf("%d\n",a+b);

}

}

本类问题的输入方案为:

①C语法

scanf("%d",&n);

for(i=0;i

{

  ....

}

②C++语法

cin>>n;

for(i=0;i

{

  ....

}

(3)第三类输入

输入不说明有多少个InputBlock,但以某个特殊输入为结束标志。

参见:

HDOJ_1091(

源代码如下:

#include

intmain()

{

inta,b;

while(scanf("%d%d",&a,&b)&&(a!

=0&&b!

=0))

printf("%d\n",a+b);

}

上面程序有什么问题?

本类问题的输入方案为:

①C语法

while(scanf(“%d”,&n)!

=EOF&&n!

=0)

{

 ....

}

②C++语法

while(cin>>n&&n!

=0)

{

  ....

}

(4)第四类输入

以上几种情况的组合,可以参照如下网页,进行上机实验。

(5)第五类输入

输入一整行的字符串。

参见:

HDOJ_1048(http:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 小升初

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1