C语言:变量的深入理解

news2024/9/21 10:42:05

文章目录

    • 一.什么是变量
      • C语言中为什么要有类型?
      • C语言中的类型为什么有这么多种呢?
      • 定义变量的本质
      • 为什么需要定义变量
      • 定义变量的本质
      • 定义变量时的规则
    • 二.深刻理解signed/unsigned定义的变量
      • 1.运算时的符号位
      • 2.数据的存储情况
      • 3.unsigned定义时的小细节
    • 三.大小端问题
    • 四.signed定义的数据类型的取值范围
    • 五.浮点数的一些奇奇怪怪的理解
    • 六.数据在内存中的存储

一.什么是变量

C语言中为什么要有类型?

本质是对内存的空间合理划分,按需索取。int就是在内存开辟4个子节的空间,不会多开辟,也不会少开辟。

C语言中的类型为什么有这么多种呢?

因为应用场景不同,解决应用场景对应的计算方式也是不同的,需要空间的大小同样也是不同的。就行定义身高,你就是要用浮点型。定义年龄你只会用int型,而不是用20.1来代表你的年龄。
本质就是用最小的成本来解决各种多样化的问题。

定义变量的本质

在内存中开辟特定的大小的空间,来保存数据。

为什么需要定义变量

换句话说,为什么需要变量,因为有数据需要保存起来,等待后续的处理,如果不定义变量来保存,之后在用的时候可能就没了。

定义变量的本质

本质就是在内存中开辟一个空间用来保存数据。但是为什么一定要在内存中开辟呢?因为定义变量也是程序逻辑的一部分,在定义的时候,写的程序已经被加载到内存中了(程序在被加载之前都存在硬盘当中)。

定义变量时的规则

以下讲的都是比较推荐的写法,当然你要怎么定义就怎么定义。

  1. 用最短的名字传递最多的信息。
  2. 全局变量名字前最好加一个g_。
  3. 宏定义,只读变量,枚举常量定义的字母要全部大写,单词之间要用_来隔开。
  4. 定义变量要初始化。

这里稍微讲一下为什么要初始化,在任何函数包括主函数在程序运行时都会经过压栈,才能给函数在内存中开辟好空间,但不是所有编译器在开辟好空间后都会给你初始化成0,也就是说如果在里面定义变量又不初始化的时候,那些变量的值可能就是随机值。而后来你又不小心用到这些没有初始化的变量就会出错。所以不管你用不用这个变量,一定要先初始化。

二.深刻理解signed/unsigned定义的变量

signed/unsigned一般修饰的都是整型。

1.运算时的符号位

如果这里有一个有符号的两个变量,在计算的时候符号位要不要进行计算?

直接说结论:要。

2.数据的存储情况

先看这样的一个代码:

int main()
{
	unsigned int a = -10;
	printf("%d\n", a);
	printf("%u\n", a);

	return 0;
}

这代码的结果:
在这里插入图片描述

为什么会有如此大的反差呢?
接下来我一步一步分析。

先看-10是如何存的。

unsigned int只是为10开辟了一块4字节的空间:
在这里插入图片描述

但是-10在存之前是不看a是什么类型的。也就是说-10在存之前已经转换成了对应的二进制补码:
在这里插入图片描述
假如a这个变量的类型是char类型的,存进来后就会发生截断。

以上就是-10如何存到内存当中的,主要记住的一个点就是:数据是直接转化成对应的二进制补码之后才开始存到内存中的。

然后再看如何取的:

	printf("%d\n", a);
	printf("%u\n", a);

-10已经存到对应的变量里的,现在-10默认的是unsigned int类型的。入乡随俗嘛,你进到a这个变量里了,你就是和a类型一样了。但是这也只是默认的。

那%d,%u是什么意思呢?就是你在取得时候也不会考虑a这个变量是什么类型的,我用%d的方式来取,我就当你a里面存的就是有符号类型的值。现在读我就当里面的二进制数:
11111111 11111111 11111111 11110110是一个负数的补码。所以在打印的时候把最高位当成符号位然后转化成原码打印出来。

%u也是一样,它也不管a是什么类型,就当里面存的二进制数是一个无符号整数。所以直接把上面那个二进制数转成10进制数后打印出来也就是我们上面看到的那个很大的数。

