
数据类型为什么要学数据类型在C语言中不同类型的数字如整数小数字符等在内存中占用的空间大小和存储方式是不同的。数据类型就是固定数字大小内存它告诉编译器这块存什么占多大内存同时还决定了怎么存。简单来说就是数据类型决定了数据在内存中如何存储和需要多大空间存储数据类型的分类基本类型内置类型整型数值类型存储整数短整型shortshort int的表示2个字节基本型int使用频率最高4个字节长整型longlong int的表示32位系统4字节64位系统8字节长长整型long longlong long intC99新增标准不常用浮点型数值类型存储小数/实数单精度型float4个字节双精度型double8个字节长双精度型long double不常用字符型char存储单个字符本质是ASCII码值1个字节构造类型用户基于C语言语法定义指针类型存储内存地址空类型void表示无类型用于函数返回值函数形参指针类型举例main(void)等价于main()数据类型在内存中的大小常用数据类型名称大小单位字节取值范围short短整型2-32768 ~ 32767int基本整型4-2147483648 ~ 2147483647long长整型4在32位系统中/8在64位系统中32位同int/64位-9223372036854775808~ 9223372036854775807float单精度型4约 ±3.4×10³⁸精度 6~7 位有效数字dounle双精度型8约 ±1.7×10³⁰⁸精度 15~16 位有效数字char字符型1-128 ~ 127有符号/ 0 ~ 255无符号备注计算机存储最小单位是bit(位)1个bit仅能存储0或1程序中最小操作单位是Byte字节1字节 8位C语言中没有Byte这个单位我们使用char表示字节。也就是1 char 8 bit。sizeof 运算符的使用基本语法sizeof(数据类型) 或者 sizeof(变量名)示例代码#include stdio.h int main(int argc,char *argv[]) { printf(int的大小%ld字节\n, sizeof(int)); printf(double的大小%ld字节\n, sizeof(double)); return 0; } //运行结果 int的大小4字节 double的大小8字节备注sizeof是运算符用来计算数据类型或者变量的大小返回的是字节数。常量常量是程序执行过程中值不可改变的量与变量一样需要用到内存空间存储。整型常量表现形式分类组成注意事项示例十进制常量数字0~9不能以0开头992180八进制常量数字0~7不能表示小数02307700十六进制常量数字0~9 字母a/A~f/F不能表示小数以0x/0X为前缀0xFFFFFF、0X123、0x0/0x00000000后缀说明长整型常量在数值后加L/l推荐用L示例long num 123L明确指定为长整型此时的L只起到一个标识作用数值依然是123有符号和无符号分类功能说明示例代码有符号默认表示范围为负数 0 正数signed int a 10086等价于int a 10086无符号表示范围0 正数内存中负数位用来存储正数正数范围更大unsigned char num 100浮点型常量浮点型常量小数/实数有两种表示方式方式组成示例注意事项十进制小数形式数字0~9小数点.必须包含小数点0.123(double默认) /0.123F(float)、-12.6、3.0、0.0float类型常量需要在末尾添加F/f默认浮点型常量为double类型。指数形式科学计数法数字 e/E 整数指数e/E表示10的幂次。正数1234.5 → 1.2345*10^3 → 1.2345e3 或 1.2345e3 十进制小数形式 → 指数形式 负数0.012 → 1.2 * 10^{-2} → 1.2e-2十进制小数形式 → 指数形式e/E前面必须有数字0~9其中小数点前的整数部分取值范围为1~9前导零0在数值上无意义但C语法允许e/E后面必须是整数不能带小数错误示例1.2345e3.5单精度常量需要加f/F如1.2345e3F(float)、1.2345e3(double默认)字符型常量普通字符串常量格式用单引号括起来的单个字符。英文输入法下的字母数字符号等示例正确示例如a,A,4,_,,\n错误示例如软,a本质硬件存储的是ASCII规范的字符的ASCII码值如a的ASCII码值为97A的ASCII码值为65转义字符常量以反斜杠\开头的特殊的字符序列用于表示控制字符或不可见字符如换行符、制表符常见转义符如下字符形式ASCII码中文解释用途\n10换行光标移动至下一行开头\r13回车光标移动至当前行开头\00空字符字符串结束标志重要\t9水平制表符相当于按Tab键8个空格\\92反斜杠表示字符\\39单引号表示字符\34双引号表示字符ASCll码表字符串常量基本概念定义用双引号括起来的字符序列可包含多个字符、数字、符号,C语言无内置的字符串类型字符串常量和变量均需要通过字符数组或者字符指针来实现。字符串常量末尾自动添加\0结束标记但是这个标志是看不见的也不会显示输出。输出通过printf函数的%s格式输出。示例代码hello world // 实际存储hello world\0 123 // 实际存储123\0 12.25 // 实际存储12.25\0 // 实际存储\0 //输出 printf(hello world!\n); // 推荐内部补充%s // 等价于 printf(%s, hello world!\n);与字符常量的区别对比项字符常量如a字符串常量如a定界符单引号双引号内存占用1字节存储ASCII码2字节a \0结束标志无自动添加\0字符串结束标志表示范围仅单个字符可多个字符或空备注关键字符串常量末尾会被系统自动添加\0用于标识字符串结束这是字符串与字符常量的核心区别。符合常量无参数宏定义定义通过预处理指令#define定义的标识符用于代表一个固定常量预处理阶段会直接替换成宏值优点增强代码的可读性用有意义的标识符代替魔法数字提升代码的可维护性需修改常量时仅需要修改宏定义无需逐个修改代码语法格式#define 宏名称 宏值注意事项① 宏名称与宏值之间用空格隔开② 行末不能加;否则替换是会带入分号导致语法错误③ 宏名称命名规范字母A~Za~z 数字0~9 下划线_不能以数字开头。习惯上宏名使用全大写如MAX_VALUE小写字母也合法但较少用于宏如max_value示例代码#include stdio.h //宏定义PI #define PI 3.1415926 int main(int argc,char *argv[]) { // 实现一个圆的面积计算 // 创建一个变量用来存放圆的半径 double r10; // 计算圆的面积 double areaPI*r*r; printf(面积%f\n,area); // 计算圆的周长 double l 2 * PI * r; printf(周长%f\n, l); return 0; } //运行结果 /20260728$ gcc demo01.c /20260728$ ./a.out 面积314.159260 周长62.831852变量概念定义在程序运行中可变的量称为变量。变量对应内存一块特有的存储单元用于存放数据变量必须有唯一名称通过变量名可访问对于内存单元备注局部变量默认在栈内存全局变量和静态变量存储在数据段。基本语法数据类型 变量名列表;变量定义与使用示例代码 #include stdio.h int main(int argc,char *argv[]) { //声明变量并初始化 int a 10; //注意 赋值运算符意思是将右边的常量21赋值给左边的变量age赋值顺序自右向左 printf(a%d\n,a);//输出结果a10%d 的意思是将数据 a 按照10进制 int 输出 a 15;//将常量15赋值给变量a printf(a%d\n,a);//输出结果a15%d 的意思是将数据 a 按照10进制 int 输出 int b 1,c ;//如果一个局部变量函数中定义的变量未赋值此时系统就会默认一个随机值无意义 printf(b%d,c%d\n,b,c);//输出结果b1c随机值无意义 return 0; } 运行结果 /20260730$ ./a.out a10 a15 b1,c25071 /20260730$ ./a.out a10 a15 b1,c23204命令规范组成规则以字母a~z/A~Z或者_开头仅包含字母数字和下划线。禁止规则不能出现中文不能与关键字或系统标识符重名。如if,int,printf等备注变量名变量值数据变量地址变量空间之间的关系标识符定义用来表示程序中对象名称的有效字符序列对象包括变量常量函数数组构造类型等标识符就是这些对象的名字。构成规则以字母a~z/A~Z或者下划线_开头命名中仅包含字母数字和下划线。编译系统中区分大小写命名约定程序员之间的约定非强求变量名、函数名C风格小写字母 下划线例如set_count推荐写法STM32风格大小写字母下划线例如Set_CountJava风格小驼峰命名法首单词字母小写后续单词首字母大写例如setCount常量名、枚举名大写字母 下划线例如SET_COUNT标识符的分类关键字是系统赋予的特定含义和用途不可用作自定义标识符。共32个auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while系统预定义的标识符是系统提供的标识符如标准库提供的函数名sinprintfscanf预处理指令#include#define等C语言常用预处理指令共12个使用是需要加#前缀#define #endif #elif #error #line #include #ifdef #ifndef #pragma #undef #if #else用户标识符是用户自定义的标识符用于给变量、自定义函数、符号常量、数组、构造类型、文件等命名。变量使用的注意事项同类型变量的两种定义方式方式1同一类型定义多个变量优点简洁明了缺点可读性差变量较多时不易区分int a, b, c; int a1 1, b1 2, c1 3;方式2同类型变量分开定义优点可读性高便于单独注释变量含义缺点繁琐int a; int b; int c; int a1 1; int b1 2; int c1 3;未初始化变量特性同类型说明语句仅为变量分配内存空间如果没有赋值则存储单元中的值是内存随机值由当前内存决定#include stdio.h int main(int argc,char *argv[]) { int a, b, c; printf(%d,%d,%d,a,b,c); return 0; } 运行结果每次运行结果都不确定是随机值 /20260730$ ./a.out 0,-1016356768,25388 /20260730$ ./a.out 0,-1036971936,24091备注总之一句话不要使用随机值因为随机值无意义。变量初始化与类型转换C语言允许定义变量时直接赋初值避免访问随机值随机值无意义推荐长整型long变量赋值时若赋值数据为int型常量编译器会自动将其转换成long型即发生了隐式转换示例代码// 将long类型的常量12赋值给long类型的变量a符号左右两边类型一致无需转换 long a 12L; // 将int类型的常量12赋值给long类型的变量b符号左右两边类型不一致此时触发隐式转换 long b 12;图片unsigned short a 12; // unsigned 表示无符号业绩还是只能存储0和正数 unsigned int b a; // 左侧是int右侧是short此时触发隐式转换 // 转换规则 // ① 系统会自动申请一块跟a一样大的临时内存 // ② 将a的值拷贝到这块临时内存 // ③ 将临时空间的数据赋值给a赋值的时候左侧是int右侧也是int(临时内存)整型变量的存储范围整型变量的存储范围由所占字节数和符号属性决定示例unsigned char a(1字节)存储范围0~255char b / signed char b(1字节)存储范围-128~127。数据类型的深入整型数据深入整型变量的定义与内存查询定义定义一个整型变量时编译器会分配一个对应大小的内存空间变量名作为该内存的标识通过查询变量名来访问对应空间中的数据。内存查询如果不确定编译器分配的内存大小可以通过运算符sizeof查询它的返回值类型为字节size_t。整型数据在内存中存储形式存储的本质在系统中数据最终以二进制的补码进行存储。示例定义short i 10short占2字节默认有符号十进制10的二进制原码为1010因为short占2字节16位高位补0内存存储的补码形式为图片补码的使用是为了统一加法运算使CPU可通过一套加法电路简化硬件设计处理所有整数运算同时消除了0和—0歧义只保留了一个0。关键概念程序中的数据转换为二进制后默认是原码形式。正数的原码、反码、补码完全相同三码一致。负数的补码计算先取该负数的绝对值的原码 → 按位取反得到反码→ 加1得到补码原码与补码之间的转换关系内存数据的读写流程① 存数据正数直接以补码存储负数需经过原码 → (按位取反) → 反码 → (1) → 补码转换后存储。② 取数据正数补码直接还原为原码负数需经过补码 → (-1) → 反码 → (按位取反) → 原码后还原八进制 / 十进制 / 十六进制示例代码#include stdio.h int main(int argc,char *argv[]) { //有符号整型 a,b,c的赋值可存放正数0负数 int a 3, b -24, c ; //无符号整型 u,v的赋值仅可存正数和0不能存放负数 unsigned short u -12, v -3; //将a,b,u的数据取出来相加然后结果赋值给c c a b u; printf(c%d\n,c); printf(u%u v%u\n,u,v); return 0; } 运行结果 /20260731$ ./a.out c65503 u65524 v65533浮点型数据的深入浮点型变量的定义与分类定义用于存储实数也就是小数的数据类型。分类类型字节数64位系统中精度有效数字格式化符合功能说明float4字节6~7 位%f需在常量后加F/f例12.25fdouble8字节15~16 位%lf或%fprintf 通用默认浮点型常量为double例12.5long double16字节18~19 位%Lf精度最高兼容性依赖编译器备注占用内存越大精度越高能表示的数值范围也越广。示例代码float f1 12.25f; // 左右两边类型一致float直接赋值 double f2 12.5; // 左右两边类型一致double直接赋值 long double f3 3.1415926L; // 表示长双精度的常量浮点型数据在内存中的存储形式IEEE 754标准浮点型数据按照IEEE 754标准以二进制指数显示存储系统将浮点型数据拆分为三部分分别存放符号位表示正负0-正1-负指数位存储指数值需加偏移量避免负指数尾数位存储尾数部分隐含整数部分为1节省存储空间IEEE 754标准相关参数类别字节数符号位指数位范围尾数位长度指数偏移量单精度型-float41位[31]8位[30~23]23位[22~0]127双精度型-double81位[63]11位[62~52]52位[51~0]1023float内存示意图案例需求分析单精度浮点型数27.5f内存存储二进制形式。解析步骤转换为二进制27.5的二进制为11011.1整数部分27→11011小数部分0.5→1标准化指数形式11011.1 1.10111×2^4小数点左移4位指数为4尾数为10111计算指数位指数(4) 偏移量(127) 131转换为8为二进制1000 0011处理尾数位尾数部分为10111(隐含了整数部分的1)补0 →1011 1000 0000 0000 0000 000组合结果符号位(0-正)指数位(1000 0011)尾数位(1011 1000 0000 0000 0000 000)最终存储以二进制形式科学计数法指数形式规则C语言中浮点数的两种表达形式十进制形式需包含整数部分和小数部分至少其一。例如10.03.14.14等指数形式科学计数法用e或E表示 10 的幂次规则如下e/E前面必须有数字例3.14e3合法e3非法e/E后面必须是整数可正可负例3.1e-2合法3.1e5.6非法示例-3.14E-2等价于 -3.14×10^{-2}、2E-3等价于 2×10^{-3}、0.3E4等价于 0.3×10^4。字符型数据深入概念定义字符型变量用于存储单个字符常量。根据ASCII字符集语法格式char 变量列表示例代码 #include stdio.h int main(int argc,char *argv[]) { char a1,a2; a1 a; a2 65; printf(a1%c,a2%c\n,a1,a2); printf(a1%d,a2%d\n,a1,a2); return 0; } 运行结果 /20260801$ ./a.out a1a,a2A a197,a265说明字符变量仅能存放单个字符ASCII 字符汉字、中文符号等占多字节的字符无法存放C 编译器为字符变量分配 1 字节内存1 字节 1 个 ASCII 字符字符常量存储本质存入字符对应的 ASCII 码值而非字符本身因此字符型数据与整型数据可通用。字符数据在内存中的存储形式将字符变量存入字符变量时实际存储的是该字符的ASCII码值二进制范例char c1 a, c2 ba的ASCII码值为97b的ASCII码值为98字符型与整型的通用性因字符数据本质上是ASCII码值整数故字符型与整型可通用。字符型变量可赋值为整数ASCII码也可赋值为字符字符需要ASCII支持字符数据可参与算数运算加减乘除取余运算本质上是ASCII码值参与运算输出形式灵活%c以字符形式输出%d以ASCII整数形式输出。说明有符号char的取值范围为-128~127若赋值超出范围如128会发生溢出属于未定义行为主流编译器通常按模256循环处理128对应-128129对应-127但结果不具备跨编译器兼容性。字符数据的存储与输出流程案例大小写字母的转换原理ASCII中大写字母与对应的小写字母相差32例如A 65, a 97转换规则大写转小写大写字母 32 小写字母小写转大写小写字母 - 32 大写字母示例代码#include stdio.h int main(int argc,char *argv[]) { char c1 c, c2 H; c1 c1 - 32; c2 c2 32; printf(转换后c1%c,c2%c\n,c1,c2); return 0; } 运行结果 /20260810$gcc demo02.c /20260801$ ./a.out 转换后c1C,c2h进制转换将二进制、八进制、十六进制转换为十进制二进制、八进制和十六进制向十进制转换都非常容易就是按权相加。所谓权也即位权。假设当前数字是 N 进制那么对于整数部分从右往左看第 i 位的位权等于 N^{i-1}对于小数部分恰好相反要从左往右看第 j 位的位权为 N^{-j}。更加通俗的理解是假设一个多位数由多个数字组成的数某位上的数字是 1那么它所表示的数值大小就是该位的位权。整数部分示例例如将八进制数字 53627 转换成十进制53627 5×8^4 3×8^3 6×8^2 2×8^1 7×8^0 22423十进制将十六进制数字 9FA8C 转换成十进制9FA8C 9×16^4 15×16^3 10×16^2 8×16^1 12×16^0 653964十进制将二进制数字转换成十进制也是类似的道理11010 1×2^4 1×2^3 0×2^2 1×2^1 0×2^0 26十进制更多示例二进制1001 1×2^3 0×2^2 0×2^1 1×2^0 8 0 0 1 9十进制二进制101.1001 1×2^2 0×2^1 1×2^0 1×2^{-1} 0×2^{-2} 0×2^{-3} 1×2^{-4} 4 0 1 0.5 0 0 0.0625 5.5625十进制八进制302 3×8^2 0×8^1 2×8^0 192 0 2 194十进制八进制302.46 3×8^2 0×8^1 2×8^0 4×8^{-1} 6×8^{-2} 192 0 2 0.5 0.09375 194.59375十进制十六进制EA7 14×16^2 10×16^1 7×16^0 3751十进制将十进制转换为二进制、八进制、十六进制将十进制转换为其它进制时比较复杂整数部分和小数部分的算法不一样。整数部分十进制整数转换为 N 进制整数采用除 N 取余逆序排列法。具体做法是将 N 作为除数用十进制整数除以 N可以得到一个商和余数保留余数用商继续除以 N又得到一个新的商和余数仍然保留余数用商继续除以 N还会得到一个新的商和余数……如此反复进行每次都保留余数用商接着除以 N直到商为 0 时为止。把先得到的余数作为 N 进制数的低位数字后得到的余数作为 N 进制数的高位数字依次排列起来就得到了 N 进制数字。从图中得知十进制数字 36926 转换成八进制的结果为 110076。从图中得知十进制数字 42 转换成二进制的结果为 101010。小数部分十进制小数转换成 N 进制小数采用乘 N 取整顺序排列法。具体做法是用 N 乘以十进制小数可以得到一个积这个积包含了整数部分和小数部分将积的整数部分取出再用 N 乘以余下的小数部分又得到一个新的积再将积的整数部分取出继续用 N 乘以余下的小数部分……如此反复进行每次都取出整数部分用 N 接着乘以小数部分直到积中的小数部分为 0或者达到所要求的精度为止。把取出的整数部分按顺序排列起来先取出的整数作为 N 进制小数的高位数字后取出的整数作为低位数字这样就得到了 N 进制小数。如果一个数字既包含了整数部分又包含了小数部分那么将整数部分和小数部分开分别按照上面的方法完成转换然后再合并在一起即可。例如十进制数字 36926.930908203125 转换成八进制的结果为 110076.7345十进制数字 42.6875 转换成二进制的结果为 101010.1011。进制对照表下表列出了前 17 个十进制整数与二进制、八进制、十六进制的对应关系十进制012345678910111213141516二进制0110111001011101111000100110101011110011011110111110000八进制01234567101112131415161720十六进制0123456789ABCDEF10注意 注意十进制小数转换成其他进制小数时结果有可能是一个无限位的小数。例如十进制 0.51 对应的二进制为 0.100000101000111101011100001010001111010111...是一个循环小数十进制 0.625 对应的二进制为 0.101是一个有限小数。二进制和八进制、十六进制的转换二进制整数和八进制整数之间的转换二进制整数转换为八进制整数时每三位二进制数字转换为一位八进制数字运算的顺序是从低位向高位依次进行高位不足三位用零补齐。八进制整数转换为二进制整数时思路是相反的每一位八进制数字转换为三位二进制数字。二进制整数和十六进制整数之间的转换二进制整数转换为十六进制整数时每四位二进制数字转换为一位十六进制数字运算的顺序是从低位向高位依次进行高位不足四位用零补齐。十六进制整数转换为二进制整数时思路是相反的每一位十六进制数字转换为四位二进制数字。注意 在C语言编程中二进制、八进制、十六进制之间几乎不会涉及小数的转换所以这里我们只讲整数的转换大家学以致用足以。另外八进制和十六进制之间也极少直接转换。