C语言初学者代码中的常见错误与瑕疵(7)
问题:
矩形的个数
在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,2个2*2的矩形,2个3*1的矩形和1个3*2的矩形,总共18个矩形。给出A,B,计算可以从中找到多少个矩形
输入:
本题有多组输入数据(<10000),你必须处理到EOF为止输入2个整数A,B(1<=A,B<=1000)
输出:
输出找到的矩形数。
样例:
输入:
1 2
3 2输出:
3
18
原代码-1:
#include <stdio.h>
int rectangle(int x,int y)
{
int i,j,sum,temp; for(i=,sum=,temp=;i<=x;i++)
{
for(j=;j<=y;j++)
{
temp = (x-i+)*(y-j+);
sum += temp;
}
} return sum;
} int main()
{
long int A[],B[],i;
int rectangle(int x,int y);
//printf("input A&B and end with 0\n"); for(i=;i<;i++)
{
scanf("%d",&A[i]); if (A[i]==)
{
break;
} scanf("%d",&B[i]);
} for(i=;A[i]!=;i++)
{
printf("%d\n",rectangle(A[i],B[i]));
} return ;
}
评析:
写完之后这位小朋友坦率地承认:
露珠不知道如何以EOF结尾..只好用0了...哪位指点下..
我告诉他,
没必要用数组
while( scanf("%d%d", &A,&B)!=EOF )
{
//计算输出矩形个数
}
于是他很快给出了新代码:
原代码-2:
#include <stdio.h>
int rectangle(int x,int y)
{
int i,j,sum,temp; for(i=,sum=,temp=;i<=x;i++)
{
for(j=;j<=y;j++)
{
temp = (x-i+)*(y-j+);
sum += temp;
}
} return sum;
} int main()
{
long int A,B;
int rectangle(int x,int y);
printf("input A&B and end with EOF\n"); while(scanf("%d%d",&A,&B)!= EOF)
{
printf("%d\n",rectangle(A,B));
} return ;
}
评析:
这次好多了。不过他又有了新的困惑:
我修改成这样之后,比如我先输入 2 3 跳出来 18,输入eof 就一直跳 18 停止不了了...
总之就是一直跳最后一次出来的结果 ..
看来他不清楚EOF是怎么回事,还以为是在键盘上键入eof三个字符呢。
我告诉他:
EOF不是三个字符
而是一个符号常量
如果你用的是WIN系统
在行首输入Control-Z试试
实际上EOF是在stdio.h中定义的一个宏,通常是这样的
#define EOF (-1)
不过C语言并没说EOF一定为-1。
在键盘上是没有这个EOF的,但在输入流中遇到特殊的字符,scanf()函数的返回值可以是EOF。那么,这句话究竟是什么意思呢?
通常scanf()的返回值是一个非负整数。比如
int i;
scanf("%d", &i ) ;
如果你在键盘上键入的是123(1、2、3与%d相匹配),scanf("%d", &i )的值就为1,因为为1个变量赋了值;如果你在键盘上键的是abc(a与%d不匹配),scanf("%d", &i )的值就为0,因为scanf无法把"a"视为十进制整数(%d),也无法对它进行转换,更无法为变量 i 赋值,也就是说scanf这种情况下没有为任何变量赋值,所以返回值为0。如果scanf()在输入流中遇到的是某个特殊的字符(具体是哪个字符与环境有关),则返回值为EOF。
另外我告诉他:
把函数类型声明
int rectangle(int x,int y);
写在main()函数之内很傻
(应该把函数类型声明)写在函数外面
另外那个temp多余
temp赋值为零就更多余
(因为可以直接)
sum += (x-i+1)*(y-j+1);
就这样,他再次进行了修改:
原代码-3
#include <stdio.h>
int rectangle(int x,int y)
{
int i,j,sum,temp; for(i=,sum=;i<=x;i++)
{
for(j=;j<=y;j++)
{
sum += (x-i+)*(y-j+);;
}
} return sum;
} int rectangle(int x,int y);
int main()
{
long int A,B;
printf("input A&B and end with EOF\n"); while(scanf("%d%d",&A,&B)!= EOF)
{
printf("%d\n",rectangle(A,B));
} return ;
}
评析:
现在毛病少多了,不过还是有一些。
首先, rectangle()函数定义的位置不妥,写在main()定义的后面为好。
其次,数据类型有问题,这个问题比较严重。
long int A,B;
这里绝对没有必要把A、B定义为long类型,int类型足矣。由于不当地把A、B定义成了long类型,所以代码中的
scanf("%d%d",&A,&B)
和
rectangle(A,B)
这两次调用都是错的。虽然没有产生错误的结果(估计在那个系统中long和int类型大小一样),但其实是瞎猫碰到死耗子,侥幸而已。
此外的两处小瑕疵就是rectangle()函数定义中的temp变量忘记删除了,循环体内删除语句时不干净,有一“;”也忘记删除了。
再有就是
sum += (x-i+)*(y-j+);
这个算法我没看懂,不知道是否正确。
重构:
其实原来代码已经改得差不多了,只剩下少许小错和瑕疵。我在这里只说一下我的算法:
我的算法是,穷举出两个点(P1,P2)的所有组合情况,只要P1可以是某个矩形的左上角,P2可以是某个矩形的右下角(P1_X<P2_X,P1_Y<P2_Y),则构成了一个矩形。
/*
矩形的个数
在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,
2个2*2的矩形,2个3*1的矩形和1个3*2的矩形,总共18个矩形。
给出A,B,计算可以从中找到多少个矩形。 输入:
本题有多组输入数据(<10000),你必须处理到EOF为止
输入2个整数A,B(1<=A,B<=1000) 输出:
输出找到的矩形数。 样例: 输入:
1 2
3 2 输出:
3
18 作者:薛非
出处:http://www.cnblogs.com/pmer/ “C语言初学者代码中的常见错误与瑕疵”系列博文 */ #include <stdio.h> int count( int , int ); int main( void )
{
int A , B ; while ( printf( "输入2个整数A,B(1<=A,B<=1000)" ),
scanf( "%d%d" , &A , &B )!= EOF
)
{
printf( "%d\n" , count( A , B ) );
} return ;
} int count( int A , int B )
{
int x1 , y1 ;//第一个点的坐标
int x2 , y2 ;//第二个点的坐标
int num = ; for ( x1 = ; x1 <= B ; x1 ++ )
for ( y1 = ; y1 <= A ; y1 ++ )//穷举第一个点的各种可能
for ( x2 = ; x2 <= B ; x2 ++ )
for ( y2 = ; y2 <= A ; y2 ++ )//穷举第二个点的各种可能
{
if ( x1 < x2 && y1 < y2 )
num ++ ;
} return num ;
}
BUG
这个代码的不足之处在于没有认真思考答案是否在int类型的表示范围之内。在 飞鸟_Asuka 网友提出是否“时间复杂度比较大”的问题后,我一并考虑了这两个问题。结论是:1.这个问题用数学的办法很容易解决,不过采用这种方案对学习编程是不利的,因为求解太容易了;2.答案确实有可能超过int类型的表示范围(假如int最大能表示到231-1的话)。这应该算是重构代码中存在的一个BUG。我将在以后的博文中给出修正及数学解答。
在此感谢飞鸟_Asuka 网友的提醒。
C语言初学者代码中的常见错误与瑕疵(7)的更多相关文章
- C语言初学者代码中的常见错误与瑕疵(23)
见:C语言初学者代码中的常见错误与瑕疵(23)
- 一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)
问题: 问题出处见 C语言初学者代码中的常见错误与瑕疵(5) . 在该文的最后,曾提到完成的代码还有进一步改进的余地.本文完成了这个改进.所以本文讨论的并不是初学者代码中的常见错误与瑕疵,而是对我自己 ...
- C语言初学者代码中的常见错误与瑕疵(5)
问题: 素数 在世博园某信息通信馆中,游客可利用手机等终端参与互动小游戏,与虚拟人物Kr. Kong 进行猜数比赛. 当屏幕出现一个整数X时,若你能比Kr. Kong更快的发出最接近它的素数答案,你将 ...
- C语言初学者代码中的常见错误与瑕疵(19)
见:C语言初学者代码中的常见错误与瑕疵(19)
- C语言初学者代码中的常见错误与瑕疵(14)
见:C语言初学者代码中的常见错误与瑕疵(14) 相关链接:http://www.anycodex.com/blog/?p=87
- 分数的加减法——C语言初学者代码中的常见错误与瑕疵(12)
前文链接:分数的加减法——C语言初学者代码中的常见错误与瑕疵(11) 重构 题目的修正 我抛弃了原题中“其中a, b, c, d是一个0-9的整数”这样的前提条件,因为这种限制毫无必要.只假设a, b ...
- C语言初学者代码中的常见错误与瑕疵(9)
题目 字母的个数 现在给你一个由小写字母组成字符串,要你找出字符串中出现次数最多的字母,如果出现次数最多字母有多个那么输出最小的那个. 输入:第一行输入一个正整数T(0<T<25) 随后T ...
- 要心中有“数”——C语言初学者代码中的常见错误与瑕疵(8)
在 C语言初学者代码中的常见错误与瑕疵(7) 中,我给出的重构代码中存在BUG.这个BUG是在飞鸟_Asuka网友指出“是不是时间复杂度比较大”,并说他“第一眼看到我就想把它当成一个数学问题来做”之后 ...
- C语言初学者代码中的常见错误与瑕疵(1)
曾在豆瓣上看到过一个小朋友贴出他自己的代码(http://www.douban.com/group/topic/40293109/),当时随口指点了几句.难得这位小朋友虚心修正.从善如流,不断地改,又 ...
随机推荐
- Swift-09-可空链式调用(Optional Chaining)
我对这个的理解就是:我们有可能会用到其他的属性或者方法,当我们在使用其他的时候,可以使用点语法去访问另一个的属性,这样的使用,就形成了链式访问. 可空链式调用是一种可以请求和调用属性.方法及下表的过程 ...
- cxf动态调用wsdl的一个冲突以及解决
cxf发布服务,调用服务的博客很多,这里也就简单贴一下代代码. 环境如下:spring+cxf (maven环境) <cxf.version>2.7.11</cxf.version& ...
- JavaScript:JavaScript事件的处理
JavaScript事件处理 —————事件的处理流程: —————动态事件绑定: —————常用的事件处理. 1.事件的概念 在页面之中,会针对用户的每一个操作进行记录.在页面中的事件可以简单的理解 ...
- Centos7关闭防火墙与selinux
CentOS 7.0默认使用的是firewall作为防火墙 直接关闭防火墙 systemctl stop firewalld.service #停止firewall systemctl disable ...
- Java8 新特性default
在JDK1.8的Iterator接口中 package java.util; import java.util.function.Consumer; public interface Iterator ...
- [Slimdx]顶点和索引缓冲,绘制了2个分离的三角形
定义网格顶点和索引缓冲,绘制了2个分离的三角形. using System; using System.Drawing; using RGeos.SlimScene.Core; using SlimD ...
- Silverlight/WPF绘制统计图Visifire.dll文件
官网:http://www.visifire.com/ 一直没找到好的中文文档,希望有的这个的可以发个我! 效果图: 前台代码: <UserControl x:Class="Text_ ...
- UISwitch属性
1.onTintColor 处于on时switch 的颜色 switchImage.onTintColor = [UIColor grayColor]; 2.tintColor 处于off时s ...
- log4j 异步日志问题分析
1. 常用的DailyRollingFileAppender与RollingFileAppender是否同步? 1.1 代码分析 2. log4j 1.2.x提供了异步appender是什么?Asyn ...
- Java基础之处理事件——实现低级事件监听器(Sketcher 2 implementing a low-level listener)
控制台程序. 定义事件监听器的类必须实现监听器接口.所有的事件监听器接口都扩展了java.util.EventListener接口.这个接口没有声明任何方法,仅仅用于表示监听器对象.使用EventLi ...