小总结一下
数据在存的时候不看要存的那个变量是什么类型的,直接先转化成对应的二进制补码,如果那个变量类型空间够就直接存,不够就发生截断在放进去。

取出的过程中,同样也不管你变量a是什么类型的,如果以%d形式打印我就认为你存的是一个有符号数。如果以%u打印我就认为你存的是一个无符号数。

3.unsigned定义时的小细节

推荐在定义无符号类型时后面+u。

int main()
{
	//大小写u都可以
	unsigned int b = 10U;
	printf("%d\n", b);
	printf("%u\n", b);

	return 0;
}

这样加上之后就知道你这个数字它就是无符号类型,当然你不加也没关系,加上的话,如果你这个数字是负数还会报错。

三.大小端问题

本质是数据和空间以字节为单位的一种映射关系。

在这里插入图片描述
在这里插入图片描述

四.signed定义的数据类型的取值范围

这里以signed char来举例。

char会开辟一个字节也就是8个比特位的空间,取值范围应该是:
在这里插入图片描述

因为它是有符号数据,所以最高位应该是符号位,所以取值范围应该是:
在这里插入图片描述

仔细看可以发现一个问题,0在这里好像出现了两次:
10000000,00000000也就是一个+0,一个-0.

但是计算机为了提高效率不可能让这两个都表示0,同时为了让效率最大化也不能丢掉其中一个0.所以现在需要用多的那个0来表示一个其它数据,而多的那个0最好用10000000,因为00000000来表示0是最好不过的了。

现在的问题就是10000000用来表示谁呢?经过上图可以发现-127~127都有人来表示了,所以10000000只有128和-128两种选择。经过重重考量其实用10000000来表示-128是最好的了。为什么呢?首先这是有符号类型,也就是说最高位是符号位,而10000000最高位是1,说明它是一个负数,如果用它表示128这个整数就会有歧义。所以这里把它定义成128是最好的了。

所以通过这些可以判断出有符号char类型的取值范围是-128~127.

但是还有最后一个问题,凭啥?凭啥你说它代表-128就是-128.下面我们来看看-128是怎么存到空间中的:

先看-128的原码。
在这里插入图片描述

发现它是9位的,存到char里面要发生截断:
在这里插入图片描述

现在发现了一件神奇的事情-128的原码是110000000,它转化成补码后还是110000000.

然后在做一件事情:把10000000取出来:
在这里插入图片描述

因为之前发生了截断,所以不能正常的提取出来。所以在这里做了一个规定(主要啊,不是我规定的)10000000代表的就是-128,以后看到10000000就知道它是-128.

为了加深记忆,这里我画了一个图:
在这里插入图片描述

五.浮点数的一些奇奇怪怪的理解

我们先看一个代码:

int main()
{
	double a = 1.0;
	double b = 0.9;
	printf("%.50lf\n", a);
	printf("%.50lf\n", b);
	printf("%.50lf\n", a - b);

	return 0;
}

再来看结果:
在这里插入图片描述
打印数据的后50位,发现了一个神奇的现象,1确实还是1,但是0.9和1-0.9好像就不是原来的数了。

接下来在看段代码:

int main()
{
	double a = 1.0;
	double b = 0.9;
	if (a - b == 0.1)
	{
		printf("相等");
	}
	else
	{
		printf("不相等");
	}

	return 0;
}

看结果:
在这里插入图片描述

发现1-0.9竟然不等于0.1,这两个不正常的现象是为什么呢?因为浮点数本身放在内存中后会有精度丢失的,可能比原来小一丢丢,也有可能大一丢丢。所以浮点数本身是不能直接比较的。

但如果我们就是想比较,该怎么做呢?比如说想比较a-0.1和b的值是否相等。此时可以在其基础上加上一个修正值。我们可以包含一个头文件:

#include <float.h>

这个文件里有两个宏定义:
在这里插入图片描述

这两个宏是什么意思呢?我拿其中一个说:有一个数字它加上任何一个数字,都能改变这个数字的大小。而DBL_EPSILON是这些数字中最小的那一个。

这个DBL_EPSILON就是我们需要添加的修正值。如果判断两个数是否相等,这两个数相减,值应该等于0对吧,但是因为精度的确实,这个值肯定会比0稍微大那么一丢丢丢丢或者小一丢丢丢丢。但是如果这个值在-DBL_EPSILON和DBL_EPSILON之间的话,我们还是可以认为它们俩相等的,所以代码可以这样写:

