变量、常量与输入输出printf 和 scanf 详解一、本篇文章要解决什么问题前面两篇你搭好了环境、了解了数据类型接下来要面对的问题是数据怎么存、怎么显示、怎么让用户输入这篇文章就帮你搞定三件事变量和常量到底是什么关系const 有什么用printf怎么控制输出格式——宽度、小数位、对齐scanf怎么安全地读取用户输入那个符号到底什么意思学完这篇你就能写出真正能和用户对话的程序——既能接收输入也能把结果漂漂亮亮地打印出来。二、先用一个简单例子理解2.1 变量就是贴标签的盒子想象你去超市存包。你把包放进一个储物柜拿到一张小票小票上印着柜子编号。以后凭这张小票就能找到你的包。C 语言里的变量就是这个意思储物柜 内存中的一块空间小票上的编号 变量的名字比如age、score包里的东西 变量存的数据柜子的大小 变量的类型int占 4 字节double占 8 字节2.2 printf 和 scanf 就像前台接待printf好比你把一张纸条递给前台前台照着纸条上的内容大声念出来。scanf好比前台问你一个问题你口头回答前台把你的话记下来存到指定的柜子里。这就是 C 语言里最基本的输入输出模型。下面的章节会把这套流程拆开讲清楚。三、核心知识点讲解3.1 变量的定义与初始化在 C 语言里用变量之前必须先声明它。声明要做两件事告诉编译器变量叫什么名字、是什么类型。intage;// 声明一个 int 类型的变量尚未初始化age20;// 赋值intscore95;// 声明的同时初始化——推荐写法什么叫初始化就是给变量赋第一个值。如果只声明不初始化局部变量的值是不确定的——里面可能残留上一次用这块内存时留下的随机数据。错误示例不要复制运行仅用于理解概念#includestdio.hintmain(void){intx;// 未初始化x 的值是随机的// printf(x %d\n, x); // 读取未初始化的局部变量属于未定义行为return0;}读取未初始化局部变量的值属于未定义行为——C 语言标准没有规定这种情况下应该怎么做不同编译器、不同运行环境可能表现出不同的结果可能输出随机值、可能崩溃、也可能看起来正常。因此永远不要依赖未初始化变量的值。建议声明变量时尽量同时初始化。如果暂时不知道赋什么值可以先用0或其他有意义的默认值。图3-1 变量与内存关系图帮助初学者建立变量 命名内存的核心概念。3.2 常量——“不能改的变量”有些数据在程序运行期间不应该被修改。比如圆周率 π 3.14159一天的秒数 86400。这些数据适合定义为常量。C 语言有两种方式定义常量方式一const 关键字constdoublePI3.14159;PI3.14;// 编译错误const 变量不能被修改方式二#define 宏常量#definePI3.14159#defineSECONDS_PER_DAY86400const和#define的区别const定义的常量有类型编译器可以做类型检查可以取地址#define是预处理替换不占内存空间但没有类型信息宏常量#define常用于定义数组长度、编译期开关等场景const更适合表示有明确类型、希望受到编译器类型检查的常量。初学阶段两者都会用到关键是理解它们各自的工作方式3.3 printf 的基本用法printf是 C 语言里最常用的输出函数来自stdio.h。它的基本格式是printf(格式字符串,变量1,变量2,...);格式字符串里用%开头的格式占位符来表示这里要被后面的变量替换。最常用的格式占位符占位符对应类型含义%dint有符号十进制整数%uunsigned int无符号十进制整数%lldlong long长长整型%ffloat/double浮点数默认 6 位小数%lfdouble浮点数printf 中%f也兼容 double%cchar单个字符%schar[]/char*字符串%p指针内存地址十六进制%%—输出一个%符号本身代码示例——各种占位符一次看全#includestdio.hintmain(void){intage20;doubleheight175.5;chargradeA;charname[]Tom;printf(姓名%s\n,name);printf(年龄%d 岁\n,age);printf(身高%.1f cm\n,height);printf(成绩等级%c\n,grade);printf(完成度%d%%\n,100);// 输出 100%%% 表示一个 %return0;}运行结果姓名Tom 年龄20 岁 身高175.5 cm 成绩等级A 完成度100%3.4 printf 格式控制宽度、小数位、对齐很多时候你不仅需要输出数据还需要控制输出的格式。printf 的占位符可以加修饰符来精确控制。控制小数位数doublepi3.14159265;printf(%.2f\n,pi);// 输出 3.14保留 2 位小数printf(%.5f\n,pi);// 输出 3.14159保留 5 位小数控制输出宽度常用于对齐表格printf(%5d\n,42);// 输出 42总宽度 5右对齐前面补空格printf(%-5d\n,42);// 输出 42 加负号左对齐printf(%05d\n,42);// 输出 00042宽度 5前面补 0综合演示——打印对齐表格#includestdio.hintmain(void){printf(%-10s %5s %8s\n,姓名,年龄,成绩);printf(-------------------------\n);printf(%-10s %5d %8.1f\n,Tom,20,92.5);printf(%-10s %5d %8.1f\n,Alice,22,88.0);printf(%-10s %5d %8.1f\n,Bob,19,76.5);return0;}运行结果姓名 年龄 成绩 ------------------------- Tom 20 92.5 Alice 22 88.0 Bob 19 76.5%-10s字符串左对齐占 10 个字符宽%5d整数右对齐占 5 个字符宽%8.1f浮点数右对齐占 8 个字符宽保留 1 位小数图3-2 printf 格式控制效果图让读者直观看到每种格式控制符对输出的影响。3.5 scanf 的基本用法——为什么需要 scanf和printf刚好相反printf把数据从程序里送出去scanf把数据从键盘读进来。intage;scanf(%d,age);// 注意age 前面必须加 为什么scanf的变量前要加回顾上一篇讲指针时的概念是取地址运算符。scanf需要知道把读到的数据存到哪里所以你必须把变量的地址传给scanf而不是把变量的值传给它。用图书馆的类比scanf是送书员你告诉它柜子的编号地址它才能把书放进正确的柜子里。如果你只告诉它柜子里现在有什么送书员根本不知道该把新书放哪。// 正确把 age 的地址传给 scanfscanf(%d,age);// 错误传的是 age 的值20scanf 把这个值当成地址来写——会崩溃scanf(%d,age);各种类型的 scanf 写法数据类型scanf 占位符示例int%dscanf(%d, age);double%lfscanf(%lf, score);float%fscanf(%f, height);char%cscanf( %c, grade);注意%c前加空格char[]字符串%sscanf(%19s, name);不加 但要限制长度特别注意%cscanf(%c, ch)会读取缓冲区中残留的换行符。解决办法是在%c前面加一个空格scanf( %c, ch)。这个空格会跳过所有空白字符包括换行符。图3-3 scanf 读取流程图帮读者理解 scanf 的工作机制和缓冲区的存在。3.6 输入缓冲区的初步认识当你在键盘上打字并按下回车时你输入的所有字符包括最后的回车\n会先被放进一个叫输入缓冲区的临时区域scanf再从这个缓冲区里按格式读取数据。这就产生了一个经典问题——残留的换行符#includestdio.hintmain(void){intage;chargrade;printf(请输入年龄);scanf(%d,age);// 输入 20然后按回车// 缓冲区里还剩一个 \nprintf(请输入等级);scanf(%c,grade);// grade 读到了那个残留的 \n// 程序不等你输入直接跳过去了printf(年龄%d等级%c\n,age,grade);return0;}运行结果用户没有机会输入等级请输入年龄20 请输入等级年龄20等级解决方案scanf( %c,grade);// %c 前加空格跳过残留的空白字符这个问题非常常见很多初学者会卡在这里。你只要知道%c前面加空格这个技巧就不会被坑了。图3-4 变量、常量、宏对比表让读者分清三种存数据方式的区别和适用场景。四、完整代码示例下面这个程序把变量定义、常量、printf 格式化、scanf 输入这些知识点串在一起模拟一个简单的学生信息录入与显示场景#define_CRT_SECURE_NO_WARNINGS#includestdio.h#defineMAX_NAME_LEN20#definePASS_SCORE60intmain(void){// 变量声明与初始化charname[MAX_NAME_LEN];intage;doublescore;chargrade;// 用户输入printf( 学生信息录入 \n);printf(请输入姓名);scanf(%19s,name);// 限制输入长度防止溢出printf(请输入年龄);scanf(%d,age);printf(请输入成绩);scanf(%lf,score);// double 用 %lfprintf(请输入等级A/B/C/D);scanf( %c,grade);// %c 前加空格跳过残留换行符// 输出结果printf(\n 学生信息卡 \n);printf(%-12s: %s\n,姓名,name);printf(%-12s: %d 岁\n,年龄,age);printf(%-12s: %.1f 分\n,成绩,score);printf(%-12s: %c\n,等级,grade);// 判断是否及格if(scorePASS_SCORE){printf(%-12s: 已及格 %d 分\n,状态,PASS_SCORE);}else{printf(%-12s: 未及格 %d 分\n,状态,PASS_SCORE);}return0;}五、运行结果 学生信息录入 请输入姓名Tom 请输入年龄20 请输入成绩85.5 请输入等级A/B/C/DA 学生信息卡 姓名 : Tom 年龄 : 20 岁 成绩 : 85.5 分 等级 : A 状态 : 已及格 60 分六、代码逐行解析第一部分预处理和常量定义#define_CRT_SECURE_NO_WARNINGS#includestdio.h#defineMAX_NAME_LEN20#definePASS_SCORE60第一行屏蔽 Visual Studio 的 scanf 安全警告第二行引入标准输入输出头文件第三、四行用#define定义了两个宏常量名字最大长度和及格分数线。好处以后如果要改及格线为 70 分只需改这一个地方不用在代码里到处找60第二部分变量声明charname[MAX_NAME_LEN];intage;doublescore;chargrade;name[20]是一个字符数组能存 19 个有效字符加一个\0age、score、grade分别存年龄、成绩和等级这些变量在声明时没有赋初值因为马上要通过scanf从键盘读取第三部分scanf 读取输入scanf(%19s,name);%19s限制最多读取 19 个字符留出第 20 位给字符串结束符\0name前面没有因为数组名本身就是首元素地址scanf(%d,age);scanf(%lf,score);age是int用%d前面加score是double用%lf注意printf 里double可以用%f但 scanf 里double必须用%lffloat用%fscanf( %c,grade);%c前面的空格是关键——它跳过输入缓冲区里残留的换行符确保能正确读到用户输入的等级字符第四部分printf 格式化输出printf(%-12s: %s\n,姓名,name);%-12s表示字符串左对齐占 12 个字符宽度。冒号后面的内容会对齐排列后面的%s输出实际的名字字符串第五部分const / #define 常量的实际应用if(scorePASS_SCORE)不使用魔术数字60而是用宏常量PASS_SCORE。这是好的编程习惯——代码更可读修改也更方便。七、初学者常见错误错误1scanf 中 int/double/char 变量忘记加 // 错误写法intage;scanf(%d,age);// 编译可能不报错但运行时崩溃// 正确写法intage;scanf(%d,age);原因scanf需要变量的地址才能把读到的数据存进去。不加就是把age的值当成地址这是典型的段错误来源。错误2scanf 读取 double 时用了 %f// 错误写法doublescore;scanf(%f,score);// double 应该用 %lf// 正确写法doublescore;scanf(%lf,score);printf里%f可以同时用于float和double但scanf里必须严格区分float用%fdouble用%lf。这是初学者最容易搞混的一个细节。错误3scanf 读取 %c 时跳过了用户输入// 错误写法前有 scanf(%d) 输入后缓冲区残留 \nscanf(%c,ch);// ch 读到了残留的 \n// 正确写法scanf( %c,ch);// %c 前加空格跳过空白字符错误4用 scanf 读取带空格的字符串charname[20];scanf(%s,name);// 用户输入 Zhang San只读到 Zhang// 如果需要读取含空格的字符串用 fgets后续文章会讲%s遇到空格、Tab、换行都会停止。如果你的输入可能包含空格比如Zhang Sanscanf(%s)不合适。这在第 8 篇字符串文章会详细展开。错误5printf 格式占位符与参数类型不匹配inta10;printf(%f\n,a);// 用 %f 打印 int——结果不可预测longlongb123456789LL;printf(%d\n,b);// 用 %d 打印 long long——可能只输出部分数据格式占位符必须和参数类型严格对应。搞错了编译器不一定报错但输出结果会出错。八、练习题练习题1个人信息卡片写一个程序让用户输入以下信息然后按对齐格式输出一张个人信息卡片姓名字符串最多 19 个字符年龄整数身高浮点数单位 cm保留 1 位小数体重浮点数单位 kg保留 1 位小数要求输出时标签左对齐、占 8 个字符宽值右对齐。输出格式参考姓名 Tom 年龄 20 身高 175.5 体重 68.3练习题2圆的周长和面积定义常量PI 3.14159。让用户输入圆的半径浮点数程序输出圆的周长和面积各保留 2 位小数。公式周长 2 × π × r面积 π × r²提示注意scanf读取double要用%lf。练习题3输入缓冲区问题修复下面的程序有 bug——用户输入学号后程序会跳过字母等级的选择直接结束。找出原因并修复#define_CRT_SECURE_NO_WARNINGS#includestdio.hintmain(void){intstudentID;chargrade;printf(请输入学号);scanf(%d,studentID);printf(请输入等级A/B/C/D);scanf(%c,grade);// 这里有问题printf(学号%d等级%c\n,studentID,grade);return0;}提示输入学号后按回车缓冲区里残留了一个\n。%c会读到这个换行符导致程序不等你输入等级就结束了。在%c前面加一个空格即可解决问题。九、本篇总结变量使用前必须声明类型推荐声明的同时初始化const 和 #define 都可以定义常量宏常量常用于数组长度等场景const 更适合有明确类型、需要类型检查的常量printf 格式控制%d整数、%f浮点、%c字符、%s字符串.2控制小数位数字控制宽度-左对齐scanf 中普通变量必须加数组名不加double用%lffloat用%f%c前面加空格可以跳过缓冲区残留的换行符解决跳过输入的问题
03_变量常量与输入输出_printf与scanf详解
发布时间:2026/5/18 23:15:51
变量、常量与输入输出printf 和 scanf 详解一、本篇文章要解决什么问题前面两篇你搭好了环境、了解了数据类型接下来要面对的问题是数据怎么存、怎么显示、怎么让用户输入这篇文章就帮你搞定三件事变量和常量到底是什么关系const 有什么用printf怎么控制输出格式——宽度、小数位、对齐scanf怎么安全地读取用户输入那个符号到底什么意思学完这篇你就能写出真正能和用户对话的程序——既能接收输入也能把结果漂漂亮亮地打印出来。二、先用一个简单例子理解2.1 变量就是贴标签的盒子想象你去超市存包。你把包放进一个储物柜拿到一张小票小票上印着柜子编号。以后凭这张小票就能找到你的包。C 语言里的变量就是这个意思储物柜 内存中的一块空间小票上的编号 变量的名字比如age、score包里的东西 变量存的数据柜子的大小 变量的类型int占 4 字节double占 8 字节2.2 printf 和 scanf 就像前台接待printf好比你把一张纸条递给前台前台照着纸条上的内容大声念出来。scanf好比前台问你一个问题你口头回答前台把你的话记下来存到指定的柜子里。这就是 C 语言里最基本的输入输出模型。下面的章节会把这套流程拆开讲清楚。三、核心知识点讲解3.1 变量的定义与初始化在 C 语言里用变量之前必须先声明它。声明要做两件事告诉编译器变量叫什么名字、是什么类型。intage;// 声明一个 int 类型的变量尚未初始化age20;// 赋值intscore95;// 声明的同时初始化——推荐写法什么叫初始化就是给变量赋第一个值。如果只声明不初始化局部变量的值是不确定的——里面可能残留上一次用这块内存时留下的随机数据。错误示例不要复制运行仅用于理解概念#includestdio.hintmain(void){intx;// 未初始化x 的值是随机的// printf(x %d\n, x); // 读取未初始化的局部变量属于未定义行为return0;}读取未初始化局部变量的值属于未定义行为——C 语言标准没有规定这种情况下应该怎么做不同编译器、不同运行环境可能表现出不同的结果可能输出随机值、可能崩溃、也可能看起来正常。因此永远不要依赖未初始化变量的值。建议声明变量时尽量同时初始化。如果暂时不知道赋什么值可以先用0或其他有意义的默认值。图3-1 变量与内存关系图帮助初学者建立变量 命名内存的核心概念。3.2 常量——“不能改的变量”有些数据在程序运行期间不应该被修改。比如圆周率 π 3.14159一天的秒数 86400。这些数据适合定义为常量。C 语言有两种方式定义常量方式一const 关键字constdoublePI3.14159;PI3.14;// 编译错误const 变量不能被修改方式二#define 宏常量#definePI3.14159#defineSECONDS_PER_DAY86400const和#define的区别const定义的常量有类型编译器可以做类型检查可以取地址#define是预处理替换不占内存空间但没有类型信息宏常量#define常用于定义数组长度、编译期开关等场景const更适合表示有明确类型、希望受到编译器类型检查的常量。初学阶段两者都会用到关键是理解它们各自的工作方式3.3 printf 的基本用法printf是 C 语言里最常用的输出函数来自stdio.h。它的基本格式是printf(格式字符串,变量1,变量2,...);格式字符串里用%开头的格式占位符来表示这里要被后面的变量替换。最常用的格式占位符占位符对应类型含义%dint有符号十进制整数%uunsigned int无符号十进制整数%lldlong long长长整型%ffloat/double浮点数默认 6 位小数%lfdouble浮点数printf 中%f也兼容 double%cchar单个字符%schar[]/char*字符串%p指针内存地址十六进制%%—输出一个%符号本身代码示例——各种占位符一次看全#includestdio.hintmain(void){intage20;doubleheight175.5;chargradeA;charname[]Tom;printf(姓名%s\n,name);printf(年龄%d 岁\n,age);printf(身高%.1f cm\n,height);printf(成绩等级%c\n,grade);printf(完成度%d%%\n,100);// 输出 100%%% 表示一个 %return0;}运行结果姓名Tom 年龄20 岁 身高175.5 cm 成绩等级A 完成度100%3.4 printf 格式控制宽度、小数位、对齐很多时候你不仅需要输出数据还需要控制输出的格式。printf 的占位符可以加修饰符来精确控制。控制小数位数doublepi3.14159265;printf(%.2f\n,pi);// 输出 3.14保留 2 位小数printf(%.5f\n,pi);// 输出 3.14159保留 5 位小数控制输出宽度常用于对齐表格printf(%5d\n,42);// 输出 42总宽度 5右对齐前面补空格printf(%-5d\n,42);// 输出 42 加负号左对齐printf(%05d\n,42);// 输出 00042宽度 5前面补 0综合演示——打印对齐表格#includestdio.hintmain(void){printf(%-10s %5s %8s\n,姓名,年龄,成绩);printf(-------------------------\n);printf(%-10s %5d %8.1f\n,Tom,20,92.5);printf(%-10s %5d %8.1f\n,Alice,22,88.0);printf(%-10s %5d %8.1f\n,Bob,19,76.5);return0;}运行结果姓名 年龄 成绩 ------------------------- Tom 20 92.5 Alice 22 88.0 Bob 19 76.5%-10s字符串左对齐占 10 个字符宽%5d整数右对齐占 5 个字符宽%8.1f浮点数右对齐占 8 个字符宽保留 1 位小数图3-2 printf 格式控制效果图让读者直观看到每种格式控制符对输出的影响。3.5 scanf 的基本用法——为什么需要 scanf和printf刚好相反printf把数据从程序里送出去scanf把数据从键盘读进来。intage;scanf(%d,age);// 注意age 前面必须加 为什么scanf的变量前要加回顾上一篇讲指针时的概念是取地址运算符。scanf需要知道把读到的数据存到哪里所以你必须把变量的地址传给scanf而不是把变量的值传给它。用图书馆的类比scanf是送书员你告诉它柜子的编号地址它才能把书放进正确的柜子里。如果你只告诉它柜子里现在有什么送书员根本不知道该把新书放哪。// 正确把 age 的地址传给 scanfscanf(%d,age);// 错误传的是 age 的值20scanf 把这个值当成地址来写——会崩溃scanf(%d,age);各种类型的 scanf 写法数据类型scanf 占位符示例int%dscanf(%d, age);double%lfscanf(%lf, score);float%fscanf(%f, height);char%cscanf( %c, grade);注意%c前加空格char[]字符串%sscanf(%19s, name);不加 但要限制长度特别注意%cscanf(%c, ch)会读取缓冲区中残留的换行符。解决办法是在%c前面加一个空格scanf( %c, ch)。这个空格会跳过所有空白字符包括换行符。图3-3 scanf 读取流程图帮读者理解 scanf 的工作机制和缓冲区的存在。3.6 输入缓冲区的初步认识当你在键盘上打字并按下回车时你输入的所有字符包括最后的回车\n会先被放进一个叫输入缓冲区的临时区域scanf再从这个缓冲区里按格式读取数据。这就产生了一个经典问题——残留的换行符#includestdio.hintmain(void){intage;chargrade;printf(请输入年龄);scanf(%d,age);// 输入 20然后按回车// 缓冲区里还剩一个 \nprintf(请输入等级);scanf(%c,grade);// grade 读到了那个残留的 \n// 程序不等你输入直接跳过去了printf(年龄%d等级%c\n,age,grade);return0;}运行结果用户没有机会输入等级请输入年龄20 请输入等级年龄20等级解决方案scanf( %c,grade);// %c 前加空格跳过残留的空白字符这个问题非常常见很多初学者会卡在这里。你只要知道%c前面加空格这个技巧就不会被坑了。图3-4 变量、常量、宏对比表让读者分清三种存数据方式的区别和适用场景。四、完整代码示例下面这个程序把变量定义、常量、printf 格式化、scanf 输入这些知识点串在一起模拟一个简单的学生信息录入与显示场景#define_CRT_SECURE_NO_WARNINGS#includestdio.h#defineMAX_NAME_LEN20#definePASS_SCORE60intmain(void){// 变量声明与初始化charname[MAX_NAME_LEN];intage;doublescore;chargrade;// 用户输入printf( 学生信息录入 \n);printf(请输入姓名);scanf(%19s,name);// 限制输入长度防止溢出printf(请输入年龄);scanf(%d,age);printf(请输入成绩);scanf(%lf,score);// double 用 %lfprintf(请输入等级A/B/C/D);scanf( %c,grade);// %c 前加空格跳过残留换行符// 输出结果printf(\n 学生信息卡 \n);printf(%-12s: %s\n,姓名,name);printf(%-12s: %d 岁\n,年龄,age);printf(%-12s: %.1f 分\n,成绩,score);printf(%-12s: %c\n,等级,grade);// 判断是否及格if(scorePASS_SCORE){printf(%-12s: 已及格 %d 分\n,状态,PASS_SCORE);}else{printf(%-12s: 未及格 %d 分\n,状态,PASS_SCORE);}return0;}五、运行结果 学生信息录入 请输入姓名Tom 请输入年龄20 请输入成绩85.5 请输入等级A/B/C/DA 学生信息卡 姓名 : Tom 年龄 : 20 岁 成绩 : 85.5 分 等级 : A 状态 : 已及格 60 分六、代码逐行解析第一部分预处理和常量定义#define_CRT_SECURE_NO_WARNINGS#includestdio.h#defineMAX_NAME_LEN20#definePASS_SCORE60第一行屏蔽 Visual Studio 的 scanf 安全警告第二行引入标准输入输出头文件第三、四行用#define定义了两个宏常量名字最大长度和及格分数线。好处以后如果要改及格线为 70 分只需改这一个地方不用在代码里到处找60第二部分变量声明charname[MAX_NAME_LEN];intage;doublescore;chargrade;name[20]是一个字符数组能存 19 个有效字符加一个\0age、score、grade分别存年龄、成绩和等级这些变量在声明时没有赋初值因为马上要通过scanf从键盘读取第三部分scanf 读取输入scanf(%19s,name);%19s限制最多读取 19 个字符留出第 20 位给字符串结束符\0name前面没有因为数组名本身就是首元素地址scanf(%d,age);scanf(%lf,score);age是int用%d前面加score是double用%lf注意printf 里double可以用%f但 scanf 里double必须用%lffloat用%fscanf( %c,grade);%c前面的空格是关键——它跳过输入缓冲区里残留的换行符确保能正确读到用户输入的等级字符第四部分printf 格式化输出printf(%-12s: %s\n,姓名,name);%-12s表示字符串左对齐占 12 个字符宽度。冒号后面的内容会对齐排列后面的%s输出实际的名字字符串第五部分const / #define 常量的实际应用if(scorePASS_SCORE)不使用魔术数字60而是用宏常量PASS_SCORE。这是好的编程习惯——代码更可读修改也更方便。七、初学者常见错误错误1scanf 中 int/double/char 变量忘记加 // 错误写法intage;scanf(%d,age);// 编译可能不报错但运行时崩溃// 正确写法intage;scanf(%d,age);原因scanf需要变量的地址才能把读到的数据存进去。不加就是把age的值当成地址这是典型的段错误来源。错误2scanf 读取 double 时用了 %f// 错误写法doublescore;scanf(%f,score);// double 应该用 %lf// 正确写法doublescore;scanf(%lf,score);printf里%f可以同时用于float和double但scanf里必须严格区分float用%fdouble用%lf。这是初学者最容易搞混的一个细节。错误3scanf 读取 %c 时跳过了用户输入// 错误写法前有 scanf(%d) 输入后缓冲区残留 \nscanf(%c,ch);// ch 读到了残留的 \n// 正确写法scanf( %c,ch);// %c 前加空格跳过空白字符错误4用 scanf 读取带空格的字符串charname[20];scanf(%s,name);// 用户输入 Zhang San只读到 Zhang// 如果需要读取含空格的字符串用 fgets后续文章会讲%s遇到空格、Tab、换行都会停止。如果你的输入可能包含空格比如Zhang Sanscanf(%s)不合适。这在第 8 篇字符串文章会详细展开。错误5printf 格式占位符与参数类型不匹配inta10;printf(%f\n,a);// 用 %f 打印 int——结果不可预测longlongb123456789LL;printf(%d\n,b);// 用 %d 打印 long long——可能只输出部分数据格式占位符必须和参数类型严格对应。搞错了编译器不一定报错但输出结果会出错。八、练习题练习题1个人信息卡片写一个程序让用户输入以下信息然后按对齐格式输出一张个人信息卡片姓名字符串最多 19 个字符年龄整数身高浮点数单位 cm保留 1 位小数体重浮点数单位 kg保留 1 位小数要求输出时标签左对齐、占 8 个字符宽值右对齐。输出格式参考姓名 Tom 年龄 20 身高 175.5 体重 68.3练习题2圆的周长和面积定义常量PI 3.14159。让用户输入圆的半径浮点数程序输出圆的周长和面积各保留 2 位小数。公式周长 2 × π × r面积 π × r²提示注意scanf读取double要用%lf。练习题3输入缓冲区问题修复下面的程序有 bug——用户输入学号后程序会跳过字母等级的选择直接结束。找出原因并修复#define_CRT_SECURE_NO_WARNINGS#includestdio.hintmain(void){intstudentID;chargrade;printf(请输入学号);scanf(%d,studentID);printf(请输入等级A/B/C/D);scanf(%c,grade);// 这里有问题printf(学号%d等级%c\n,studentID,grade);return0;}提示输入学号后按回车缓冲区里残留了一个\n。%c会读到这个换行符导致程序不等你输入等级就结束了。在%c前面加一个空格即可解决问题。九、本篇总结变量使用前必须声明类型推荐声明的同时初始化const 和 #define 都可以定义常量宏常量常用于数组长度等场景const 更适合有明确类型、需要类型检查的常量printf 格式控制%d整数、%f浮点、%c字符、%s字符串.2控制小数位数字控制宽度-左对齐scanf 中普通变量必须加数组名不加double用%lffloat用%f%c前面加空格可以跳过缓冲区残留的换行符解决跳过输入的问题