learn_C_deep_6 (布尔类型、布尔与“零值“、浮点型与“零值“、指针与“零值“的比较)(下)

简介: learn_C_deep_6 (布尔类型、布尔与“零值“、浮点型与“零值“、指针与“零值“的比较)

learn_C_deep_6 (布尔类型、布尔与“零值“、浮点型与“零值“、指针与“零值“的比较)(上):https://developer.aliyun.com/article/1424508


“零值”的比较


1.bool变量与“零值”比较


#include <stdbool.h>

#include <windows.h>

int main()

{

   int pass = 0; //0表示假,C90,我们习惯用int表示bool

   //bool pass = false; //C99


   写法一:

   if (pass == 0) { //理论上可行,但此时的pass是应该被当做bool看待的,== 用来进行整数比较,不推荐

       //TODO

   }


   写法二:

   if (pass == false) { //不推荐,尽管在C99中也可行

       //TODO

   }


   写法三:

   //1.先执行()中的表达式,得到真假结果(true or false,逻辑结果) - 而这里的pass本身就是逻辑结果

   //2.条件  判定功能

   //3.进行  分支功能

   if (pass) { //推荐 - 直挂的反应出来了,flag是"bool"

       //TODO

   }

   system("pause");

   return 0;

}


结论:bool类型,直接判定,不用操作符进行和特定值比较。


2.float、double变量与“零值”比较 - (这里以double为例)


我们接下来看这个代码,后面的注释是我们预测的输出。


#include <stdio.h>

int main()

{

   double x = 1.0;

   double y = 0.1;

   printf("%.50f\n", x - 0.9);//0.1

   printf("%.50f\n", y);//0.1

   if ((x - 0.9) == y) {

       printf("you can see me!\n");//输出you can see me!

   }

   else {

       printf("you can not see me!\n");

   }

   return 0;

}


但是当我们运行这个代码的时候,结果令我们大失所望呀。


为什么呢?

这里我们将数值3.1打印50的精度,结果出现了一大堆意外的数字。


 这是因为浮点数在内存中存储,并不想我们想的,是完整存储的,在十进制转化成为二进制,是有可能有精度损失的。 注意这里的损失,不是一味的减少了,还有可能增多。浮点数本身存储的时候,在计算不尽的时候,会“四舍五入”或者其他策略。所以上面才会输出you can not see me!


那么两个浮点数该如何比较呢? -  应该进行范围精度比较


       在 C 语言中,由于浮点数的精度问题,不能直接使用等于号(==)判断两个浮点数是否相等。通常使用以下方法来比较两个浮点数的大小关系:


       1.定义一个比较精度值 EPS,例如 1e-6,代表可接受的最小误差范围;

       2.判断两个数之差(绝对值)是否小于等于精度值 EPS;


了解fabs函数


       


       在 C 语言中,fabs 函数属于 math.h 头文件,因此在使用该函数前需要先包含 math.h 头文件。该函数返回一个 double 类型的值,可以用于计算浮点数的绝对值。


当我们去改进程序后,我么发现就可以比较两个浮点数了。


两个精度定义


我们发现我们定义1e-6(也就是0.000001),可能有时候设置的误差范围比较大导致判断错误,那么我们一个具体怎么设置这个值呢,那么此时C语言就提供了两个精度:


#include //使用下面两个精度,需要包含该头文件

DBL_EPSILON //double 最小精度

FLT_EPSILON //float 最小精度


转到定义后


        XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数。 EPSILON这个单词翻译过来是'ε'的意思,数学上,就是极小的正数 。


请问我们这样写会有问题嘛? -  问题是:要不要相等


       XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数。 XXX_EPSILON+n不等于n的最小的正数: 有很多数字+n都可以不等于n,但是XXX_EPSILON是最小的,但是, XXX_EPSILON依旧是引起不等的一员。 换句话说:fabs(x) <= DBL_EPSILON(确认x是否是0的逻辑),如果=,就说明x本身,已经能够引起其他和他+和-的数据本身的变化了,这个不符合0的概念。


现在我们来回归主题:float、double变量与“零值”比较

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <windows.h>
int main()
{
  double x = 0.00000000000000000000001;
  //if (fabs(x-0.0) < DBL_EPSILON){ //写法1
  //if (fabs(x) < DBL_EPSILON){ //写法2
  if (x > -DBL_EPSILON && x < DBL_EPSILON) { //写法3
    printf("you can see me!\n");
  }
  else {
    printf("you can not see me!\n");
  }
  system("pause");
  return 0;
}


总结:在 C 语言中,由于浮点数在计算机中存储的方式和精度限制的原因,不能直接使用等于号来判断两个浮点数是否相等,也不能直接判断浮点数是否等于 0.0,如果我们要比较,就需要形成一个极小的精度EPS,然后将这个数与0.0的差值的绝对值进行比较,这样我们才能判断float、double变量与“零值”的比较。


3.指针变量与"零值"比较


       常识补充:对NULL, '\0', 0的整体理解


1.NULL、'\0'和0是C语言中常用的三个表示“0”的值。


2.它们的类型是不同的。


1. NULL:通常被定义为一个值为0的宏,表示指针不指向任何有效的内存地址。在大多数情况下,一个指针的值为NULL表示其未被初始化或者指向了无效的内存地址,NULL是'0'被强制转换成指针类型的值。

2. '\0':是一个字符常量,表示字符数组的结束符。在C语言中,字符串是由字符数组组成的,每个字符串的结尾都必须以'\0'字符作为结束标志,告诉程序字符串的长度。

3. 0:是整数常量的一种,表示数值0。在C语言中,用0来表示逻辑假,非0的值表示逻辑真。


3.强制类型转化的理解  


总结:强制类型转化没有改变内存中的数据,只是改变了它的类型。


接下来看下面的写法哪个好

#include<stdio.h>
int main()
{
    int* p = NULL;
    if (p == 0)
    {
        //写法一
    }
    if (p)
    {
        //写法二
    }
    if (NULL == p)
    {
        //写法三
    }
    return 0;
}


写法一:尽管NULL的值和0一样,但是意义不同,写法一容易让人认为p是整形变量

写法二:让人认为p是bool变量

写法三:很容易让人认识到这是指针相关的判断

相关文章
|
1月前
|
C语言 C++
【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)
【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)
|
2月前
|
存储 Go
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
3月前
|
存储 安全 Go
深入理解 Go 语言中的指针类型
【8月更文挑战第31天】
46 0
|
5月前
|
编译器 C++
函数指针和函数对象不是同一类型怎么替换
函数指针和函数对象不是同一类型,为何可替换用作同一函数的参数
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
49 0
|
5月前
|
图形学 Windows
程序技术好文:记录类型指针
程序技术好文:记录类型指针
27 0
|
5月前
|
JSON Go 数据格式
Go 语言基础之指针、复合类型【数组、切片、指针、map、struct】(4)
Go 语言基础之指针、复合类型【数组、切片、指针、map、struct】
|
5月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
1月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
25 0
|
2月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
下一篇
无影云桌面