#include <float.h>
#include <math.h>
int main()
{
	double a = 1.0;
	double b = 0.9;
	//需要比较的两个值是a-0.1和0.9
	if (fabs(a - 0.1 - 0.9) < DBL_EPSILON)
	{
		printf("相等");
	}
	else
	{
		printf("不相等");
	}

	return 0;
}

既然相间的范围在-DBL_EPSILON和DBL_EPSILON之间,是不是可以写成绝对值在0和DBL_EPSILON之间。

所以如果只在这个区间内,我们还是可以认为这两个数相等的。
在这里插入图片描述

既然这样,我在提一个问题,上面的小于号可不可以写成小于等于:

#include <float.h>
#include <math.h>
int main()
{
	double a = 0.0;
	double b = 0.9;
	if (fabs(a - 0.0) <= DBL_EPSILON)
	{
		printf("相等");
	}
	else
	{
		printf("不相等");
	}

	return 0;
}

上面先简化一下代码让a和0比较。首先答案时不推荐加上等号

首先这个代码是用来判断a和0是否相等,如果上面的条件加上等号就说明在a==DBL_EPSILON的时候,a和0相等这个逻辑也是成立的。但是DBL_EPSILON是引起一个数中变化最小的那个值,满足:b + DBL_EPSILON != b的这个条件。如果说a在等于DBL_EPSILON的时候同时满足a = = 0,不就相当于a = = DBL_EPSILON = = 0.但是0的概念是:b + 0 = = b.这和b + DBL_EPSILON != b有冲突,所以不能加等号。

六.数据在内存中的存储

数据在内存中的存储(一)

数据在内存中的存储(二)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/80111.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 13 VTS HIDL interface 解析

Android 13 VTS Introduction Android 13已经发布&#xff0c;VTS testcase发生很多变化&#xff0c;在此博客中对其每个测试项目进行流程介绍。 这里先对VTS 做一个介绍&#xff1a; VTS是vendor test suite简称&#xff0c;意为供应商测试套件。目的是确保Vendor层实现的兼容…

Spring Boot自动装配原理

Spring Boot自动装配原理1.Spring Boot 入口2.SpringBootApplicationSpringBootConfigurationComponentScanEnableAutoConfiguration判断自动装配开关是否打开获取EnableAutoConfiguration注解中的 exclude 和 excludeName获取需要自动装配的所有配置类最后3.总结1.Spring Boot…

Github访问量过百万!阿里内部至尊级分布式事务手册,实至名归

分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说&#xff0c;就是一次大的操作由不同的小操作组成&#xff0c;这些小的操作分布在不同的服务器上&#xff0c;且属于不同的应用&#xff0c;分布式…

[附源码]JAVA毕业设计养生药膳推荐系统(系统+LW)

[附源码]JAVA毕业设计养生药膳推荐系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术…

[LeetCode周赛复盘] 第 323 场周赛20221211

[LeetCode周赛复盘] 第 323 场周赛20221211 一、本周周赛总结二、 [Easy] 6257. 删除每行中的最大值1. 题目描述2. 思路分析3. 代码实现三、[Medium] 6258. 数组中最长的方波1. 题目描述2. 思路分析3. 代码实现四、[Medium] 6259. 设计内存分配器1. 题目描述2. 思路分析3. 代码…

web前端期末大作业【足球网页】学生网页设计作业源码

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

基于C++实现(控制台)单位职工管理系统(数据结构)【100010017】

1需求分析 1.1 问题描述 对单位的职工进行管理&#xff0c; 包括插入、 删除、 查找、 排序等功能。 1.2 问题要求 职工对象数不必很多&#xff0c; 便于一次读入内存&#xff0c; 所有操作不经过内外存交换。 &#xff08;1&#xff09; 由键盘输 入职工对象&#xff0c;…

1564_AURIX_TC275_电压监控寄存器整理

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 1. 如果HSM保护开启了&#xff0c;那么访问修改其他的bit就会导致一个总线错误。 2. SMU中可以配置电压监控的相关alarm是否配置 生效。 这个寄存器是几个欠压阈值的配置&#xff0c;在这…

