一、请用C语言写出int、bool、float、double、指针型与零值的比较语句
- 布尔变量与零值比较
不可将布尔变量直接与TRUE、FALSE或者1、0进行比较。 根据布尔类型的语义,零值为“假”(记为FALSE),任何非零值都是“真”(记为TRUE)。TRUE的值究竟是什么并没有统一的标准。例如Visual C++ 将TRUE定义为1,而Visual Basic则将TRUE定义为-1。
假设布尔变量名字为flag,它与零值比较的标准if语句如下:
if(!a) {
return false;
} else {
return true;
}
其它的用法都属于不良风格,例如:
if (flag == TRUE)
if (flag == 1 )
if (flag == FALSE)
if (flag == 0)
- 整型变量与零值比较
将整型变量用“==”或“!=”直接与0比较。int型的零值就是0;
假设整型变量的名字为value,它与零值比较的标准if语句如下:
if (value == 0)
if (value != 0)
不可模仿布尔变量的风格而写成
if (value) // 会让人误解 value是布尔变量
if (!value)
- 浮点变量与零值比较
不可将浮点变量用“==”或“!=”与任何数字比较。 千万要留意,无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“> =”或“ <=”形式。
float型的零值约为0.000001,即为1e-6;double是保证14-15位小数有效的;
假设浮点变量的名字为x,应当将
if ((x> =-EPSINON) && (x <=EPSINON))
转化为
if ((x> =-EPSINON) && (x <=EPSINON))
其中EPSINON是允许的误差(即精度)。
- 指针变量与零值比较
应当将指针变量用“==”或“!=”与NULL比较。 指针变量的零值是“空”(记为NULL)。尽管NULL的值与0相同,但是两者意义不同。假设指针变量的名字为p,它与零值比较的标准if语句如下:
if (p == NULL) // p与NULL显式比较,强调p是指针变量
if (p != NULL)
不要写成
if (p == 0) // 容易让人误解p是整型变量
if (p != 0)
//或者
if (p) // 容易让人误解p是布尔变量
if (!p)
考查对0值判断的“内功”,BOOL型变量的0判断完全可以写成if(var==0),而int型变量也可以写成if(!var),指针变量的判断也可以写成if(!var),上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思。一般的,如果想让if判断一个变量的“真”、“假”,应直接使用if(var)、if(!var),表明其为“逻辑”判断;如果用if判断一个数值型变量(short、int、long等),应该用if(var==0),表明是与0进行“数值”上的比较;而判断指针则适宜用if(var==NULL),这是一种很好的编程习惯。浮点型变量并不精确,所以不可将float变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。如果写成if (x == 0.0),则判为错;
完整代码:
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
/*********bool和零比值********/
bool bool_and_zero(bool a)
{
if(a)
{
return true;
}
else
{
return false;
}
}
/********int和零比值*************/
int int_and_zero(int a)
{
if(0 == a)
{
return 0;
}
else if(0 < a)
{
return 1;
}
else
{
return -1;
}
}
/***********float和零比值******************/
float float_and_zero(float a)
{
float zero = 1e-6;
float yes = 0.1;
float no = 0.2;
if(fabs(a) <= zero)
{
return yes;
}
else
{
return no;
}
}
/************指针和零比值**************/
char p_and_zero(int *a)
{
void *p= (void *)(a);
printf("%p\n",p);
if(NULL == p)
{
return 'y';
}
if(NULL != p)
{
return 'n';
}
}
int main(void)
{
bool t1 = true,r1;
int t2 = -2,r2, *p=0;
float t3 = 3.56,r3;
char pp;
r1 = bool_and_zero(t1);
r2 = int_and_zero(t2);
r3 = float_and_zero(t3);
pp = p_and_zero(p);
printf("bool:%d\nint:%d\nfloat:%0.2f\np:%c\n",r1,r2,r3,pp);
return 0;
}
二、判断一个坐标点C是否在点A与B之间的线上
Q(xc,yc),P1(xa,ya),P2(xb,yb)
两种方法第一点都要验证点是否在P1与P2的这条线上,向量叉乘:
假设直线方程为:Ax+By+C=0,则有:A=y2-y1; B=x1-x2; C=x2y1-x1y2;
(Q - P1)×(P2 - P1)=0 => (yb-ya)/(xb-xa)=(yc-ya)/(xc-xa) => (xb-xa)*(yc-ya)-(xc-xa)*(yb-ya)=0
- 第一种方法:
如果想判断一个点是否在线段上,设点为Q,线段为P1P2,那么要满足以下两个条件:
① ( Q - P1 ) × ( P2 - P1 )= 0;
② Q在以P1,P2为对角顶点的矩形内;
第一点通俗点理解就是要求Q、P1、P2三点共线;当第一个满足后,就应该考虑是否会出现Q在P1P2延长线或反向延长线这种情况。此时第二个条件就对Q点的横纵坐标进行了限制,要求横纵坐标要在P1P2两点的最小值和最大值之间,也就是说保证了Q在P1P2之间。
第二点:min(P1x, P2x) ≤ Qx ≤ max(P1x, P2x) && min(P1y, P2y) ≤ Qy ≤ max(P1y, P2y)
特别要注意的是,由于需要考虑水平线段和垂直线段两种特殊情况,min(xi,xj)<=xk<=max(xi,xj)和min(yi,yj)<=yk<=max(yi,yj)两个条件必须同时满足才能返回真值。
Java语言代码:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
Point point1 = new Point();
Point point2 = new Point();
double x, y;
point1.setLocation(5.0, 5.0);
point2.setLocation(1.0, 1.0);
System.out.println("请分别输入点x,y的坐标:");
x = scan.nextDouble();
y = scan.nextDouble();
boolean pdline = (x - point1.getX()) * (point1.getY() - point2.getY()) == (point1.getX() - point2.getX())
* (y - point1.getY());
boolean inline = (Math.min(point1.getX(), point2.getX()) <= x && x <= Math.max(point1.getX(), point2.getX())) && (Math.min(point1.getY(), point2.getY()) <=y && y <= Math.max(point1.getY(), point2.getY()));
if (pdline&&inline) {
System.out.println("您输入的点在point1和point2直线之间");
} else {
System.out.println("您输入的点不在point1和point2直线之间");
}
scan.close();
}
C语言代码:
bool onsegment(point pi,point pj,point Q)
{
if((Q.x-pi.x)*(pj.y-pi.y)==(pj.x-pi.x)*(Q.y-pi.y)&&min(pi.x,pj.x)<=Q.x&&Q.x<=max(pi.x,pj.x)&&min(pi.y,pj.y)<=Q.y&&Q.y<=max(pi.y,pj.y)){
return true;
}else{
return false;
}
}
- 第二种方法
设点为Q,线段为P1P2 ,判断点Q在该线段上的依据是:
① 向量P1P2 · 向量QP1 =0
② 向量P1P2 与向量QP1反向
两种方法第一点都相同,不同在于第二点是验证向量P1P2与向量QP1是否反向。假设P1P2 = (x1, y1), QP1 = (x2, y2),那么只需要判断:x1*x2<=0 &&y1*y2<=0 就可以知道是否反向。也即,需要两次乘法和两次比较。所以,这两种算法的差别是比较细微的。
C++语言版完整代码:
#include <iostream>
#include <cstdio>
using namespace std;
struct point
{
double x;
double y;
};
bool onSegment(point Pi , point Pj , point Q)
{
if((Q.x - Pi.x) * (Pj.y - Pi.y) == (Pj.x - Pi.x) * (Q.y - Pi.y)
&& min(Pi.x , Pj.x) <= Q.x && Q.x <= max(Pi.x , Pj.x)
&& min(Pi.y , Pj.y) <= Q.y && Q.y <= max(Pi.y , Pj.y))
return true;
else
return false;
}
int main()
{
point p1 , p2 , q;
cin >> p1.x >> p1.y;
cin >> p2.x >> p2.y;
cin >> q.x >> q.y;
if(onSegment(p1 , p2 , q))
cout << "Q点在线段P1P2内" << endl;
else
cout << "Q点不在线段P1P2内" << endl;
}
Java代码:
/**
* 判断鼠标的点是否在线段上
* @param p1x
* @param p1y
* @param p2x
* @param p2y
* @param x
* @param y
* @return
*/
private boolean onSegment(int p1x, int p1y, int p2x, int p2y, int x, int y) {
if (x >= min(p1x, p2x) && x <= max(p1x, p2x) && y >= min(p1y, p2y)
&& y <= max(p1y, p2y))
return true;
else
return false;
}
/**
* 判断两点的最小值
* @param x1
* @param x2
* @return
*/
private int min(int x1, int x2) {
if (x1 > x2)
return x2;
else
return x1;
}
/**
* 判断连点的最大值
* @param x1
* @param x2
* @return
*/
private int max(int x1, int x2) {
if (x1 < x2)
return x2;
else
return x1;
}
/**
* 计算点到直线的距离
* @param x1 线段上的一个端点
* @param y1
* @param x2 线段上的一个端点
* @param y2
* @param x3 待测点
* @param y3
* @return
*/
private boolean ptOnLine(double x1, double y1, double x2, double y2,
double x3, double y3) {
if (!onSegment((int) x1, (int) y1, (int) x2, (int) y2, (int) x3,
(int) y3))
return false;
double distance = (Math.sqrt(quadratic(x2, x3) + quadratic(y2, y3)) + Math
.sqrt(quadratic(x1, x3) + quadratic(y1, y3)));
double p2pDist = Math.sqrt(quadratic(x2, x1) + quadratic(y2, y1));
if (distance - p2pDist < 1 && distance - p2pDist > -1)
return true;
else
return false;
}
/**
*
* @param x
* @param y
* @return
*/
private double quadratic(double x, double y) {
return (y - x) * (y - x);
}