C语言程序设计第三次作业——选择结构(1)

C语言程序设计第三次作业——选择结构(1)

标签(空格分隔): C语言


又一周过去了,我们在这一周有一个仅属于我们的节日:1024程序员节。为了今后能成为优秀的程序员,我一定会努力的学习C语言这门课程,争取做到精通C语言。下面我们进入正题。


(一)改错题

题目:计算f(x)的值:输入实数x,计算并输出下列分段函数f(x)的值,输出时保留1位小数。

函数

输入输出样例1:
  Enterr x: 10.0
  f(10.0) = 0.1

输入输出样例2:
  Enter x: 234
  f(234.0) = 234.0
源代码:

#include <stdio.h> 
     int main(void)
     { 
        double x,y;
        printf("Enter x: \n"); 
        scanf("=%f", x);
        if(x = 10);
        { 
            y = 1 / x
        }
        else (x != 10)
        {
           y = x;
        }
        printf("f(%.2f) = %.lf\n" x y); 
        return 0; 
     }

我们先试着运行一次我们的源代码,编译错误,错误结果如下:
--------------------配置: mingw5 - CUI Debug, 编译器类型: MinGW--------------------

检查文件依赖性...
正在编译 D:\Begining C\测试专用\main.c...
[Error] D:\Begining C\测试专用\main.c:10: error: syntax error before '}' token
[Error] D:\Begining C\测试专用\main.c:15: error: syntax error before string constant
[Error] D:\Begining C\测试专用\main.c:15: error: conflicting types for 'printf'
[Warning] D:\Begining C\测试专用\main.c:15: note: a parameter list with an ellipsis can't match an empty parameter name list declaration
[Error] D:\Begining C\测试专用\main.c:15: error: conflicting types for 'printf'
[Warning] D:\Begining C\测试专用\main.c:15: note: a parameter list with an ellipsis can't match an empty parameter name list declaration
[Warning] D:\Begining C\测试专用\main.c:15: warning: data definition has no type or storage class
[Warning] D:\Begining C\测试专用\main.c:17:7: warning: no newline at end of file

构建中止 main: 4 个错误, 4 个警告

编译器的第一个错误定位在第十行,我们检查第十行没有发现问题,错误信息提示}前有问题,故回到第9行发现y = 1 / x这一语句并没有加“;”来结束它。

我们应将第九行改为:y = 1 / x;


再次编译还是出现错误,错误定位于第11行。
--------------------配置: mingw5 - CUI Debug, 编译器类型: MinGW--------------------

检查文件依赖性...
正在编译 D:\Begining C\测试专用\main.c...
[Error] D:\Begining C\测试专用\main.c:11: error: syntax error before "else"
[Error] D:\Begining C\测试专用\main.c:15: error: syntax error before string constant
[Error] D:\Begining C\测试专用\main.c:15: error: conflicting types for 'printf'
[Warning] D:\Begining C\测试专用\main.c:15: note: a parameter list with an ellipsis can't match an empty parameter name list declaration
[Error] D:\Begining C\测试专用\main.c:15: error: conflicting types for 'printf'
[Warning] D:\Begining C\测试专用\main.c:15: note: a parameter list with an ellipsis can't match an empty parameter name list declaration
[Warning] D:\Begining C\测试专用\main.c:15: warning: data definition has no type or storage class
[Warning] D:\Begining C\测试专用\main.c:17:7: warning: no newline at end of file

构建中止 main: 4 个错误, 4 个警告

错误提示else前有语法错误,我们检查第11行,else后跟着(x != 10)我们知道如果想要在再次判断,应该使用else if语句,而直接在else后加判断信息是会有编译错误出现的。

我们应该直接去掉(x != 10)
我们运行改正后的程序还是提示相同的信息,于是我们再次检查之前的语句,发现第8行的if(x = 10);后多加了一个分号使得if语句提前结束,后面大括号内的语句不会执行。

我们应该将第8行的“;”去掉。


修改后我们再次运行程序又提示了错误,错误信息如下:
--------------------配置: mingw5 - CUI Debug, 编译器类型: MinGW--------------------

检查文件依赖性...
正在编译 D:\Begining C\测试专用\main.c...
[Error] D:\Begining C\测试专用\main.c:16: error: syntax error before "x"
[Warning] D:\Begining C\测试专用\main.c:18:2: warning: no newline at end of file

构建中止 main: 1 个错误, 1 个警告

错误提示定位在第16行,我们检查第6行 printf("f(%.2f) = %.lf\n" x y);发现没有用“,”将输出语句和变量隔开。

应用","将输出语句和变量隔开。


