
变量程序运行过程中会发生变化格式存储类型 数据类型 变量名auto存储类型决定变量存放的位置auto 表示默认存储在栈区由系统自动管理数据类型决定开辟的空间大小变量名遵循标识符命名规则类型含义字节大小取值范围(了解)char字符型1-128~127int整型4约 -21 亿 ~ 21 亿short短整型2-32768~32767long长整型32位4 64位8依赖平台32/64位不同float单精度浮点型4有效位数6-7double双精度浮点型8有效位数15-16使用sizeof运算符可以查看任意类型在当前平台下占用的字节数printf(%ld\n, sizeof(char));以上代码输出char类型在当前平台下的字节大小通常为 1。局部变量和全局变量的区别对比维度局部变量全局变量定义位置函数体内部函数体外部初值未初始化值为随机数未初始化值为0存储位置栈区全局区作用域当前函数体内整个程序生命周期随函数共存亡随整个程序共存亡简单记忆局部变量在函数内部定义函数结束即销毁全局变量在函数外部定义整个程序运行期间一直存在。虚拟内存空间32位系统4G 虚拟地址空间64位系统264 虚拟地址空间栈区系统自动开辟、回收存放局部变量、函数参数堆区程序员手动开辟、回收通过 malloc/free 管理全局区 / 静态区存放全局变量和静态变量进一步分为.bss 段未初始化或初始化为 0 的全局/静态变量.data 段已初始化且初值非 0 的全局/静态变量常量区存放字符串常量等只读数据常量程序运行过程中不会发生变化整型常量支持四种进制表示二进制0b 前缀、八进制0 前缀、十进制默认、十六进制0x 前缀浮点型常量float 和 double 类型如 3.14默认 double 类型3.14f 表示 float 类型字符常量由单引号包裹单个元素char a a;a 是变量a 是字符常量\ 转义字符如 \n换行、\t制表、\\反斜杠本身字符串常量由双引号包裹以 \0 为结束标志hello ---- 实际存储为 hello\0占 6 个字节标识常量宏定义宏定义在预处理阶段进行文本替换格式#define 宏名 常量值或表达式或函数宏名一般用大写为了和普通变量区分开特点先进行单纯的替换最后再计算注意运算优先级建议加括号保护#includestdio.h #define N 3 #define M N1 #define NUM NM/2 int main(int argc, char const *argv[]) { printf(%d\n, NUM); return 0; }宏示例求两个数中的最大值#includestdio.h #define MAX ab?a:b int main(int argc, char const *argv[]) { int a 33; int b 56; printf(%d\n, MAX); a 67; b 89; printf(%d\n, MAX); return 0; }宏函数带参数的宏#includestdio.h #define MAX(a, b) ab?a:b int main(int argc, char const *argv[]) { printf(%d\n, MAX(12, 35)); printf(%d\n, MAX(87, 59)); return 0; }宏函数与普通函数的区别宏函数在预处理阶段直接展开没有函数调用开销但不做类型检查且多次参数求值可能带来副作用。输入输出按字符输入输出getcharint getchar(void);// int a;功能从终端标准输入读取一个字符参数 void无参数返回值读取字符的 ASCII 码值int 类型失败返回 EOFputcharint putchar(int c);功能向终端标准输出输出一个字符参数要输出的字符的 ASCII 码值返回值成功输出时返回该字符的 ASCII 码值失败返回 EOF#includestdio.h int main(int argc, char const *argv[]) { // getchar(); int n getchar(); putchar(n); putchar(10); return 0; }利用 getchar 吸收多余的换行符当使用 scanf 读取字符后缓冲区中可能残留换行符可以在下一次 scanf 前调用 getchar() 将其吸收掉char a 0; scanf(%c, a); getchar(); printf(%d\n, a); char b 0; scanf(%c, b); printf(%d\n, b);按格式输入输出printfint printf(const char *format, ...);功能按指定格式向终端输出内容参数第一个参数是格式字符串后面是不定长的输出项返回值成功输出元素的个数常用格式占位符%dint 整型%cchar 字符型%ffloat 单精度浮点型%lfdouble 双精度浮点型%s字符串%p指针地址%o / %#o八进制加 # 显示前导 0%x / %#x十六进制加 # 显示前导 0x精度控制.n 保留 n 位小数四舍五入%f 默认输出小数点后六位float a 123.456; printf(%f\n, a); // 输出 123.456000 printf(%.1f\n, a); // 输出 123.5位宽控制m 位宽位宽值大于数据实际宽度时才会在左侧补空格对齐#includestdio.h int main(int argc, char const *argv[]) { int a 2; int b 22; int c 222; printf(%3d\n, a); // 输出 2 printf(%3d\n, b); // 输出 22 printf(%d\n, c); // 输出 222 return 0; }scanfint scanf(const char *format, ...);功能按指定格式从终端读取输入参数格式字符串 变量地址列表需使用 取地址返回值成功赋值的输入项个数第一个元素赋值失败时返回 0#includestdio.h int main(int argc, char const *argv[]) { int a 0; int b 0; printf(please input a b:\n); scanf(%d %d, a, b); printf(%d %d\n, a, b); return 0; }需要注意scanf 中%d、%f、%s会自动跳过前置空白字符空格、换行、制表符但%c不会自动跳过。如果想深入了解%c的特殊行为以及如何处理缓冲区中的垃圾字符请继续阅读下一章「垃圾字符回收」。垃圾字符回收一、核心问题%c会读取空白垃圾字符1. 空白字符包含哪些空格 、制表符\t、换行符\n都属于空白垃圾字符%c会原封不动读入变量。2. 案例 1连续两个%c无空格char a 0; char b 0; scanf(%c%c, a, b); printf(%d %d\n, a, b);输入场景演示场景 1输入x yx 空格 y回车第一个%c读取字符x→ 存入 a第二个%c直接读取中间的空格→ 存入 b输出结果120 32x 的 ASCII120空格 ASCII32场景 2输入x按回车再输入ya xASCII120b 换行符\nASCII10输出120 10结论%c不会自动跳过空格、回车缓冲区中残留的空白字符会被直接当成有效字符读取产生意料之外的垃圾值。二、空白回收方案格式串前加空格%c语法规则在%c转换符前面写一个空格 作用自动跳过缓冲区中一个或多个连续空白字符空格、\t、\n全部清空。对比代码char a 0; scanf(%c, a); // 无前置空格会读回车/空格 printf(%d\n, a); char b 0; scanf( %c, b); // 前置空格自动清空前面所有空白垃圾 printf(%d\n, b);连续双字符修正写法如果要连续读取两个字符、忽略中间空白给每个%c前加空格scanf( %c %c, a, b);此时输入a 回车 b、a 空格 b、a\tb都会正常读取 a、b空白全部被过滤。三、易混淆知识点%d/%f和%c的区别%d、%f、%s默认自动跳过前置空白不用手动加空格%c不会自动跳过空白缓冲区残留的回车 / 空格会直接读入必须手动加空格过滤垃圾字符。小结遇到%c读字符前如果前面有输入残留优先使用%c前置空格方案如果只是想丢弃单个回车也可以用getchar()吸收。