在Ubuntu中为ROG笔记本安装驱动asusctl

我是在Kubuntu22.04上安装的&#xff0c;系统自带“省电”、“平衡”、“性能”三个电源选项&#xff0c;显卡模式切换是拿nvidia驱动切换的&#xff0c;所以目前装的这个驱动我只用到了灯光调节功能。 文章目录介绍安装安装asusctl卸载显卡模式切换驱动supergfxctl使用方法启用…

LwIP——无操作系统启动流程

目录 启动流程 虚拟网卡控制块 发送流程 接收流程 总结 启动流程 通过阅读正点原子的无操作系统移植工程的源码&#xff0c;可以总结出LwIP的无操作系统的启动流程。 前面一些都是基于其他的外设的初始化&#xff0c;我们只关心这里lwip_comm_init()&#xff0c;这个函数的…

eve-ng ubuntu 20.04 设置iptables

eve-ng ubuntu 20.04 设置iptables一、设置方法1、建立iptables规则开机加载脚本2、建立iptables规则关机/重启保存脚本3、添加可执行权限4、保存当前iptables规则到配置文件二、命令解释一、设置方法 1、建立iptables规则开机加载脚本 sudo vi /etc/network/if-pre-up.d/ipt…

(十一)Vue之条件渲染

文章目录v-if与v-else-if、v-else一起使用v-show关于 <template>标签Vue学习目录 上一篇&#xff1a;&#xff08;十&#xff09;Vue之绑定样式 v-if v-if&#xff0c;默认为true&#xff0c;如果为false&#xff0c;底层实现是直接把这个节点删除 适用于&#xff1a;…

MLE,MAP,经验风险最小化,结构风险最小化,邻域风险最小化

文章目录Maximun likelihood extimationMaximum A Posterior EstimationVicinal Risk Minimization, VRMMaximun likelihood extimation 最大似然估计:样本->参数,完全相信观测到的数据,最优可能产生这些看到的数据的模型就是最理想的模型. 频率学派认为,参数是一个常数,不…

fpga实操训练(基础)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 之前我们虽然说过怎么编写verilog代码&#xff0c;怎么用iverilog软件和gtkwave软件进行仿真验证&#xff0c;但是一直没有说明如何在真实的板子上…

web前端期末大作业——基于HTML+CSS+JavaScript仿蘑菇街时尚服装购物商城

常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他等网页设计题目, A…

28个你应该知道的JavaScript技巧

今天我将分享一些Javascript中的常用技巧&#xff0c;以帮助您解决问题。设置过程中的常见问题更快更容易。 01、Javascript 反向字符串 下面是代码&#xff1a; /*niemvuilaptrinh.com*/const stringReverse str > str.split("").reverse().join("")…

搜索引擎项目测试报告

目录单元测试构建索引模块文档信息对象Document的构建的单元测试**针对每一篇文档进行分析、处理、分词**针对文档内容提取关键字的测试&#xff08;正则表达式&#xff09;测试去掉script测试去掉标签完整测试Document类中的parseContent方法关于ansj分词器的测试关于构建倒排…

CleanMyMac4.12.2最新免费的macOS电脑清理工具

相信不少的小伙伴都在用苹果电脑&#xff0c;不论是 iMac&#xff0c;还是 MacBook&#xff0c;用着用着电脑就变慢了。这通病与苹果电脑的性能无关&#xff0c;主要是硬盘空间不足的问题&#xff01;当然你可以在购买电脑的时候就把硬盘升级&#xff0c;但主要的问题是 – 没有…

python代码圣诞树你还没有嘛?所有画法都在这篇文章里拉~

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~ 今天&#xff0c;我就来给大家分享一下python制作的几种圣诞树吧~ 一&#xff1a;唯美圣诞 代码展示 导入模块 完整源码点击领取即可 import turtle as t from turtle import * import random as r import time n 100.0spee…

【JavaWeb】Tomcat的入门使用

1Tomcat的相关概念: Tomcat是Apache软件基金会一个核心项目&#xff0c;是一个开源免费的轻量级Web服务器&#xff0c;支持Servlet/JSP少量JavaEE规范。 概念中提到了JavaEE规范&#xff0c;那什么又是JavaEE规范呢? JavaEE: Java Enterprise Edition,Java企业版。指Java企业…