我们将修改后的程序再次运行,程序可以正常编译但运行结果有错误。
测试输入10.0:1.PNG-18.1kB
测试输入234.0:2.PNG-35.7kB
由上图可见,虽然程序能编译但是因为某些不会提示的bug而使得运算结果不正确,这些不会提示的bug更加难以找到。

首先我们的一个问题是输入语句没有加上寻址符,可以预见到以后这个错误可能使得程序错误弹出。我们应将 scanf("=%f", x);的x前加上寻址符&。
第二个问题是应该将 printf("Enter x: \n");中的"\n"去掉。否则我们的输出形式会和题目要求的不相符。
第三个问题是应将 y = 1 / x; 中的“1”改为“1.0”使运算成为浮点型。否则会使得输出结果为零。
第四个问题是应将printf("f(%.2f) = %.lf\n" x y); 中的%.2f改为%.1f。否则输出的结果也会和题目要求的不相符。
第五个问题出在输入语句,如果我们想要得到正确的答案在这个程序中需要先输入“=”再输入输入需要计算的数字,十分的繁琐,我们将它去掉就好很多了。
第六个问题是应将输入语句的%f改为%lf,我们定义的变量都是double类型的,直接%f会出现结果错误。
第七个问题出在判断语句,x等于的应该是10.0的浮点数而不是10的整形。
最后的最后也是我最想强调的问题是“=”和"=="的问题,一个赋值语句,一个判断,如果我们因为思维的惯性而混淆了他们,那么就有的头痛了。

从上面几个问题看出,我们在写输入语句时一定要注意,它有很多重要的点需要注意。
最后的更改结果为:

#include <stdio.h> 

int main(void)
{ 
	double x = 0.0,y = 0.0;
 	printf("Enter x:"); 
  	scanf("%lf",&x);
   	if(x == 10.0)
    { 
		y = 1.0 / x; 
	}
 	else
	{
		y = x;
	}
 	printf("f(%.1f) = %.1f\n",x,y); 
	return 0; 
}

最后的输出结果为:
输入10.0的结果:4.PNG-32.6kB
输入234的结果:5.PNG-51.5kB


(二)学习总结

1.if else 语句的对应。

if(a)
    if(b) 
        x=x+1;
    else 
    y=y+1;

看到这段程序我们是不是非常的熟悉?这和我们PTA中的一道选择题很类似。
else只会和离他最近的未配对的if语句配对。于是,程序中唯一的一个else语句就会和if(b)配对,但是这个语句又是属于if(a)的。所以,在这段语句中如果不满足a就会整段跳过。于是,我们的那道选择题的答案也就是2了。这段程序当初把我误导为if(a)语句不起作用,但没想到的是这整段语句都不起作用。if(b)语句本身属于if(a)语句满足条件才会执行的语句。改成更容易理解的形式就变成了。

	if(a)
	{
		if(b)
		{
			x = x + 1;
		}
		else
		{
			y = y + 1;
		}
	}

根据逻辑,我们还可以把程序改为:

if(a&&b)
{
	x = x + 1;
}
else if(a)
{
	y = y + 1;
}

在一些情况下,else if可以直接用else代替,具体情况就需要人来自己判断了。

2.判断语句相关

根据题意,我们是想要表示x在(-10,10)的开区间内,但是题目所给的判断语句 (-10< x <10) 显然是不能将这种意思准确的传达给编译器的。而这一个判断语句如果让编译器执行会无论输入什么数都判断为真执行if内的语句。我们的编译器会直接判断“-10<x”是否为真,无论x为任何值,结果只会是0或1,而无论是0还是1都小于10。于是我们想要表示在(-10,10)区间内的表达式就变成了在R区间内的了。如果我们想要正确的让编译器懂得我们的意思就需要写成 if(x > -10&&x < 10) 的形式。

3.C语言对非法字符的处理

在C中scanf()函数返回成功读入的变量的个数。如果它没有读取任何项目(输入非法字符,例如:希望得到数字,而用户却输入的是字符),scanf()返回值为0。

#include <stdio.h>

