第二章——C程序设计的初步知识 第三节——C语言基本数据类型及其定义规则
一、常量
在生活中,我们常常会有一些不需要去更改的数值,比如说一天,我们知道他就是 24 小时,比如说 1 小时,他就绝对是 60 分钟,诸如此类的。像这种在程序运行时不会改变的值,我们称作常量。
1. 定义
程序运行时其值不能改变的量(即常数)
2. 分类
- 符号常量
由用户用标识符所定义的常量,称为符号常量
- 格式:#define 符号常量 常量
1 |
|
- 一般使用大写字母作为常量名
- 是宏定义预处理命令,不是C语句
- 直接常量
- 整型常量
- 实型常量
- 字符常量
- 字符串常量
接下来我们分别来讲一下直接常量
二、整型常量(整常数)
1. 形式
一般来说,整型常量我们有如下三种类型,分别对应不同的进制
- 十进制整数:由数字0~9和正负号表示.如 123,-456,0
- 八进制整数:由数字0开头,后跟数字0~7表示.如0123,011
- 十六进制整数:由0x开头,后跟0
9,af,A~F表示. 如0x123,0Xff
对于进制之间的相互转换此处不做教学,兴趣的可以自己学学。
其中十进制整数有正负,而八进制,十六进制没有正负,仅能以正数存在。
2. 类型
- 根据其值所在范围确定其数据类型
- 在整常量后加字母l或L,认为它是long int 型常量
补充:整数在内存中的存储形式
基于在计算机中,存储数据均是以 0 和 1 的二进制作为基准。此时,存储正数很好理解,比如 5,以八位二进制为主,表示为0000 0101,但是负数就比较有意思了,比如-5,就不能单纯的表示为**-0000 0101**。
此时我们引入两个新的概念, 有符号整数 和 无符号整数。
- 有符号整数:最高位是符号位(0是正,1是负)。
- 无符号整数:所有位都是数值,没有符号位。
然后,我们表示负数的话,需要基于有符号整数,再度引入一个概念叫做补码。
- 补码的简单规则:
- 先写出正数的二进制(比如5是
0000 0101)。 - 全部取反(0变1,1变0)→
1111 1010。 - 加1 →
1111 1011。这就是-5 的补码
- 先写出正数的二进制(比如5是
这样设计的好处就是,可以直接用加法电路计算正负数,计算机处理起来更方便。
此时再来分别看一下 有符号整数 和 无符号整数。
- 正数:比如 5 → 0000 0101
- 负数:比如 -5 → 1111 1011
- 最大正数(无符号):所有位都是 1 → 1111 1111 → 255(因为 2⁸ -1 = 255)。
- 最大负数(有符号,最高位0 是正,1 是负):最高位是 1,其他为 0 → 1000 0000 → -128(因为 2⁷ = 128)。
总结就是,计算机用0和1的开关组合表示数字,正数直接存,负数用“补码”存,内存里存的是二进制,具体数值要看类型(有符号/无符号)和位数。所以比较有意思的就是,在不指明类型的情况下,有可能-1=65535.
三、C语言基本数据类型及其定义规则
1. 常量
在生活中,我们常常会有一些不需要去更改的数值,比如说一天有24小时,1小时等于60分钟。在程序中这些固定值就叫做常量。
1 |
|
1.1 分类
- 符号常量:用
#define定义的常量,如上面的PI - 字面常量:直接写出的数字或字符,如
123、3.14、'A'
1.2 注意事项
- 常量一旦定义就不能修改
- 建议使用全大写字母命名常量(约定俗成)
2. 变量
与常量相对的是变量,它的值可以在程序运行过程中改变。
1 | int age = 20; // 整型变量 |
2.1 数据类型
C语言中有以下常用基本数据类型:
| 类型 | 关键字 | 典型用途 |
|---|---|---|
| 整型 | int |
存储整数 |
| 浮点型 | float/double |
存储小数 |
| 字符型 | char |
存储单个字符 |
| 无值型 | void |
表示没有类型 |
2.2 变量命名规则
- 只能使用字母、数字和下划线
- 首字符不能是数字
- 区分大小写(
age和Age不同) - 不能使用关键字(如
int、return等) - 推荐使用有意义的名字(如
studentName而不是x)
四、实型常量(实数或浮点数)
1. 表示形式
- 十进制数形式:(必须有小数点) 如0.123, .123, 123.0, 0.0, 123.
- 指数形式:(e或E之前必须有数字;指数必须为整数)如12.3e3 ,123E2, 1.23e-4
2. 实型常量的类型
在 C 语言中,象是类似于 3.14,0.5 之类的数字,默认会是 double 的类型,如下
1 | double d = 3.14; |
如果我们想明确为 float 型,则需如下定义:
1 | float f = 3.14f; |
对于如何选择 double 和 float,需要看自己的精度需求
| 特性 | double(默认) |
float(加 f/F) |
|---|---|---|
| 内存占用 | 通常 8 字节 | 通常 4 字节 |
| 精度 | 高(15-17 位有效数字) | 低(6-9 位有效数字) |
注意:
在内存中,实数一律是以指数形式存储的
实数(如 3.14、1.23e-4)在内存中以二进制科学计数法的形式存储,即 符号位 + 指数部分 + 尾数部分。这种设计可以同时满足以下需求:
- 表示极大或极小的数值(如天文数字或量子物理中的微小值)。
- 节省存储空间(通过指数压缩数值范围)。
- 平衡精度与范围(通过尾数位数控制有效数字)。
以 3.14159 为例,分步说明其如何被转换为二进制指数形式并存储:
1. 转换为二进制科学计数法
十进制转换为二进制:
3.14159的二进制表示为11.001001000011111101101...(精确二进制可能无限长,但内存中只能存储有限位数)。规范化:
将二进制数写成 1.xxxxx… × 2^指数 的形式:
11.001001000011111101101…_{2} =1.1001001000011111101101… _{2} ×2^{2}规范化的目的是统一格式,确保尾数部分的二进制数在
[1.0, 2.0)范围内(二进制中最高位隐含为1,无需存储)。
2. 分配内存空间(以 float 为例)
- float 类型:占 4字节(32位),按以下结构存储:
1 | 符号位(1位) | 阶码(8位) | 尾数(23位) |
符号位(Sign):
0表示正数,1表示负数。例如3.14159是正数 → 符号位为0。阶码(Exponent,指数部分):
将指数 2 加上一个偏移量(float的偏移量是127),得到2 + 127 = 129,然后转换为二进制:
129_{10} =10000001_{2}
这样,指数部分存储为 `10000001`。尾数(Mantissa,有效数字部分):
规范化后的二进制数1.1001001000011111101101...中,去掉前面隐含的1,只存储小数点后的部分:1001001000011111101101…→取前23位→10010010000111111011011
尾数部分存储为 10010010000111111011011。
3. 最终内存存储形式
将符号位、阶码和尾数按顺序拼接:
1 | 0(符号)∥10000001(阶码)∥10010010000111111011011(尾数)0(符号)∥10000001(阶码)∥10010010000111111011011(尾数) |
二进制表示:
1 | 0100000011001001000011111101101101000000110010010000111111011011 |
十六进制表示(方便阅读):
40490FD7_{16}
计算机中存储整数不会出现误差,存储实型数往往存入误差。
从上面的存储方式可以看出来,小数的存储方式极其复杂,并且会有一定的舍弃,这一部分舍弃也就造就了计算机在存储实型数据是会产生误差,而我们的整数因为只需要将其转换后便可以存储,所以并不会出现误差。
三、字符常量
1. 定义
用单引号括起来的单个普通字符或转义字符,例如 'a'、'C'、'7'、'\n' 等等,包括大小写字母,数字,标点符号,特殊符号,转义字符。
2. 字符常量的值
该字符的ASCII码值,在 ASCII 表中,每个字符都有对应的码值。在内存中以 ASCII码 的形式存储为整数(占1个字节)。例如 'A' 的ASCII码是 65,'0' 是 48。
3. 转义字符
反斜线后面跟一个字符或一个代码值表示,用来表示一些不可见或特殊功能的字符。部分举例如下:
| 转义字符 | 含义 | ASCII码 |
|---|---|---|
'\n' |
换行符 | 10 |
'\t' |
制表符(横向跳格) | 9 |
'\r' |
回车符 | 13 |
'\b' |
退格符 | 8 |
'\'' |
单引号 ' |
39 |
| ‘"‘` | 双引号 " |
34 |
'\\' |
反斜杠 \ |
92 |
'\0' |
空字符(结束符) | 0 |
4. 非法的字符常量
使用双引号
”A” 是字符串常量,不是字符常量。
多个字符
’AB’ 是非法的,单引号内只能有一个字符。
缺少反斜杠的转义字符
如果想表示单引号 ',必须写成 '\'',而不是 '(否则单引号会被当作结束符)。
四、字符串常量
1. 定义
用双引号(“”)括起来的字符序列,在之前的字符常量中,仅能表示单个字符,而字符串常量能表示好多,比如”ASDFGHJK”
2.存储
每个字符串尾自动加一个 \0 作为字符串结束标志
以存储一个 Hello 为例
| H | E | L | L | O | \0 |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 |
同时,字符串常量也可以是空串,即什么都没有 " ",在内存中为
| \0 |
|---|
| 0 |
字符串常量和字符常量也是有区别的,比如字符常量 'a' 和字符串常量 "a",在内存中如下:
| 字符常量 | 字符串常量 |
|---|---|
| a | a \0 |
五、变量
变量,看名字就可以看出来,他与常量不同,是可以变化的一个值。
1. 概念
其值可以改变的量
2. 特点
变量初始化:在C语言中,变量是需要初始化的,因为变量在存储时,需要从内存单元中获取到值,而我们的内存并不会真正意义上的“删除”,只是去“覆盖”,所以说当我们的变量没有初始化时,那从内存中读到的值就可能是一些无用的杂乱数据,会对程序的运行造成影响,因此我们需要对变量进行初始化。
变量的使用:变量的使用必须遵守“先定义后使用” 的规则,如下:
1 | // 定义方法一 |
两种写法的区别是分不分行,作用上相同,我个人是习惯,如果变量在三个一下,使用第二种写法,如果变量超过三个,使用第一种写法。(前提是变量类型相同)
3. 变量定义的位置
变量一般来说按照如上写法写,但是不排除有特殊情况(比如临时需要一个)
六、整型变量
- 整型变量,即整数类型变量,占字节数随机器的不同而不同,一般只占一个机器字(机器字:即CPU一次能处理的二进制数据的位数,由寄存器和数据总线宽度决定。如32位CPU,则机器字一次只能处理32位的二进制数据,换算之后也就是四字节,同样的,64位CPU,则机器字一次只能处理64位的二进制数据,换算之后也就是8字节)。
- 在整型变量中,共有三种数据类型,分别是:short、int、long。三者在范围上:short ≤ int ≤ long。
- 在不同机器上,三个类型范围有所不同。具体的我们可以使用sizeof函数来查看。sizeof函数用于获取 数据类型 或 变量 在内存中所占的 字节数。
七、实型变量
说完整形,我们来说说实型变量(我习惯叫浮点型,从python那边带过来的习惯了,有时候我可能会把实型叫浮点型,但是为了避免混淆,还是叫实型变量)。实型变量共有两种类型,分别是:float、double。
- float:float类型占4个字节,float类型在计算机中占4个字节,float类型在计算机中的存储方式就是小数点后保留6位,也就是6位小数。
- double:double类型占8个字节,double类型在计算机中占8个字节,double类型在计算机中的存储方式就是小数点后保留15位,也就是15位小数。
两种类型输出如下:
1 |
|
输出结果为:
1 | float a = 10.123457 |
这时候有个疑问就是,为什么输出的float a = 10.123457,而double b也是等于10.123457呢?在此我们还要注意一个就是我们在使用printf函数时,要考虑到占位符%f的精度,默认情况下,%f的精度只有6位小数,我们要是想输出高i精度的数据,则需要对占位符进行修改,比如:%.10f,这种类型的格式化输出表示输出10位小数。
八、字符型变量
字符变量,也叫字符型变量,在C语言中,字符变量通常存储的是字符的ASCII码值,而ASCII码值是数字,只占一个字节,所以其实可以与int数据之间进行运算,举例如下:
1 |
|
输出结果为:
1 | a = 97 |
基于此,我们便有以下玩法:
1 |
|
输出结果为:
1 | a = 97 |
不仅仅是与int型相加,更好玩的还有float和double型相加。我们逐个来讲:
char与float相加
1. 类型转换规则
当 char 和 float 进行运算时,会发生以下隐式类型转换:
char→int:char是整数类型(1字节),先被提升为int(4字节)。int→float:
提升后的int再被转换为float(4字节),因为float的优先级高于int。- 运算结果类型为
float:
最终运算结果以float类型存储。
2. 具体示例
示例 1:char 与 float 相加
1 |
|
解释:
c的 ASCII 码值为 65。65被提升为int类型(65),再转换为float类型(65.0)。- 65.0 + 3.14 = 68.14,结果存储为
float类型。
示例 2:有符号 char 的负值
1 |
|
解释:
- 有符号
char的-10被提升为int类型(-10),再转换为float类型(-10.0)。 - -10.0 + 2.5 = -7.5,结果为
float类型。
3. 注意事项
(1) 无符号 char 的转换
如果 char 是 unsigned char,其范围为 0~255,转换规则类似:
1 | unsigned char c = 200; // 无符号 char 的最大值为 255 |
(2) 精度问题
虽然 char 的范围较小(-128127 或 0255),但 float 的精度足够表示这些整数,因此不会出现精度损失。但如果 char 的值通过复杂计算得到,需注意浮点数的舍入误差:
1 | float a = 0.1f; |
(3) 避免直接比较
由于浮点数的精度问题,不建议直接用 == 比较 char 和 float 的值:
1 | char c = 'A'; // 65 |
但注意:如果 f 是通过计算得到的近似值(如 f = 65.000001),比较结果可能为假。
4. 显式类型转换
为了代码的清晰性,可以显式转换 char 为 float:
1 | char c = 'B'; // ASCII码值为 66 |
char与double相加
1. 类型转换规则
当 char 与 double 相加时,会发生以下隐式类型转换:
char→int:char是整数类型(1字节),先被提升为int(4字节)。int→double:
提升后的int再被转换为double(8字节),因为double的优先级高于int。- 运算结果类型为
double:
最终运算结果以double类型存储。
2. 示例代码
示例 1:基本运算
1 |
|
解释:
c的 ASCII 码值为 65。65被提升为int类型(65),再转换为double类型(65.0)。- 65.0 + 3.14 = 68.14,结果存储为
double类型。
示例 2:无符号 char 的负值
1 |
|
解释:
- 有符号
char的-10被提升为int类型(-10),再转换为double类型(-10.0)。 - -10.0 + 2.5 = -7.5,结果为
double类型。
3. 注意事项
(1) 无符号 char 的转换
如果 char 是 unsigned char,其范围为 0~255,转换规则类似:
1 | unsigned char c = 200; // 无符号 char 的最大值为 255 |
(2) 精度问题
虽然 char 的范围较小(-128127 或 0255),但 double 的精度足够表示这些整数,因此不会出现精度损失。但如果 char 的值通过复杂计算得到,需注意浮点数的舍入误差:
1 | double a = 0.1; |
(3) 避免直接比较
由于浮点数的精度问题,不建议直接用 == 比较 char 和 double 的值:
1 | char c = 'A'; // 65 |
但注意:如果 d 是通过计算得到的近似值(如 d = 65.000001),比较结果可能为假。
4. 显式类型转换
为了代码的清晰性,可以显式转换 char 为 double:
1 | char c = 'B'; // ASCII码值为 66 |
总结
虽然说这种玩法好玩,但实际开发中,应该避免这种做法。,因为要考虑到精度,还有遵循隐式类型转换规则,其实也是个很麻烦的东西。
需要注意的是,没有字符串变量,用字符数组存放一整串的那种
- 标题: 第二章——C程序设计的初步知识 第三节——C语言基本数据类型及其定义规则
- 作者: 亓翎_Re-Tikara
- 创建于 : 2026-02-07 02:21:28
- 更新于 : 2026-02-10 02:48:46
- 链接: https://re-tikara.fun/Blog/posts/fcadce25/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。