C语言--嵌套循环

一、PTA实验作业

题目1 水果价格

1.本题PTA提交列表

2.设计思路

  • 第一步:定义变量number,表示输入的编号
  • 第二步:定义变量i,用来记录编号数目
  • 第三步:输出菜单:[1] apple
    [2] pear
    [3] orange
    [4] grape
    [0] exit
  • 第四步:输入number
  • 第五步:如果number==0,结束程序
  • 第六步:如果number1,输出price3.00;如果number2,输出price2.50;如果number3,输出price4.10;如果number4,输出price10.20;若都不是,输出0.00;
  • 第七步:再次输入number
  • 第八步:重复五,六,七步,直到i>5,结束程序

3.本题调试过程碰到问题及解决办法

问题:没有在输入0后结束程序

问题代码:

          int number;
	  int i;
	printf("[1] apple\n[2] pear\n[3] orange\n[4] grape\n[0] exit\n");
	scanf("%d",&number);
	if(number==0){
	   return 0;
	}
	if(number>=0){
	  for(i=1;i<=5;i++){
		switch(number)
		{
		
			case 1:
			printf("price=3.00\n") ;
			break;
			case 2:
			printf("price=2.50\n");
			break;
			case 3:
			printf("price=4.10\n");
			break;
			case 4:
			printf("price=10.20\n");
			break;
	
            	}
    	       scanf("%d",&number);
	     }
	  if(i>5){
		printf("price = 0.0");
	}
}
     if(number>4){
     printf("price = 0.0");

调试:

可以看到输入0后发生错误,我们想要的是它进入number==0这个分支然后结束程序,但是实际上进的依然是循环体,会不会是因为等于0这个分支执行位置不对?还是因为下一次输入是在循环体里面进行的导致不能执行0这一分支?

初步改正:将number的判断全部移入循环体

运行结果:

可以看到答案与题目不符,所以之前的分支number==0执行结果应该是先输出0,0再结束程序

微调后:

修正代码:

          int number;
	  int i;
	printf("[1] apple\n[2] pear\n[3] orange\n[4] grape\n[0] exit\n");
	scanf("%d",&number);
	  for(i=1;i<=5;i++){
	  		if(number==0){
	  			printf("price = 0.0");	
	   return 0;
	}
	if(number>4){
	printf("price = 0.0");
}
		if(number>0&&number<4){
		 switch(number)
		{
		
			case 1:
			printf("price = 3.00\n") ;
			break;
			case 2:
			printf("price = 2.50\n");
			break;
			case 3:
			printf("price = 4.10\n");
			break;
			case 4:
			printf("price = 10.20\n");
			break;
     	}
   	}
    	scanf("%d",&number);
	}
	if(i>5){
		return 0;
	}

另外根据输出结果发现循环条件错误,少循环一次,还有输入超过5次结束程序而不是输出0.0,不符合题目要求

错误:

改正:

PTA 提交结果

修改:增加对i==5时程序结束的判断


这种是还是要输入一组


这种是直接跳到i==5的分支,不走循环体了

后面是一系列的折腾i==5,注意力全放在如何在刚好五组数据时结束程序,浪费很多时间去增添语句调试,把错误提示理解成恰好输入五组,然后结束程序,不能再输入了。调试成功后依旧提交错误,而且错 的还是一样的,开始去排查其他可能的错误,忽然发现输入的不一定是数字也可能别的,所以改用default判断余下输入情况

改正:

优化:i>5这一分支没有必要,可以删去,因为i只有小于等于5才进入循环体,输出相应语句

本题错误总结:
不熟悉错误类型,定位不准,导致浪费时间。最好是先写算法再写代码,这样会更熟悉每一步,而不会因为代码理解的不足多加很多无用语句,可读性更差了,也方便修正。一定要严格按照题目意思来,不能主观妄断。

题目7、8 歌唱比赛评分系统、餐饮服务质量调查打分【有类似点就放在一起写了】

1.本题PTA提交列表

题目7

题目8

2.题目8设计思路

  • 第一步:定义变量n表示输入数字总数,repeat表示执行次数,class表示等级,i,j,m都是循环变量
  • 第二步:输入repeat的值
  • 第三步:对one,two,three,four,five赋初值,初值为0
  • 第四步:输入class的值
  • 第五步: 若class1,one的值加一;若class2,two的值加一;若class3,three的值加一;若class4,four的值加一;若class==5,five的值加一
  • 第六步:当i满足不大于n时,重复第四步,第五步
  • 第七步:输出1,当m小于等于one时,输出,不满足m<=one时换行
    输出2,当m小于等于two时,输出
    ,不满足m<=two时换行
    输出3,当m小于等于three时,输出,不满足m<=three时换行
    输出4,当m小于等于four时,输出
    ,不满足m<=four.时换行
    输出5,当m小于等于five时,输出*,不满足m<=five时换行
  • 第八步:当评分次数小于等于repeat,重复第3步到第七步

3.本题调试过程碰到问题及解决办法

问题代码:

    int repeat,n,i,j,one,two,three,four,five,m,class;
scanf("%d%d",&repeat,&n);
one=0;
two=0;
three=0;
four=0;
five=0;
for(j=1;j<=repeat;j++){
for(i=1;i<=n;i++){
	scanf("%d",&class);
	switch(class){
		case 1:one++;break;
		case 2:two++;break;
		case 3:three++;break;
		case 4:four++;break;
		case 5:five++;break;
                  } 
	      printf("%d:",class);
     for(m=0;m<=one;m++){
		printf("*");

运行结果:

首先一个小错误,换行符的使用导致输出格式不对
第二个,输出结果不对,比如1输出的俩个*

调试:

可以看到输出一个星号后再次进入循环体,输出星号

结果:

错误原因:m所赋初值不对,导致循环多了一次。当m等于1也是可以进入循环的,所以不需要初值为0

后来想到要用变量count来储存各数字输入次数,来简化程序。。。。

错误截图:

调试:

count会跟着循环,导致输出很多组
调试修改了一晚上发现真的不会这种方法,代码本身好像都有问题,最终选择用if语句判断这五种情况,一一列举,并且完善了当有1到5有数字没输入时的情况

代码:

         int n,repect,class,i,j,m;
     scanf("%d%d",&repect,&n); 
     int one=0,two=0,three=0,four=0,five=0;
     if(repect>0&&repect<9&&n>=1&&n<=20){
     for(i=1;i<=repect;i++){
	for(j=1;j<=n;j++){
		scanf("%d",&class);
		switch(class){
			case 1:one++;break;
			case 2:two++;break;
			case 3:three++;break;
			case 4:four++;break;
			case 5:five++;break;
		}
	}
	printf("1:");
	for(m=1;m<=one;m++){
		printf("*");
	} 
	printf("\n");
	printf("2:");
	for(m=1;m<=two;m++){
		printf("*");
	} 
	printf("\n");
	printf("3:");
	for(m=1;m<=three;m++){
		printf("*");
	} 
	printf("\n");
	printf("4:");
	for(m=1;m<=four;m++){
		printf("*");
	} 
	printf("\n");
	printf("5:");
	for(m=1;m<=five;m++){
		printf("*");
	} 
	printf("\n");
}

PTA提交显示答案错误,验证多组数据,输出都没有问题,找不出错误,在助教和学长提示下修正了代码,提交正确

错误原因:虽然明白repeat是多次输入,但是调试时一直默认repeat为1,导致没有发现n的输入位置不对所以检验时选择多组数据以及选择的条件很重要,要考虑充分。

后排补充:为什么每次循环评分后要把one到five初始化

第七题比赛评分与第八题餐饮打分某些部分是一个类型的,比如实现多次打分和打分后初始化这俩个点,下面借第七题调试解释下为什么要初始化还有一些语句放置位置

可以看到输出结果错误,计算方法没问题那就是数值输入发生了错误,下面调试

sum=85=min,也就是sum并没有包括第一次输入的90,所以调整或者加多一步sum=sum+grade,这个错误修正后我们往下进行
(截图里我选了一组新数据)

这次评分结束后,准备下一组评分

可以看到sum不是我们想象中的0,而是保留了第一组评分的结果,导致后面一系列全错了,这就是对一组运行后变量再次初始化的意义

题目4 换硬币

1.本题PTA提交列表

2.设计思路

  • 第一步:定义变量x,count1,count2,count3,count,total分别代表需要换的钱数目,5分的数目,2分的数目,1分的数目,有几组达标,总共硬币数
  • 第二步:输入x的值
  • 第三步:计算5分最多的数目x/5,2分数目x/2,1分数目x
  • 第四步:随机递减count1,count2,count3,当满足count15+count22+count3时,count的值加一
  • 第五步:total=count1+count2+count3
  • 第六步:输出5分,2分,1分的数目
  • 第七步:输出硬币总数

3.本题调试过程碰到问题及解决办法

错误代码:

         int x,count1,count2,count3,count,total;
	 scanf("%d",&x);
	 count=0;
	 for(count1=1;count1*5<=x;count1++)
	   for(count2=1;count2*2<=x;count2++)
	       for(count3=1;count3*1<=x;count3++)
	          if(count1*5+count2*2+count3*1==x){
	          	count++;
	          	total=count1+count2+count3;
	          	printf("fen5:%d,fen2:%d,fen1:%d,total:%d\n",count1,count2,count3,total);
	          }
	          printf("count = %d",count);

首先输出的count1,count2,count3是随机的,只要满足硬币代表的钱数为x即可,不一定按照从大到小的顺序,再一个,控制每种硬币至少一枚比较麻烦,而且容易出错,那能不能反着来,循环递减,最小为1
改正后,结果正确

二、同学代码结对互评

1.互评同学名称:兰子欣、陈欢

2.代码截图

梅森数

兰子欣的代码:

    int i,j,n,sum,count=0;
	 scanf("%d",&n);
	 for(i=1;i<=n;i++){
	 sum=pow (2,i)-1;
		for(j=2; j<=sum; j++){
			if(sum%j==0)
			break;
			if(j>sum/2&&sum!=1){
			printf("%d\n",sum);
			count++;
			break;}
			else
			count=count;
		}
	}
	if(count==0)
	printf("None");

我的代码:

int prime(int result);
int main(){
	int n,result,i,j;
	scanf("%d",&n);
	j=0;
		for(i=1;i<=n;i++){
		result=pow(2,i)-1;
	   if(prime(result)!=0){
	    printf("%d\n",result);
	    j++;}
	}
		if(j==0)
		printf("None");
    	return 0;
}
int prime(int result){
	int m;
	if(result==1)return 0;
	for(m=2;m<=result/2;m++){
		if(result%m==0)
		return 0;
     else	return 1;
 }
}

歌唱比赛评分系统

陈欢的代码:

我的代码:

          for(i=1;i<=repeat;i++){
		scanf("%d",&n);
		scanf("%d",&grade);
		sum=0;
		sum=sum+grade;
		max=min=grade; 
		for(j=2;j<=n;j++){
			scanf("%d",&grade);
			sum=sum+grade;
			if(grade>max){
				max=grade;
			}
			if(grade<min){
				min=grade;
			}
				
		}

3.我的代码和同学的代码不同在哪里?有哪些各自的优势?你更喜欢哪种代码风格?

  • 梅森数这题我和兰子欣的代码不同在我在代码中使用了函数,看上去我的代码要长一些,但我认为慢慢习惯使用函数是很好的一种代码编写方式,因为增加了代码可读性,思路更清楚,将判断素数这一部分用函数调用,再分析其中一些特殊值比如1,但是弊端也是在函数调用上,初学可能会在调用发生各种问题,要考虑到函数声明,形参,调用语句,返回结果等,if语句使用相对考虑的少些,只要考虑执行条件就可以了。初学函数的我还是偏向if语句,但在继续学习的路上慢慢转向函数的调用
  • 歌唱比赛这题我和陈欢的代码不同在对一组数据最大值最小值的判断,我是将输入的第一个成绩,赋值给max,min,再与后面输入的数据判断大小,从而得到数据中最大值,最小值。而她是将评分范围的最大值最小值赋值给max,min,然后再将这俩个值与输入数据比大小,最终得到数据中最大值最小值,这也是一种方法,简单明了,但我觉得这个方法是有漏洞的,如果没有限制输入的范围,这种思路就行不通了,但是对于这一题来说,这是一个好办法,一种新思维,至少我就没想到过这种,学到了。

三、截图本周题目集PTA最后排名

四、本周学习总结

1.你学会了什么?

(1)函数分类:库函数、自定义函数

(2)函数定义一般形式

函数类型 函数名(形式参数表){//函数首部
函数实现过程//函数体
}

1.函数首部:函数类型、函数名、形式参数表

函数类型一般与return语句中表达式的类型一致

形参表中各个形参之间用逗号隔开,每个形参之前的类型必须写明。
形参可以是一个,可以是多个,可以没有

注意:函数首部后面不能加分号,它和函数体构成完整的函数定义

2.函数体是大括号括起来的多个语句,用于计算,完成特定工作

3.形参与普通变量的区别在于是否只能从主调函数中得到已知条件

(3)函数的调用

1.调用之前要有定义、声明,函数声明是一条C语句,即带分号

2.调用形式:函数名(实际参数表)

注意点;- 实参可以是变量,常量或表达式,形参只能是变量
- 数值从实参传递给形参,是单向的,形参值改变了不会影响实参
- 实参和形参要一一对应,数量相同,类型尽量一致

3.常见调用:赋值语句;输出函数的实参

4.结果返回:return语句,注意return只能返回一个值

5.关于函数调用:当遇到函数调用时,主函数被暂停执行,转而执行相应函数,该函数执行完后将返回主函数,然后再从原先暂停的位置继续执行

(3)不返回结果的函数类型:void
注意void不能省,否则默认函数类型为int

(4)局部变量和全局变量

局部变量作用于其所在的函数,优点是各函数互不干扰,但是一些被多个函数共同使用的变量,就没法解决了,于是引出了全局变量,它作用范围为定义到程序结束,就能解决这一问题了,并且全局变量可以帮助函数解决多结果返回的问题

注意,当全局变量和局部变量同名时,局部变量优先

(5)关于动态变量和静态局部变量没有赋初值,前者储存单元中将是随机值,后者会为0,但是赋0值只在函数第一次调用起作用

(6)静态局部变量只作用于该函数,不作用于其他函数包括主函数,静态局部变量最大特点是会保存函数上一次调用的结果,可以利用这一点解决循环问题

2.本周的内容,你还不会什么?

函数调用是对于形参名的设置,以及调用函数时主函数中调用条件的书写。还是不大习惯把程序中某一计算过程换成调用函数从主函数中拎出来,领出来后主函数里的书写形参实参傻傻不知道怎么办了,不过这样子调用函数代码可读性会提高,也方便调试改错,慢慢从例题和代码中体会吧

posted @ 2017-11-11 09:47  我是纪予哇  阅读(1145)  评论(8编辑  收藏  举报