int main(void)
{   
    int  a = 0, b = 0;
    scanf("%d %d", &a, &b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

输入123a时的结果:6.PNG-34.9kB
我们看到结果,a确实被赋值为123,而b的值为我初始化过的0,可以想到,如果没有初始化b的化应该会得到一个垃圾值,从这里可以看到对程序初始化的重要性了。
从老师给我们的补充信息可以了解到,当scanf语句读到非法字符输入时将会终止输入语句的进行,我们在书写输入语句是要给将要输入的数据定义的才能让计算机知道应该怎么给我们输入的数据分配合理的内存。也就是说123a之前的123都成功的赋值进了a的整数型中,而终止后的语句却不会对b造成任何的影响。我以为计算机会将123a看做一组数据,但a仅仅是起到了一种类似于回车的作用被缓存到了内存中,终止了这条语句。
我们将b的初始化值改为一检验一下我的推断:
同样输入123a的结果如下:7.PNG-30.4kB,这就可以证明我的推论基本正确。程序在读到a时,它不属于我们给的整数定义从而成为非法数据将输入强行的停止了,而为b赋值直接就跳过了从而让b为初始化时的值。
对输入语句进行简单的探究后我们可以进行下一项任务了。
让我们来看源程序二吧:

#include <stdio.h>

int main(void)
{   
    int  a = 0, b = 0,n = 0;
    
	n = scanf("%d %d", &a, &b);
	printf("n = %d\n", n);
    
	return 0;
}

根据题意运行并输入12345和123a后的结果如下:
8.PNG-41.6kB
根据第7行的语句可只,是将scanf("%d %d", &a, &b)成功赋值的数量赋值给了n。而12345是在int型数据正常数据范围内的数据,虽然123a并不符合规范,但根据上一道题我们得到的结论我们推测b的赋值为123。我们来补充程序来检验一下:

#include <stdio.h>

int main(void)
{   
    int  a = 0, b = 0,n = 0;
    
	n = scanf("%d %d", &a, &b);
	printf("n = %d\n", n);
	printf("a = %d,b = %d",a,b);
    
	return 0;
}

补充:我不慎将123 45看成了12345。现在将123 45的测试数据后期补上。我们可以很简单的预测到结果:
a = 123,b = 45
运行结果为:
9.PNG-27.8kB
结果符合预期,说明我推论基本正确。
接下来来到正题,要求修改源程序一来实现检测非法数据的目的。

#include <stdio.h>

int main(void)
{
	int a = 0,b = 0,n = 0;
	
	printf("请输入a和b的值用空格隔开。\n");
	n = scanf("%d %d",&a,&b);
	
	if(n < 2)
	{
		printf("Input error!\n");
	} 
	else 
	{
		printf("a = %d, b = %d\n", a, b);
	}
	
	return 0;
} 

这是我存疑的数据,虽然基本满足老师给出的案例:
输入123 45:10.PNG-43.8kB
输入123a:11.PNG-31.8kB
虽然这个程序能够达到题目给出的范例的要求。但却不能真真正正的完成题目,例如当我输入123 123a时,结果如下:12.PNG-35.9kB
也就是,如果非法数据在第二个输入位置时,scanf的正确输入语句数会为二。根据我前面的探究已经可以知道非法字母只是终止语句却不会影响其前方的正确数据的输入,补充证明如下:
13.PNG-27.1kB
由此,我推断我们在用键盘输入时数字、空格、回车等等等等其实都会缓存在内存中等待我们程序的调用,而我们在输入之所以需要&就是因为寻址符正是需要为我们的变量来一个正确的门牌好,我们键盘输入的数据已经不属于我们的程序而属于计算机硬件中存储的其他部分。这也正是我们在使用getchar时连用时错误的原因。
所以我认为在仅使用我们现在学到的知识的情况下是无法完美的达到题目的要求的。

4.其他问题总结

在这一周里我们主要学习的就是顺序结构,而学习最多的又是if else语句。到了目前,我们已经很少再出现格式错误了,虽然如此我还是出过几次。让人无奈的有时会只在判断语句中写一个=。在我一脸蒙蔽的找半天却找不着最后却发现错误在这种问题上时还是非常崩溃的。


到了现在我们面对的就主要是逻辑方面的问题了,这时候就需要我们熟练c语言对问题的表达方式,我们学英语时对方可以是人,对我们的语法错误宽容。但我们在用c写程序是却是在对只懂0/1的机器对话,这时候我们就必须符合规范的使用命令语句。像什么时候用if else语句,什么时候连用if,什么时候用嵌套,到底需不需要大括号。这些都是我们应该注意的问题。

(三)实验总结

3.回文数

判断一个5位数是不是回文数。例如12321是一个回文数,即它的个位与万位相同,十位与千位相同。。
流程图:
1.PNG-90.8kB
源代码:

//3. 回文数
#include <stdio.h>

int main(void)
{
	double number = 0.0;
	int n_a = 0,n_b = 0,n_c = 0,n_d = 0,n_e = 0;
	
	scanf("%lf",&number);
	
	n_a = number / 10000;
	n_b = number / 1000 - n_a * 10;
	n_c = number / 100 - n_a * 100 - n_b * 10;
	n_d = number / 10 - n_a * 1000 - n_b * 100 - n_c * 10;
	n_e = number / 1 - n_a * 10000 - n_b * 1000 - n_c * 100 - n_d * 10;
	
	if(n_a == n_e&&n_b == n_d)
	{
		printf("yes\n");
	}
	else
	{
		printf("no\n");
	}
	
	return 0;
}

运行源代码结果如下:
输入12521:2.PNG-27.6kB
输入12345:3.PNG-27.6kB
实验总结:

这道题的重点不在if else语句,而在我们这么去将一个5位数的每一位数字分离出来来进行比较。而这也是Raptor中的关键。

5.计算火车运行时间

本题要求根据火车的出发时间和达到时间,编写程序计算整个旅途所用的时间。
流程图如下:
4.PNG-94.3kB
源代码如下:

//5. 计算火车运行时间
#include <stdio.h>

int main(void)
{
	int time_a = 0,time_b = 0,hour_a = 0, min_a = 0,hour_b = 0,min_b = 0;
	int hour = 0,min = 0;
	
	//printf("请输入出发时间和到达时间,中间以空格隔开。"); 
	
	scanf("%d%d",&time_a,&time_b);
	
	hour_a = time_a / 100;	//求出发时间中的小时部分。 
	min_a = time_a - hour_a*100;	//求出发时间中的分钟部分。 
	hour_b = time_b / 100;	//到达时间 。 
	min_b = time_b - hour_b*100;	//到达时间。 
	
	if(min_a <= min_b)
	{
		hour = hour_b - hour_a;
		min = min_b - min_a;
	}
	else
	{
		hour = hour_b - hour_a - 1;
		min = (60-min_a) + (min_b);
	}
	
	printf("%002d:%002d",hour,min);
	
	return 0;
}

源代码运行结果如下:
正常:5.PNG-19.9kB
特殊:6.PNG-32.7kB
这个程序的重点在于借位。

借位:时间差就是减法,可能要借位。例如上面,15.12 - 7.45,分钟部分不够减,向小时借位,变成14.72 - 7.45,等于,7小时27分钟。
只要我们明白时间差有两种类型就能很容易的编完这个程序。现在我们学到的都只是工具,实际编写程序还是很需要我们的数学逻辑思维的,要不然为什么算法工程师工资那么高哪。


7.三天打鱼两天晒网(不含贬义)

中国有句俗语叫“三天打鱼两天晒网”。假设某人从某天起,开始“三天打鱼两天晒网”,问这个人在以后的第N天中是“打鱼”还是“晒网”?
Raptor流程图如下:
7.PNG-87.7kB
源代码如下:

//7. 三天打鱼两天晒网
#include <stdio.h>

int main(void)
{
	int day = 0;
	
	//printf("请输入今天是从开始的第几天。")
	scanf("%d",&day);
	
	if((day%5) != 0)
	{
		if((day%5) <= 3)
		{
			printf("Fishing in day %d\n",day);
		}
		else
		{
			printf("Drying in day %d\n",day);
		}
	}
	else
	{
		printf("Drying in day %d\n",day);
	}
	
	return 0;
}

测试源代码结果如下:
输入103:9.PNG-35.6kB
输入34:8.PNG-39.4kB
结果符合题目要求。
实验分析:

这道题考察的是我们对嵌套语句的使用,重复判断需要我们的逻辑需要一定的严谨性。而我们的数学问题就不是那么的重要了,只要知道余数对应的相应数值就不会太难。

9.阶梯电价

为了提倡居民节约用电,某省电力公司执行“阶梯电价”,安装一户一表的居民用户电价分为两个“阶梯”:月用电量50千瓦时(含50千瓦时)以内的,电价为0.53元/千瓦时;超过50千瓦时的,超出部分的用电量,电价上调0.05元/千瓦时。请编写程序计算电费。
Raptor流程图如下:
10.PNG-88.7kB
源代码如下:

//9.阶梯电价
#include <stdio.h>

int main(void)
{
	double x = 0.0,money = 0.0;
	
	//printf("请输入用电量。");
	scanf("%lf",&x);
	
	if(x < 0)
	{
		printf("Invalid Value!\n");
	} 
	else if(x <= 50)
	{
		money = 0.53 * x;
		printf("cost = %.2f\n",money);
	}
	else
	{
		money = 26.5 + (x-50)*0.58;
		printf("cost = %.2f\n",money);
	}
	
	return 0;
}

输入10:11.PNG-43.4kB
输入100:12.PNG-30kB
实验分析:

这道题的难度在我看来比其他题的难度都低,数学上没有难度,c也只检验了我们对嵌套的应用。可能是为了庆祝我们的1024节吧,可惜我用了好几天才完成这个博客园作业。为1024致敬!

(四)PTA提交列表

13.PNG-248.8kB
又一周的作业完成了。我们这一周很充实。我们也逐渐的入门了C语言。加油。

posted @ 2017-10-28 22:18  人满为患  阅读(597)  评论(0编辑  收藏  举报