本文建议收藏,当作数据类型小百科使用
引言:
在计算机的世界里,内存是一片浩瀚无垠的荒原,而数据类型(Data Types),便是我们在这片荒原上建立的秩序。
C语言之所以强大,正因为它是直面内存的语言。当我们声明一个变量时,选择的不仅仅是一个名字,更是在向计算机申请一块特定大小、具有特定解读方式的“领地”。类型决定了比特流的命运:同样的32个比特,在 int眼中是整数,在 float眼中却是科学计数法,而在 void*眼中,它只是一串无意义的地址。这种解读方式的差异,正是程序逻辑复杂性与魅力的根源。
然而,权力越大,责任越重。数据类型也是一把双刃剑。它既是安全的护盾——通过边界检查防止越界;也是隐藏的陷阱——符号位的扩展、精度的丢失往往成为最难调试的Bug源头。理解数据类型,本质上是在理解“限制”与“表达”的平衡:在有限的字节内,如何精准地刻画现实世界的无限信息。
这不仅是语法的学习,更是编程思维的基石。让我们一同走进C语言的数据世界,学会与内存对话。

一、基本数据类型(内置类型)

类型关键字典型字节数取值范围示例说明
字符型​char1-128 ~ 127 或 0 ~ 255存储字符或小整数
整型​int4-2³¹ ~ 2³¹-1最常用的整数类型
短整型​short2-32768 ~ 32767节省内存的小整数
长整型​long4/8≥ int范围大整数
超长整型​long long8-2⁶³ ~ 2⁶³-1C99新增,更大整数
单精度浮点​float4±3.4e±38约6~7位有效数字
双精度浮点​double8±1.7e±308约15位有效数字
长双精度​long double8/16更大范围高精度浮点

注:字节数因编译器和系统而异(32/64位)。可用 sizeof()查看实际大小。

二、类型修饰符

可组合使用以扩展基本类型:

修饰符作用示例
signed有符号(默认)signed int a;
unsigned无符号(仅非负)unsigned int count;
short短长度short int x;
long长长度long double d;

三、派生数据类型

类型声明方式说明
数组​int arr[10];相同类型元素的集合
指针​int *p;存储地址的变量
结构体​struct { … };不同类型成员的集合
联合体​union { … };共享内存的不同类型
枚举​enum { RED, GREEN };命名整数常量

四、void 类型

1.函数返回空值:void func();
2.无类型指针:void *ptr;(可指向任意数据类型)
3.函数无参数:int func(void);

五、类型选择建议

场景推荐类型
计数(非负)unsigned int
循环索引size_t(无符号)
布尔标志_Bool/ bool
精确控制位uint8_t, uint32_t
金额计算int64_t(避免浮点误差)

六、printf常用格式控制符

  1. 基本类型
控制符类型示例输出
%d/ %iintprintf(“%d”, 10);10
%uunsigned intprintf(“%u”, 10);10
%ldlongprintf(“%ld”, 100L);100
%lldlong longprintf(“%lld”, 100LL);100
%ccharprintf(“%c”, ‘A’);A
%s字符串printf(“%s”, “Hi”);Hi
%ffloat/doubleprintf(“%f”, 3.14);3.140000
%lfdouble(C99)printf(“%lf”, 3.14);3.140000
%e/ %E科学计数法printf(“%e”, 123.4);1.234000e+02
%g/ %G自动选择 %f/%eprintf(“%g”, 123.4);123.4
%p指针地址printf(“%p”, &x);0x7ffd…
%x/ %X十六进制printf(“%x”, 255);ff
%o八进制printf(“%o”, 8);10
%%输出 %printf(“%%”);%

七、scanf常用格式控制符

控制符类型示例
%dint *scanf(“%d”, &a);
%ffloat *scanf(“%f”, &x);
%lfdouble *scanf(“%lf”, &y);
%cchar *scanf(“%c”, &ch);
%s字符串scanf(“%s”, str);
%uunsigned *scanf(“%u”, &n);
%x十六进制scanf(“%x”, &hex);

⚠️ 注意:scanf中:
%s遇到空格停止读取
数组名本身就是地址,不要加 &
建议使用 fgets替代 %s防溢出

八、修饰符(增强控制)

  1. 宽度控制
    printf(“%5d”, 12); // 输出:" 12"(右对齐)
    printf(“%-5d”, 12); // 输出:"12 "(左对齐)
  2. 精度控制
    printf(“%.2f”, 3.14159); // 输出:“3.14”
    printf(“%8.2f”, 3.14159); // 输出:" 3.14"
  3. 填充与对齐
    printf(“%05d”, 12); // 输出:“00012”
    printf(“%*d”, 5, 12); // 动态宽度(等价于 %5d)

九、printf vs scanf对照表

对比项printfscanf
主要作用​输出数据到标准输出输入数据从标准输入
函数原型​int printf(const char *fmt, …);int scanf(const char *fmt, …);
参数本质​值(变量的内容)地址(变量在内存中的位置)
是否使用 &​❌ 不需要✅ 除数组/指针外都需要
返回值​成功打印的字符数​成功读取并赋值的变量个数​
处理字符串​%s输出字符串%s读取字符串(遇空格结束)
空白字符处理​原样输出跳过空白(空格、换行、Tab)
缓冲区行为​通常行缓冲(遇到 \n刷新)输入前常清空输入缓冲区
安全性​较安全⚠️ 易溢出(尤其 %s)
常见错误​格式符与变量类型不匹配忘记加 &、缓冲区残留 \n

从混沌的内存荒原中划定疆域,我们终将明白:数据类型并非束缚思维的枷锁,而是抵御混乱的堤坝。每一个 int的选择、每一次 cast的权衡,都是在有限的比特中寻找确定的答案。愿你在未来的代码中,既能精准丈量每一寸内存的边界,也能在严谨的类型系统中,构建出无限可能的逻辑宇宙。

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