03-数据类型
整型、浮点型、字符、字符串、布尔型、常量与变量的解析
文章目录
一、整型
int a = 0;
注意事项
在32位系统和64位系统中,整型(int)都占用4字节。
1.1 取值范围
通过命令行工具getconf
可以获取整型的最大值和最小值:
$ getconf INT_MAX
2147483647
$ getconf INT_MIN
-2147483648
1.2 整型的修饰符
short
:短整型,用于将整型的尺寸减少为原本的一半,减少内存开支,缩小取值范围。
long
:长整型,用于将整型的尺寸变大,增加内存开支,扩大取值范围。
long long
:长长整型,用于进一步增加整型的尺寸和取值范围。在64位系统中,long与long long的大小一致。
unsigned
:无符号整型,用于去掉符号位,使得整型数据没有负数,扩展正整数的取值范围(0到4294967295)。
1.3 整型数据的符号位
整型数据在二进制存储时,最高位(第31位)表示符号位:
如果符号位为1,则表示负数。
如果符号位为0,则表示正数。
1.4 整数的存储方式
1.4.1 原码
正整数是直接使用原码进行存储的。原码是指整数的绝对值的二进制表示。
例如,整数100的原码表示如下:
100 --> 0000 0000 0000 0000 0000 0000 0110 0100
1.4.2 补码
负数使用补码来存储。补码的计算方法是:取该数的原码的绝对值,取反加1。
符号位(最高位)不变。
例如,-100的补码表示如下:
- 计算100的二进制原码:
(注意其实是-100的原码,符号位带上了为1)
100 --> 1000 0000 0000 0000 0000 0000 0110 0100
- 取反(符号位保持不变):
取反-> 1111 1111 1111 1111 1111 1111 1001 1011
- 加1:
加1 -> 1111 1111 1111 1111 1111 1111 1001 1100
所以,-100的补码表示为:
1111 1111 1111 1111 1111 1111 1001 1100
1.4.3 溢出
当整数运算的结果超过其取值范围时,会发生溢出。溢出后的结果会变成相邻的最小值或最大值。
例如,对于32位有符号整数(int
):
- 最大值是2147483647(
0111 1111 1111 1111 1111 1111 1111 1111
) - 最小值是-2147483648(
1000 0000 0000 0000 0000 0000 0000 0000
)
如果将最大值加1,则会溢出为最小值:
2147483647 + 1 = -2147483648
1.4.4 示例
以下示例代码演示了正整数和负整数的存储方式及溢出情况:
#include <stdio.h>
#include <limits.h>
int main() {
int positive = 100;
int negative = -100;
printf("正整数 %d 的二进制表示(原码):%x\n", positive, positive);
printf("负整数 %d 的二进制表示(补码):%x\n", negative, negative);
// 演示溢出
int max_int = INT_MAX;
int min_int = INT_MIN;
printf("最大整型值: %d\n", max_int);
printf("最小整型值: %d\n", min_int);
printf("最大整型值加1(溢出):%d\n", max_int + 1);
printf("最小整型值减1(溢出):%d\n", min_int - 1);
return 0;
}
输出结果
正整数 100 的二进制表示(原码):64
负整数 -100 的二进制表示(补码):ffffff9c
最大整型值: 2147483647
最小整型值: -2147483648
最大整型值加1(溢出):-2147483648
最小整型值减1(溢出):2147483647
二、浮点型(实型)
概念:浮点型用于表达一个实数的数据类型。
2.1 分类
- 单精度浮点型(
float
)- 典型尺寸:4字节
- 双精度浮点型(
double
)- 典型尺寸:8字节
- 长双精度浮点型(
long double
)- 典型尺寸:16字节
占用的内存越多,则精度越高。但是注意是经典尺寸,在不同系统中可能不同。
2.2 浮点数的存储
IEEE 754浮点数标准采用如下形式来表示一个浮点数:
- 单精度浮点数(32位)
- 符号位(S):1位
- 指数位(E):8位
- 尾数位(M):23位
-
双精度浮点数(64位)
- 符号位(S):1位
- 指数位(E):11位
- 尾数位(M):52位
-
长双精度浮点数(128位)
- 符号位(S):1位
- 指数位(E):15位
- 尾数位(M):112位
2.3 示例代码
以下代码展示了如何声明和打印浮点数,以及如何用不同的解析方式查看存储的二进制值:
#include <stdio.h>
int main() {
float f = 3.14;
double d = 3.14;
long double ld = 3.14;
// 输出浮点数
printf("float f: %f\n", f);
printf("double d: %lf\n", d);
printf("long double ld: %Lf\n", ld);
// 使用整型方式查看浮点数存储的二进制值
printf("float f (as int): %d\n", *(int*)&f);
printf("double d (as int): %lld\n", *(long long*)&d);
printf("long double ld (as int): %lld\n", *(long long*)&ld); // 这只是部分显示
return 0;
}
注意事项:
- 当使用
printf
函数输出浮点数时,需要使用对应的格式化标识符:float
用%f
double
用%lf
long double
用%Lf
- 当直接使用整型方式查看浮点数的存储值时,可以将浮点数的地址转换为整型指针,然后解引用该指针。这样可以直接看到存储的二进制值(以整型形式展示)。
输出结果:
float f: 3.140000
double d: 3.140000
long double ld: 3.140000
float f (as int): 1078523331
double d (as int): 4614253070214989087
long double ld (as int): 4614253070214989087
三、字符
概念:字符类型(char
)用于存储单个字符的数据类型。
3.1 字符的详细解释
-
声明和初始化字符变量
char c = 'K';
- 申请一片内存并命名为
c
- 确定内存的大小为
char
(1字节) - 把字符
'K'
的ASCII码值(75)转换为二进制,并存储到该内存中
- 申请一片内存并命名为
-
打印字符及其ASCII码值
printf("字符:%c\n", c); printf("整型ASCII值:%d\n", c);
printf("%c", c)
:以字符的形式来解析内存c
的内容,得到字符'K'
printf("%d", c)
:以十进制整型来解析内存c
的内容,得到字符'K'
对应的ASCII值75
-
字符类型支持整型操作
char k = 'H'; printf("%c\n", k + 1); printf("%c\n", k - 1);
char k = 'H'
:字符'H'
的ASCII值是72printf("%c", k + 1)
:'H'
的ASCII值加1得到73,对应字符'I'
printf("%c", k - 1)
:'H'
的ASCII值减1得到71,对应字符'G'
3.2 示例代码及解释
#include <stdio.h>
int main() {
// 声明并初始化字符变量
char c = 'K';
// 申请一片内存并且命名为c
// 确定内存的大小为char(1字节)
// 把字符‘K’的ASCII码值转换为二进制,并存储到该内存中
// 打印字符及其ASCII码值
printf("字符:%c\n", c); // 以字符的形式来解析内存c的内容,得到字符'K'
printf("整型ASCII值:%d\n", c); // 以十进制整型来解析内存c的内容,得到'K'对应的ASCII值
// 声明并初始化另一个字符变量
char c1 = '1';
// 打印字符及其ASCII码值
printf("字符:%c\n", c1); // 以字符的形式来解析内存c1的内容,得到字符'1'
printf("整型ASCII值:%d\n", c1); // 以十进制整型来解析内存c1的内容,得到'1'对应的ASCII值
// 字符类型支持整型操作
char k = 'H';
printf("字符加一:%c\n", k + 1); // 'H'的ASCII值是72,加1后得到73,对应字符'I'
printf("字符减一:%c\n", k - 1); // 'H'的ASCII值是72,减1后得到71,对应字符'G'
return 0;
}
注意事项:
- 在计算机中,所有数据都是以二进制形式存储的。因此,字符必须映射到某个数字才能被存放到计算机中。这个映射表称为ASCII表,可以使用
man ascii
命令查看。 - 字符实质上是一个单字节的整型,因此支持所有整型的操作。
四、字符串
字符串在C语言中的表示有两种形式:数组和指针。
4.1 形式一:数组(可读、可写)
char s1[] = "Hello";使用一个数组来存放字符串 "Hello"
- 使用一个数组来存放字符串 “Hello”。
- 实际上是把字符串常量 “Hello” 复制到数组
s1
所代表的内存中。
示例代码:
#include <stdio.h>
int main() {
char s1[] = "Hello";
// 修改数组中的字符
s1[0] = 'h';
printf("%s\n", s1); // 输出 "hello"
return 0;
}
4.2 形式二:指针(只读)
char *s2 = "Even"; // 使用一个指针来指向常量字符串
- 使用一个指针来指向字符串常量 “Even”。
- 字符串常量存储在只读存储区,因此通过指针
s2
访问的字符串是只读的,不能修改。
示例代码:
#include <stdio.h>
int main() {
char *s2 = "Even";
// 尝试修改指针指向的字符串内容会导致未定义行为
// s2[0] = 'e'; // 这行代码会导致运行时错误
printf("%s\n", s2); // 输出 "Even"
return 0;
}
4.3 综合示例代码
#include <stdio.h>
int main() {
char s1[] = "Hello";
char *s2 = "Even";
// 修改数组中的字符
s1[0] = 'h';
// 打印字符串
printf("%s %s\n", s1, s2); // 输出 "hello Even"
return 0;
}
解释
- 字符串数组:
char s1[] = "Hello";
- 数组的内存是可读可写的,可以修改字符串内容。
- 示例中,
s1[0] = 'h';
将 “Hello” 修改为 “hello”。
- 字符串指针:
char *s2 = "Even";
- 指针指向字符串常量,存储在只读内存区。
- 尝试修改
s2
指向的内容(如s2[0] = 'e';
)会导致运行时错误。
输出结果
hello Even
五、布尔型
概念:布尔类型用于表示真/假(非零则为真)。
- 真:
true
- 假:
false
在使用布尔类型时需要包含头文件<stdbool.h>
。
5.1 详细解释
-
布尔变量声明和初始化
bool a = 1; // 真 bool b = 0; // 假 bool c = true; // 真 bool d = false; // 假
bool
类型的变量可以使用整数或布尔常量进行初始化。1
和true
表示真,0
和false
表示假。
-
打印布尔值
printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", c); printf("d: %d\n", d);
- 布尔值在输出时显示为整数,
true
为1
,false
为0
。
- 布尔值在输出时显示为整数,
-
打印布尔类型和变量的大小
printf("sizeof(bool): %ld\n", sizeof(bool)); // 布尔类型的大小 printf("sizeof(a): %ld\n", sizeof(a)); // 变量a的大小 printf("sizeof(true): %ld\n", sizeof(true)); // 常量true的大小 printf("sizeof(false): %ld\n", sizeof(false)); // 常量false的大小
- 在C语言中,
bool
类型的大小为1字节。 - 变量
a
的大小也是1字节。 - 常量
true
和false
在C语言中的大小为4字节,因为它们被视为int
常量。
- 在C语言中,
-
打印布尔常量的整数值
printf("false: %d\n", false); // 0 printf("true: %d\n", true); // 1
false
的整数值为0
。true
的整数值为1
。
示例代码
#include <stdio.h>
#include <stdbool.h>
int main() {
bool a = 1; // 真
bool b = 0; // 假
bool c = true; // 真
bool d = false; // 假
// 打印布尔值及其大小
printf("a: %d\n", a);
printf("b: %d\n", b);
printf("c: %d\n", c);
printf("d: %d\n", d);
printf("sizeof(bool): %ld\n", sizeof(bool)); // 布尔类型的大小
printf("sizeof(a): %ld\n", sizeof(a)); // 变量a的大小
printf("sizeof(true): %ld\n", sizeof(true)); // 常量true的大小
printf("sizeof(false): %ld\n", sizeof(false)); // 常量false的大小
printf("false: %d\n", false); // 打印false的整数值
printf("true: %d\n", true); // 打印true的整数值
return 0;
}
运行结果:
a: 1
b: 0
c: 1
d: 0
sizeof(bool): 1
sizeof(a): 1
sizeof(true): 4
sizeof(false): 4
false: 0
true: 1
六、 常量与变量
概念:
- 常量:不可以被改变的内存。
- 变量:可以被改变的内存。
6.1 示例代码
#include <stdio.h>
int main() {
int a = 100; // a是一个变量,而100是常量
float f = 3.1415; // f是一个变量,而3.1415是常量
char s1[] = "abcdefg"; // s1是一个变量,而"abcdefg"是常量(字符串常量)
printf("a: %d\n", a);
printf("f: %f\n", f);
printf("s1: %s\n", s1);
return 0;
}
练习