import{_ as s,c as i,o as a,a5 as n}from"./chunks/framework.BE8if9e6.js";const l="/c/assets/1.L8V3GBrc.png",p="/c/assets/2.BkF1yWLn.png",h="/c/assets/3.CceY8r_n.png",t="/c/assets/4.DHaUgOwj.png",e="/c/assets/5.CXGaq_zh.png",k="/c/assets/6.BrZYAEEl.png",m=JSON.parse('{"title":"第一章:数据类型(⭐)","description":"","frontmatter":{},"headers":[],"relativePath":"notes/01_c-basic/03_xdx/index.md","filePath":"notes/01_c-basic/03_xdx/index.md","lastUpdated":1721208111000}'),r={name:"notes/01_c-basic/03_xdx/index.md"},d=n('
根据变量
中存储
的值
的不同
,我们可以将变量
分为两类:
普通变量
:变量所对应的内存中存储的是普通值
。指针变量
:变量所对应的内存中存储的是另一个变量的地址
。如下图所示:
NOTE
普通变量和指针变量的相同点:
普通变量和指针变量的不同点:
NOTE
普通变量
中存储
的值
的类型不同,可以将普通变量类型
划分为基本数据类型
(整型、字符类型、浮点类型、布尔类型)和复合数据类型
(数组类型、结构体类型、共用体类型、枚举类型)。指针变量
所指向空间
中存储
的值
的类型不同,可以将指针类型
分为基本数据类型指针
、复合数据类型指针
、函数指针
、数组指针
等,例如:如果指针所指向的空间保存的是 int 类型,那么该指针就是 int 类型的指针。内存空间
大小的不同,可以将整数类型划分为:类型 | 存储空间(内存空间) | 取值范围 |
---|---|---|
unsigned short (无符号短整型) | 2 字节 | -32,768 (- 2^15) ~ 32,767 (2^15 -1) |
[signed] short(有符号短整型,默认) | 2 字节 | 0 ~ 65,535 (2^16 - 1) |
类型 | 存储空间(内存空间) | 取值范围 |
---|---|---|
unsigned int(无符号整型) | 4 字节(通常) | -2147483648(- 2^31) ~ 2147483647 (2^31-1) |
[signed] int(有符号整型,默认) | 4 字节(通常) | 0 ~ 4294967295 (0 ~2^32 -1) |
类型 | 存储空间(内存空间) | 取值范围 |
---|---|---|
unsigned long(无符号长整型) | 4 字节(通常) | - 2^31 ~ 2^31-1 |
[signed] long(有符号长整型,默认) | 4 字节(通常) | 0 ~2^31 -1 |
类型 | 存储空间(内存空间) | 取值范围 |
---|---|---|
unsigned long long(无符号长整型) | 8 字节(通常) | - 2^63 ~ 2^63-1 |
[signed] long long(有符号长整型,默认) | 8 字节(通常) | 0 ~2^34 -1 |
NOTE
sizeof(short int) ≤ sizeof(int) ≤ sizeof(long int) ≤ sizeof(long long)
,具体的存储空间由编译系统自行决定;其中,sizeof 是测量类型或变量、常量长度的运算符。最常用整型
就是 int
类型了,如果取值范围不够,就使用 long 或 long long 。格式占位符
非常多,只需要大致了解即可;因为,我们在实际开发中,一般都会使用 C++ 或 Rust 以及其它的高级编程语言,如:Java 等,早已经解决了需要通过格式占位符
来输入和输出变量。unsigned short x = 10 ; // 无符号短整型
short x = -10; // 有符号短整型
NOTE
printf
中无符号短整型(unsigned short)
的格式占位符
是 %hu
,有符号短整型(signed short)
的格式占位符
是 %hd
。sizeof
运算符获取无符号短整型(unsigned short)
和 有符号短整型(signed short)
的存储空间(所占内存空间)
。#include <limits.h>
来获取 无符号短整型(unsigned short)
和有符号短整型(signed short)
的取值范围
。#include <stdio.h>
int main() {
// 定义有符号 short 类型
signed short s1 = -100;
printf("s1 = %hd \\n", s1); // s1 = -100
// 定义无符号 short 类型
unsigned short s2 = 100;
printf("s2 = %hu \\n", s2); // s2 = 100
// 定义 short 类型,默认是有符号
short s3 = -200;
printf("s3 = %hd \\n", s3); // s3 = -200
return 0;
}
#include <stdio.h>
int main() {
size_t s1 = sizeof(unsigned short);
printf("unsigned short 的存储空间是 %zu 字节 \\n", s1); // 2
size_t s2 = sizeof(signed short);
printf("signed short 的存储空间是 %zu 字节 \\n", s2); // 2
size_t s3 = sizeof(short);
printf("short 的存储空间是 %zu 字节 \\n", s3); // 2
return 0;
}
#include <limits.h>
#include <stdio.h>
int main() {
printf("unsigned short 类型的范围是[0,%hu]\\n", USHRT_MAX); // [0,65535]
printf("short 类型的范围是[%hd,%hd]\\n", SHRT_MIN,SHRT_MAX); // [-32768,32767]
return 0;
}
unsigned int x = 10 ; // 无符号整型
int x = -10; // 有符号整型
NOTE
printf
中无符号整型(unsigned int)
的格式占位符
是 %u
,有符号整型(signed int)
的格式占位符
是 %d
。sizeof
运算符获取无符号整型(unsigned int)
和 有符号整型(signed int)
的存储空间(所占内存空间)
。#include <limits.h>
来获取 无符号整型(unsigned int)
和有符号整型(signed int)
的取值范围
。#include <stdio.h>
int main() {
// 定义有符号 int 类型
signed int i1 = -100;
printf("i1 = %d \\n", i1); // i1 = -100
// 定义无符号 int 类型
unsigned int i2 = 100;
printf("i2 = %u \\n", i2); // i2 = 100
// 定义 int 类型,默认是有符号
short i3 = -200;
printf("i3 = %d \\n", i3); // i3 = -200
return 0;
}
#include <stdio.h>
int main() {
size_t i1 = sizeof(unsigned int);
printf("unsigned int 的存储空间是 %zu 字节 \\n", i1); // 4
size_t i2 = sizeof(signed int);
printf("signed int 的存储空间是 %zu 字节 \\n", i2); // 4
size_t i3 = sizeof(int);
printf("int 的存储空间是 %zu 字节 \\n", i3); // 4
return 0;
}
#include <limits.h>
#include <stdio.h>
int main() {
printf("unsigned int 类型的范围是[0,%u]\\n", UINT_MAX); // [0,4294967295]
printf("int 类型的范围是[%d,%d]\\n", INT_MIN,INT_MAX); // [-2147483648,2147483647]
return 0;
}
unsigned long x = 10 ; // 无符号长整型
long x = -10; // 有符号长整型
NOTE
printf
中无符号长整型(unsigned long)
的格式占位符
是 %lu
,有符号长整型(signed long)
的格式占位符
是 %ld
。sizeof
运算符获取无符号长整型(unsigned long)
和 有符号长整型(signed long)
的存储空间(所占内存空间)
。#include <limits.h>
来获取 无符号长整型(unsigned long)
和有符号长整型(signed long)
的取值范围
。#include <stdio.h>
int main() {
// 定义有符号 long 类型
signed long l1 = -100;
printf("l1 = %ld \\n", l1); // l1 = -100
// 定义无符号 long 类型
unsigned long l2 = 100;
printf("l2 = %lu \\n", l2); // l2 = 100
// 定义 long 类型,默认是有符号
long l3 = -200;
printf("l3 = %ld \\n", l3); // l3 = -200
return 0;
}
#include <stdio.h>
int main() {
size_t l1 = sizeof(unsigned long);
printf("unsigned long 的存储空间是 %zu 字节 \\n", l1); // 4
size_t l2 = sizeof(signed long);
printf("signed long 的存储空间是 %zu 字节 \\n", l2); // 4
size_t l3 = sizeof(long);
printf("long 的存储空间是 %zu 字节 \\n", l3); // 4
return 0;
}
#include <limits.h>
#include <stdio.h>
int main() {
printf("unsigned long 类型的范围是[0,%lu]\\n", ULONG_MAX); // [0,4294967295]
printf("long 类型的范围是[%ld,%ld]\\n", LONG_MIN,LONG_MAX); // [-2147483648,2147483647]
return 0;
}
unsigned long long x = 10 ; // 无符号长长整型
long long x = -10; // 有符号长长整型
NOTE
printf
中无符号长长整型(unsigned long long)
的格式占位符
是 %llu
,有符号长长整型(signed long long)
的格式占位符
是 %lld
。sizeof
运算符获取无符号长长整型(unsigned long long)
和 有符号长长整型(signed long long)
的存储空间(所占内存空间)
。#include <limits.h>
来获取 无符号长长整型(unsigned long long)
和有符号长长整型(signed long long)
的取值范围
。#include <stdio.h>
int main() {
// 定义有符号 long long 类型
signed long long ll1 = -100;
printf("ll1 = %lld \\n", ll1); // ll1 = -100
// 定义无符号 long long 类型
unsigned long long ll2 = 100;
printf("ll2 = %llu \\n", ll2); // ll2 = 100
// 定义 long long 类型,默认是有符号
long long ll3 = -200;
printf("ll3 = %lld \\n", ll3); // ll3 = -200
return 0;
}
#include <stdio.h>
int main() {
size_t ll1 = sizeof(unsigned long long);
printf("unsigned long long 的存储空间是 %zu 字节 \\n", ll1); // 8
size_t ll2 = sizeof(signed long long);
printf("signed long long 的存储空间是 %zu 字节 \\n", ll2); // 8
size_t ll3 = sizeof(long long);
printf("long long 的存储空间是 %zu 字节 \\n", ll3); // 8
return 0;
}
#include <limits.h>
#include <stdio.h>
int main() {
printf("unsigned long long 类型的范围是[0,%llu]\\n", ULLONG_MAX); // [0,18446744073709551615]
printf("long long 类型的范围是[%lld,%lld]\\n", LLONG_MIN,LLONG_MAX); // [-9223372036854775808,9223372036854775807]
return 0;
}
字面量
是源代码
中一个固定值
的表示方法
,用于直接表示数据,即:int num1 = 100; // 100 就是字面量
long num2 = 100L; // 100L 就是字面量
long long num3 = 100LL; // 100LL 就是字面量
NOTE
#include <stdio.h>
int main() {
int num = 100;
printf("num = %d\\n", num); // num = 100
long num2 = 100L;
printf("num2 = %ld\\n", num2); // num2 = 100
long long num3 = 100LL;
printf("num3 = %lld\\n", num3); // num3 = 100
unsigned int num4 = 100U;
printf("num4 = %u\\n", num4); // num4 = 100
unsigned long num5 = 100LU;
printf("num5 = %lu\\n", num5); // num5 = 100
unsigned long long num6 = 100ULL;
printf("num6 = %llu\\n", num6); // num6 = 100
return 0;
}
NOTE
<stdint.h>
中定义了一些新的类型别名,如下所示:类型名称 | 含义 |
---|---|
int8_t | 8 位有符号整数 |
int16_t | 16 位有符号整数 |
int32_t | 32 位有符号整数 |
int64_t | 64 位有符号整数 |
uint8_t | 8 位无符号整数 |
uint16_t | 16 位无符号整数 |
uint32_t | 32 位无符号整数 |
uint64_t64 | 64 位无符号整数 |
NOTE
上面的这些类型都是类型别名,编译器会指定它们指向的底层类型,如:在某个系统中,如果 int 类型是 32 位,那么 int32_t 就会指向 int ;如果 long 类型是 32 位,那么 int32_t 就会指向 long。
#include <stdio.h>
#include <stdint.h>
int main() {
// 变量 x32 声明为 int32_t 类型,可以保证是 32 位(4个字节)的宽度。
int32_t x32 = 45933945;
printf("x32 = %d \\n", x32); // x32 = 45933945
return 0;
}
sizeof(表达式)
NOTE
sizeof(...)
的返回值类型
是 size_t
。printf
中使用占位符 %zu
来处理 size_t
类型的值。#include <stdio.h>
#include <stddef.h>
int main() {
size_t s = sizeof(int);
printf("%zu \\n", s); // 4
return 0;
}
#include <stdio.h>
#include <stddef.h>
int main() {
int num = 10;
size_t s = sizeof(num);
printf("%zu \\n", s); // 4
return 0;
}
#include <stdio.h>
#include <stddef.h>
int main() {
size_t s = sizeof(10);
printf("%zu \\n", s); // 4
return 0;
}
所谓的数值溢出指的是:当超过一个数据类型能够存放的最大范围的时候,数值就会溢出。
在 C 语言中,整数
的数据类型
分为无符号
和有符号
的,其在底层表示和存储是不一样的,即:
NOTE
对于无符号的数值溢出:
那么,无符号的上溢出,原理就是这样的:
对于有符号的数值溢出:
那么,有符号的上溢出,原理就是这样的:
NOTE
在实际开发中,选择合适的数据类型,以避免数值溢出问题!!!
#include <limits.h>
#include <stdio.h>
int main() {
unsigned short s1 = USHRT_MAX + 1;
printf("无符号的上溢出 = %hu \\n", s1); // 0
unsigned short s2 = 0 - 1;
printf("无符号的下溢出 = %hu \\n", s2); // 65535
return 0;
}
#include <limits.h>
#include <stdio.h>
int main() {
short s1 = SHRT_MAX + 1;
printf("有符号的上溢出 = %hd \\n", s1); // -32768
short s2 = SHRT_MIN - 1;
printf("有符号的下溢出 = %hd \\n", s2); // 32767
return 0;
}