一,刷题一.基础(区分float/double,字符/字符串)float / doublefloat4字节小数后加 f3.14fdouble8字节默认小数类型3.14%f / %lfprintf统一用 %ffloat、double 都可以scanffloat → %f,double → %lf输出一位小数C语言printf(%.1f, 变量); 例 printf(%.1f, 3.1415); → 输出 3.1%c字符/ %s字符串%cchar ch- scanf必须加 %c, ch- printf不加- %schar str[]- scanf不加 %s, str- printf不加二.题目 noob5 复读机错误点1. 整数溢出变量 b 的范围是 -10^18 ≤ b ≤ 10^18 使用 int 类型会溢出。2. 输入缓冲区残留读取浮点数后缓冲区的换行符被后续 %c 读取导致字符输入错误。修正方案1. 类型匹配将 int b 改为 long long b 输入输出用 %lld 。2. 清除缓冲区字符输入改为 scanf( %c, d); 用空格跳过换行符。核心知识点- long long 用于存储超大整数对应格式符 %lld 。- %c 会读取换行符需在格式串前加空格跳过空白字符。- 浮点数输出保留一位小数用 %.1f 。三,字符串核心结论1. 初始化定义时赋值一步可用 直接给字符串 char str[10] abc;2. 赋值定义后赋值两种不能用 只能用- scanf(%s, str); 输入赋值- strcpy(str, abc); 函数复制3. scanf(%s)可给字符数组赋值但不能读空格有溢出风险4. 字符数组不初始化时局部数组存随机值建议 char str[100] {0}; 初始化5. 数组名本身是首地址 scanf/printf 用 %s 时不加 四,疫情死亡率计算C语言核心总结四大必记关键点易错点1. 数据类型c,d 上限10^7必须用 long long int 易溢出输入格式符 %lld2. 计算强转必须 (double)d / c * 100 强转 double 不可省否则整数除法结果为03. 输出百分号 printf 中用 %% 输出单个 % 格式 %.3f%%4. 函数封装计算逻辑抽独立函数形参名任意作用域独立函数名与变量名可重复不建议五,平方根编程题坑点复盘与思想误区一、这道题里的具体坑点1. 函数名非法使用减号- 错误写法 floor-sqrt- 问题本质C语言规定函数名、变量名只能由字母、数字和下划线 _ 组成减号 - 会被编译器识别为减法运算符。2. 遗漏头文件 #include math.h- 问题使用 sqrt() 函数却未包含对应的头文件导致编译器报“未定义的引用”错误。3. 浮点数精度的潜在风险- 风险当输入值 n 非常大时浮点数计算可能存在精度丢失导致 sqrt(n) 的结果有误差。4. 数据类型选择不严谨- 风险如果输入变量 n 选用 int 类型当 n 接近 10^9 时会发生溢出。二、思想本质上的误区1. 惯性思维凭直觉写代码- 表现把日常写法如 floor-sqrt 直接套用在函数名上忽略了编程语言的严格规则。- 根源没有建立“编程世界有自己一套规则”的意识而是用生活中的直觉去写代码。2. 只关注核心逻辑忽略配套细节- 表现只想着“计算平方根再转成整数”这个核心功能却忘了检查头文件、变量类型等“配套设施”。- 根源缺乏“完整工程”思维默认编译器“应该都懂”而不是主动确保代码的完整性。3. 默认“没问题”缺乏风险预判- 表现认为“强转肯定能向下取整”但没思考过浮点数精度问题觉得 int 够用但没看题目给的输入范围。- 根源存在侥幸心理依赖“当前场景没问题”而不是追求“通用、严谨的解决方案”。六,反向输出四位数一、数学拆分法核心- 千位 n / 1000- 百位 n / 100 % 10- 十位 n / 10 % 10- 个位 n % 10- 输出 个位 十位 百位 千位二、字符串法核心- 用 sprintf(s, %d, n) 把数字转成字符串- 倒序输出 s[3] s[2] s[1] s[0]- 需头文件 #include string.h三、关键坑点必记1. 不能用整数反转会丢前导零2. 字符串数组要开 5 位存 \0 3. 函数名不能用减号只能用字母、数字、下划线4. 输出 % 要写 %%七,绕距问题踩坑总结一、核心坑点1. 类型不匹配对浮点数改用 fabs() 取绝对值。2. 依赖直觉凭习惯用 abs() 忽略了整数/浮点数的函数差异。3. 命名不严谨局部变量与参数名冲突增加了阅读和维护成本。二、思想本质- 未建立类型优先的编程思维写代码时只关注逻辑忽略了类型匹配。- 缺乏写完即自查的习惯依赖编译报错来发现问题而不是主动检查。八,循环问题错误原因总结精简版1. 先加1再取余 (d 1) % 7 会把周日d6算成0和题目要求的1~7范围不符必须额外用 if 把0改成7。2. 先取余再加1 (d % 7) 1 先把d映射到0~6再加1自然回到1~7一步到位不用判断。核心规律处理1~N的循环序列时- 先把数映射到0~N-1用 x % N 再做加减最后1回到1~N。- 这样可以避免0的问题代码更简洁。九,比较大小求三个整数最大/最小值的两种简洁写法方法一三目运算符法一行搞定三目运算符 条件 ? 真 : 假 可以让代码更紧凑逻辑清晰。// 先比较前两个数得到临时最大/最小值int max (a b) ? a : b;int min (a b) ? a : b;// 再用临时值和第三个数比较得到最终结果max (max c) ? max : c;min (min c) ? min : c;方法二标准库函数法最省事C 语言的标准库提供了 fmax 和 fmin 函数需要包含 math.h 可以直接求最大/最小值代码最简洁。// 嵌套调用函数直接得到三个数的最大/最小值int max fmax(fmax(a, b), c);int min fmin(fmin(a, b), c);十,判断素数问题:scanf读取方法,1. 最朴素的试除法根据素数定义大于1且只能被1和自身整除。- 对一个数 n从 2 到 n-1 逐个检查是否能整除 n。- 如果都不能整除n 就是素数否则是合数。int isPrime(int n) {if (n 1) return 0; // 1及以下不是素数for (int i 2; i n; i) {if (n % i 0) {return 0; // 能被整除不是素数}}return 1; // 都不能整除是素数}缺点效率极低当 n 很大时比如 10^5循环次数太多会超时。2. 优化版试除法核心优化关键思路如果 n 有一个大于 \sqrt{n} 的因数那它必然有一个小于 \sqrt{n} 的因数。所以我们只需要检查到 \sqrt{n} 就够了循环次数大幅减少。#include math.hint isPrime(int n) {if (n 1) return 0;if (n 2) return 1; // 2是唯一的偶素数if (n % 2 0) return 0; // 大于2的偶数都不是素数直接排除for (int i 3; i sqrt(n); i 2) { // 只检查奇数if (n % i 0) {return 0;}}return 1;}优化点1. 范围减半从 n-1 缩小到 \sqrt{n}。2. 跳过偶数除了2所有偶数都不是素数所以从3开始每次2只检查奇数。3. 更高级的算法可选当 n 非常大比如 10^{18}时试除法也不够用了这时会用到更高效的算法比如- Miller-Rabin 素性测试一种概率性算法速度极快常用于大数判断。- 埃氏筛法 / 欧拉筛法如果需要判断很多数是否为素数可以先筛出所有素数再直接查表。十一,奇偶交替数列核心问题在 for 循环体内修改了循环变量 i 破坏了循环的确定性导致逻辑混乱甚至死循环。正确做法循环变量 i 只由 for 语句的 i 控制不要在循环体内修改它需要取反或变换时用临时变量承载。十二,找最大/最小值时的初始化问题- 核心痛点不知道如何给 max / min 赋初值纠结“第一个数怎么处理”。- 本质给 max 一个足够小的初值给 min 一个足够大的初值保证第一个数一定能更新它们。- 常用方法- 用 limits.h 里的 INT_MIN / INT_MAX 最稳妥。- 手动设一个比题目范围更极端的数如 -1e9 / 1e9 。- 也可以先读第一个数把它作为初值再从第二个数开始比较。十三,斐波那契数列-递归十四,数位之和int swzh(int n){int sum0;while(n0){sumn%10;nn/10;}return sum;}十五,二维斐波那契数列刷题错误总结1. 数组定义错误- 错误用变量 n 、 m 定义数组大小如 long long a[n][m] 。- 原因C 语言数组大小必须是编译期常量不能用变量。- 修正定义固定大小数组 long long a[1001][1001] 或使用动态内存分配。2. 数据类型选择错误- 错误使用 int 存储中间结果。- 原因数值增长极快 int 范围不足会导致溢出。- 修正使用 long long 类型存储数组元素。3. 取模时机错误- 错误仅在最后输出时取模。- 原因中间加法结果会远超数据类型范围导致溢出和结果错误。- 修正每一步加法后立即取模如 a[i][j] (a[i-1][j] a[i][j-1]) % MOD 。十六,神秘石像的镜像序列 刷题错误总结1. 对 cnt 计数时机的理解偏差核心错误- 错误误以为终止符 0 会被计入 cnt 导致对有效数字个数的判断出现偏差。- 原因代码中 a[cnt] digit; 是先赋值再自增当读到 0 时直接 break 0 并未存入数组 cnt 的值恰好等于有效数字的个数。- 修正明确 cnt 是有效数字的计数数组有效下标是 0 到 cnt-1 输出时只需从 cnt-1 开始倒序即可。2. 循环范围判断错误- 错误使用 while(cnt 0) 作为输出循环的条件。- 原因在修正时只修改了 printf 中的下标却忘记同步修改循环条件。当 cnt0 时会尝试访问 a[-1] 导致数组越界和未定义行为。- 修正将循环条件改为 while(cnt 0) 确保只遍历有效元素。十七,约瑟夫环暴力解法#include stdio.h int main() { int n,k,m; scanf(%d %d %d,n,k,m); int a[100]{0}; int posk; int out0; int cnt0; while(outn-1){ if(a[pos]0){ cnt; if(cntm){ a[pos]-1; out; cnt0; } } pos; if(posn){ pos0; } } for(int i0;in;i){ if(a[i]0){ printf(%d\n,i); break; } } return 0; }十八,字符串赋值#include stdio.h #includestring.h int main() { char s[1000002]{0}; fgets(s,1000002,stdin); int lenstrlen(s); if(s[len-1]\n){ s[len-1]\0; } for(int i0;s[i]!\0;i){ if(s[i]5){ s[i]*; } } printf(%s\n,s); return 0; }fgetsstrlen十九,求阶乘易错点二,补基础知识数据类型:1.基本数据类型C 语言数据类型主要分为四大类决定了变量的存储大小、取值范围和可执行操作。修饰符signed/unsigned控制是否有符号默认signed。unsigned类型所有位都用于表示数值范围翻倍如unsigned char为 0~255。const定义常量值不可修改。例:const int a 10;2. 构造数据类型自定义类型由基本类型或其他构造类型组合而成数组相同类型元素的有序集合如int arr[5]。结构体struct不同类型成员的集合用于表示复杂对象如学生、员工。一,结构体基本格式 struct 结构体名{ 类型 成员1; 类型 成员2; ... .... } struct Student{ int id; char name[20]; float score; } struct Student stu1; 二,定义结构体变量 struct 结构体名{ 成员; }变量一,变量二 struct Student{ int id; char name[20]; float score; }stu1,stu2; 三,给结构体起别名(最常用) typedef struct Student{ int id; char name[20]; float score; }Stu;共用体union所有成员共享同一块内存空间同一时间只能存储一个成员。枚举enum定义一组命名的整型常量提高代码可读性如enum Color {RED, GREEN, BLUE};。3. 指针类型本质存储内存地址的变量。声明类型 *变量名如int *p表示指向int类型的指针。核心操作取地址运算符获取变量的内存地址。*解引用运算符通过地址访问内存中的值。int *p a;printf(%d,*p);4. 空类型void表示 “无类型”主要用于函数返回值void func()表示函数不返回任何值。函数参数func(void)表示函数不接受任何参数。无类型指针void *p可以指向任意类型的数据但使用前需强制类型转换。核心要点大小依赖数据类型的字节数与操作系统和编译器有关使用sizeof()运算符可精确获取。类型安全C 语言是强类型语言变量必须先声明类型才能使用不同类型赋值需注意隐式转换规则。内存布局理解数据类型是掌握内存管理、指针操作和结构体对齐的基础。初始化 字符串赋值一、初始化定义变量时直接赋值 初始化。局部变量不初始化随机垃圾值。全局 / 静态变量不初始化自动为 0。常用初始化基本类型int a 10; char c a;数组int arr[5] {1,2,3}; int arr[5] {0};字符串char str[] hello;指针int *p NULL; int *p a;定义后再赋值 普通赋值不是初始化。二、字符串赋值正确方式定义时初始化char str[10] hello;后期赋值必须用strcpy#include string.h char str[10]; strcpy(str, hello);错误写法char str[10]; str hello; // 错误数组名不能直接赋值字符串必须以\0结尾否则不是合法字符串。一句话记定义能用 后期用 strcpy。变量分类 区别const char* pieces[] {elephant,tiger,cat,mouse};只讲最核心、最常考的 4 种变量区别1. 局部变量定义位置函数内部 / 代码块内部生命周期进入函数创建出函数销毁初始值随机垃圾值作用域只在本函数 / 本代码块内能用2. 全局变量定义位置函数外面生命周期整个程序运行期间都存在初始值自动为 0作用域整个工程所有函数都能用3. static 静态局部变量定义位置函数内部 static生命周期程序全程存在只初始化一次初始值自动为 0特点多次调用函数值会保留上一次结果4. static 静态全局变量定义位置函数外面 static作用域只在本文件内有效其他文件不能用目的防止全局变量名字冲突一句话速记局部用完就丢值随机全局全程都在值为 0静态局部函数内常驻值保留静态全局只在本文件有效三、数组初始化以 int 数组为例1. 完全初始化最常用int arr[5] {1, 2, 3, 4, 5};2. 部分初始化剩下自动补 0int arr[5] {1, 2};结果1 2 0 0 03. 不写长度自动算大小int arr[] {10, 20, 30};编译器自己算长度 3。4. 全置 0超级常用int arr[5] {0};整个数组都是 0。四、字符串初始化重点C 语言字符串就是char数组必须以\0结尾。1. 最常用、最推荐char str[] hello;大小自动算6内容h e l l o \02. 用字符数组一个个写了解char str[] {h,e,l,l,o,\0};必须手动写\0不然不是字符串。3. 指针方式常用char *str hello;注意这是字符串常量不能改内容。4. 指定大小char str[10] hello;后面自动补\0剩下填 0。五、你必须背下来的 4 句int arr[5] {0};→ 全 0int arr[] {1,2,3};→ 自动长度char str[] hello;→ 最标准字符串char *str hello;→ 指针字符串三,switch 完整结构switch (变量) { case 常量1: 语句; break; case 常量2: 语句; break; default: 语句; break; }给你一个能直接背的小例子int a 2; switch (a) { case 1: printf(星期一); break; case 2: printf(星期二); break; case 3: printf(星期三); break; default: printf(其他); break; }你只需要记住 3 条铁律超级重要switch 里面只能放整数、字符不能放 float、字符串每个 case 结束必须写 break不然会 “穿透” 往下跑default 可要可不要但写上更安全
C语言刷题总结
一,刷题一.基础(区分float/double,字符/字符串)float / doublefloat4字节小数后加 f3.14fdouble8字节默认小数类型3.14%f / %lfprintf统一用 %ffloat、double 都可以scanffloat → %f,double → %lf输出一位小数C语言printf(%.1f, 变量); 例 printf(%.1f, 3.1415); → 输出 3.1%c字符/ %s字符串%cchar ch- scanf必须加 %c, ch- printf不加- %schar str[]- scanf不加 %s, str- printf不加二.题目 noob5 复读机错误点1. 整数溢出变量 b 的范围是 -10^18 ≤ b ≤ 10^18 使用 int 类型会溢出。2. 输入缓冲区残留读取浮点数后缓冲区的换行符被后续 %c 读取导致字符输入错误。修正方案1. 类型匹配将 int b 改为 long long b 输入输出用 %lld 。2. 清除缓冲区字符输入改为 scanf( %c, d); 用空格跳过换行符。核心知识点- long long 用于存储超大整数对应格式符 %lld 。- %c 会读取换行符需在格式串前加空格跳过空白字符。- 浮点数输出保留一位小数用 %.1f 。三,字符串核心结论1. 初始化定义时赋值一步可用 直接给字符串 char str[10] abc;2. 赋值定义后赋值两种不能用 只能用- scanf(%s, str); 输入赋值- strcpy(str, abc); 函数复制3. scanf(%s)可给字符数组赋值但不能读空格有溢出风险4. 字符数组不初始化时局部数组存随机值建议 char str[100] {0}; 初始化5. 数组名本身是首地址 scanf/printf 用 %s 时不加 四,疫情死亡率计算C语言核心总结四大必记关键点易错点1. 数据类型c,d 上限10^7必须用 long long int 易溢出输入格式符 %lld2. 计算强转必须 (double)d / c * 100 强转 double 不可省否则整数除法结果为03. 输出百分号 printf 中用 %% 输出单个 % 格式 %.3f%%4. 函数封装计算逻辑抽独立函数形参名任意作用域独立函数名与变量名可重复不建议五,平方根编程题坑点复盘与思想误区一、这道题里的具体坑点1. 函数名非法使用减号- 错误写法 floor-sqrt- 问题本质C语言规定函数名、变量名只能由字母、数字和下划线 _ 组成减号 - 会被编译器识别为减法运算符。2. 遗漏头文件 #include math.h- 问题使用 sqrt() 函数却未包含对应的头文件导致编译器报“未定义的引用”错误。3. 浮点数精度的潜在风险- 风险当输入值 n 非常大时浮点数计算可能存在精度丢失导致 sqrt(n) 的结果有误差。4. 数据类型选择不严谨- 风险如果输入变量 n 选用 int 类型当 n 接近 10^9 时会发生溢出。二、思想本质上的误区1. 惯性思维凭直觉写代码- 表现把日常写法如 floor-sqrt 直接套用在函数名上忽略了编程语言的严格规则。- 根源没有建立“编程世界有自己一套规则”的意识而是用生活中的直觉去写代码。2. 只关注核心逻辑忽略配套细节- 表现只想着“计算平方根再转成整数”这个核心功能却忘了检查头文件、变量类型等“配套设施”。- 根源缺乏“完整工程”思维默认编译器“应该都懂”而不是主动确保代码的完整性。3. 默认“没问题”缺乏风险预判- 表现认为“强转肯定能向下取整”但没思考过浮点数精度问题觉得 int 够用但没看题目给的输入范围。- 根源存在侥幸心理依赖“当前场景没问题”而不是追求“通用、严谨的解决方案”。六,反向输出四位数一、数学拆分法核心- 千位 n / 1000- 百位 n / 100 % 10- 十位 n / 10 % 10- 个位 n % 10- 输出 个位 十位 百位 千位二、字符串法核心- 用 sprintf(s, %d, n) 把数字转成字符串- 倒序输出 s[3] s[2] s[1] s[0]- 需头文件 #include string.h三、关键坑点必记1. 不能用整数反转会丢前导零2. 字符串数组要开 5 位存 \0 3. 函数名不能用减号只能用字母、数字、下划线4. 输出 % 要写 %%七,绕距问题踩坑总结一、核心坑点1. 类型不匹配对浮点数改用 fabs() 取绝对值。2. 依赖直觉凭习惯用 abs() 忽略了整数/浮点数的函数差异。3. 命名不严谨局部变量与参数名冲突增加了阅读和维护成本。二、思想本质- 未建立类型优先的编程思维写代码时只关注逻辑忽略了类型匹配。- 缺乏写完即自查的习惯依赖编译报错来发现问题而不是主动检查。八,循环问题错误原因总结精简版1. 先加1再取余 (d 1) % 7 会把周日d6算成0和题目要求的1~7范围不符必须额外用 if 把0改成7。2. 先取余再加1 (d % 7) 1 先把d映射到0~6再加1自然回到1~7一步到位不用判断。核心规律处理1~N的循环序列时- 先把数映射到0~N-1用 x % N 再做加减最后1回到1~N。- 这样可以避免0的问题代码更简洁。九,比较大小求三个整数最大/最小值的两种简洁写法方法一三目运算符法一行搞定三目运算符 条件 ? 真 : 假 可以让代码更紧凑逻辑清晰。// 先比较前两个数得到临时最大/最小值int max (a b) ? a : b;int min (a b) ? a : b;// 再用临时值和第三个数比较得到最终结果max (max c) ? max : c;min (min c) ? min : c;方法二标准库函数法最省事C 语言的标准库提供了 fmax 和 fmin 函数需要包含 math.h 可以直接求最大/最小值代码最简洁。// 嵌套调用函数直接得到三个数的最大/最小值int max fmax(fmax(a, b), c);int min fmin(fmin(a, b), c);十,判断素数问题:scanf读取方法,1. 最朴素的试除法根据素数定义大于1且只能被1和自身整除。- 对一个数 n从 2 到 n-1 逐个检查是否能整除 n。- 如果都不能整除n 就是素数否则是合数。int isPrime(int n) {if (n 1) return 0; // 1及以下不是素数for (int i 2; i n; i) {if (n % i 0) {return 0; // 能被整除不是素数}}return 1; // 都不能整除是素数}缺点效率极低当 n 很大时比如 10^5循环次数太多会超时。2. 优化版试除法核心优化关键思路如果 n 有一个大于 \sqrt{n} 的因数那它必然有一个小于 \sqrt{n} 的因数。所以我们只需要检查到 \sqrt{n} 就够了循环次数大幅减少。#include math.hint isPrime(int n) {if (n 1) return 0;if (n 2) return 1; // 2是唯一的偶素数if (n % 2 0) return 0; // 大于2的偶数都不是素数直接排除for (int i 3; i sqrt(n); i 2) { // 只检查奇数if (n % i 0) {return 0;}}return 1;}优化点1. 范围减半从 n-1 缩小到 \sqrt{n}。2. 跳过偶数除了2所有偶数都不是素数所以从3开始每次2只检查奇数。3. 更高级的算法可选当 n 非常大比如 10^{18}时试除法也不够用了这时会用到更高效的算法比如- Miller-Rabin 素性测试一种概率性算法速度极快常用于大数判断。- 埃氏筛法 / 欧拉筛法如果需要判断很多数是否为素数可以先筛出所有素数再直接查表。十一,奇偶交替数列核心问题在 for 循环体内修改了循环变量 i 破坏了循环的确定性导致逻辑混乱甚至死循环。正确做法循环变量 i 只由 for 语句的 i 控制不要在循环体内修改它需要取反或变换时用临时变量承载。十二,找最大/最小值时的初始化问题- 核心痛点不知道如何给 max / min 赋初值纠结“第一个数怎么处理”。- 本质给 max 一个足够小的初值给 min 一个足够大的初值保证第一个数一定能更新它们。- 常用方法- 用 limits.h 里的 INT_MIN / INT_MAX 最稳妥。- 手动设一个比题目范围更极端的数如 -1e9 / 1e9 。- 也可以先读第一个数把它作为初值再从第二个数开始比较。十三,斐波那契数列-递归十四,数位之和int swzh(int n){int sum0;while(n0){sumn%10;nn/10;}return sum;}十五,二维斐波那契数列刷题错误总结1. 数组定义错误- 错误用变量 n 、 m 定义数组大小如 long long a[n][m] 。- 原因C 语言数组大小必须是编译期常量不能用变量。- 修正定义固定大小数组 long long a[1001][1001] 或使用动态内存分配。2. 数据类型选择错误- 错误使用 int 存储中间结果。- 原因数值增长极快 int 范围不足会导致溢出。- 修正使用 long long 类型存储数组元素。3. 取模时机错误- 错误仅在最后输出时取模。- 原因中间加法结果会远超数据类型范围导致溢出和结果错误。- 修正每一步加法后立即取模如 a[i][j] (a[i-1][j] a[i][j-1]) % MOD 。十六,神秘石像的镜像序列 刷题错误总结1. 对 cnt 计数时机的理解偏差核心错误- 错误误以为终止符 0 会被计入 cnt 导致对有效数字个数的判断出现偏差。- 原因代码中 a[cnt] digit; 是先赋值再自增当读到 0 时直接 break 0 并未存入数组 cnt 的值恰好等于有效数字的个数。- 修正明确 cnt 是有效数字的计数数组有效下标是 0 到 cnt-1 输出时只需从 cnt-1 开始倒序即可。2. 循环范围判断错误- 错误使用 while(cnt 0) 作为输出循环的条件。- 原因在修正时只修改了 printf 中的下标却忘记同步修改循环条件。当 cnt0 时会尝试访问 a[-1] 导致数组越界和未定义行为。- 修正将循环条件改为 while(cnt 0) 确保只遍历有效元素。十七,约瑟夫环暴力解法#include stdio.h int main() { int n,k,m; scanf(%d %d %d,n,k,m); int a[100]{0}; int posk; int out0; int cnt0; while(outn-1){ if(a[pos]0){ cnt; if(cntm){ a[pos]-1; out; cnt0; } } pos; if(posn){ pos0; } } for(int i0;in;i){ if(a[i]0){ printf(%d\n,i); break; } } return 0; }十八,字符串赋值#include stdio.h #includestring.h int main() { char s[1000002]{0}; fgets(s,1000002,stdin); int lenstrlen(s); if(s[len-1]\n){ s[len-1]\0; } for(int i0;s[i]!\0;i){ if(s[i]5){ s[i]*; } } printf(%s\n,s); return 0; }fgetsstrlen十九,求阶乘易错点二,补基础知识数据类型:1.基本数据类型C 语言数据类型主要分为四大类决定了变量的存储大小、取值范围和可执行操作。修饰符signed/unsigned控制是否有符号默认signed。unsigned类型所有位都用于表示数值范围翻倍如unsigned char为 0~255。const定义常量值不可修改。例:const int a 10;2. 构造数据类型自定义类型由基本类型或其他构造类型组合而成数组相同类型元素的有序集合如int arr[5]。结构体struct不同类型成员的集合用于表示复杂对象如学生、员工。一,结构体基本格式 struct 结构体名{ 类型 成员1; 类型 成员2; ... .... } struct Student{ int id; char name[20]; float score; } struct Student stu1; 二,定义结构体变量 struct 结构体名{ 成员; }变量一,变量二 struct Student{ int id; char name[20]; float score; }stu1,stu2; 三,给结构体起别名(最常用) typedef struct Student{ int id; char name[20]; float score; }Stu;共用体union所有成员共享同一块内存空间同一时间只能存储一个成员。枚举enum定义一组命名的整型常量提高代码可读性如enum Color {RED, GREEN, BLUE};。3. 指针类型本质存储内存地址的变量。声明类型 *变量名如int *p表示指向int类型的指针。核心操作取地址运算符获取变量的内存地址。*解引用运算符通过地址访问内存中的值。int *p a;printf(%d,*p);4. 空类型void表示 “无类型”主要用于函数返回值void func()表示函数不返回任何值。函数参数func(void)表示函数不接受任何参数。无类型指针void *p可以指向任意类型的数据但使用前需强制类型转换。核心要点大小依赖数据类型的字节数与操作系统和编译器有关使用sizeof()运算符可精确获取。类型安全C 语言是强类型语言变量必须先声明类型才能使用不同类型赋值需注意隐式转换规则。内存布局理解数据类型是掌握内存管理、指针操作和结构体对齐的基础。初始化 字符串赋值一、初始化定义变量时直接赋值 初始化。局部变量不初始化随机垃圾值。全局 / 静态变量不初始化自动为 0。常用初始化基本类型int a 10; char c a;数组int arr[5] {1,2,3}; int arr[5] {0};字符串char str[] hello;指针int *p NULL; int *p a;定义后再赋值 普通赋值不是初始化。二、字符串赋值正确方式定义时初始化char str[10] hello;后期赋值必须用strcpy#include string.h char str[10]; strcpy(str, hello);错误写法char str[10]; str hello; // 错误数组名不能直接赋值字符串必须以\0结尾否则不是合法字符串。一句话记定义能用 后期用 strcpy。变量分类 区别const char* pieces[] {elephant,tiger,cat,mouse};只讲最核心、最常考的 4 种变量区别1. 局部变量定义位置函数内部 / 代码块内部生命周期进入函数创建出函数销毁初始值随机垃圾值作用域只在本函数 / 本代码块内能用2. 全局变量定义位置函数外面生命周期整个程序运行期间都存在初始值自动为 0作用域整个工程所有函数都能用3. static 静态局部变量定义位置函数内部 static生命周期程序全程存在只初始化一次初始值自动为 0特点多次调用函数值会保留上一次结果4. static 静态全局变量定义位置函数外面 static作用域只在本文件内有效其他文件不能用目的防止全局变量名字冲突一句话速记局部用完就丢值随机全局全程都在值为 0静态局部函数内常驻值保留静态全局只在本文件有效三、数组初始化以 int 数组为例1. 完全初始化最常用int arr[5] {1, 2, 3, 4, 5};2. 部分初始化剩下自动补 0int arr[5] {1, 2};结果1 2 0 0 03. 不写长度自动算大小int arr[] {10, 20, 30};编译器自己算长度 3。4. 全置 0超级常用int arr[5] {0};整个数组都是 0。四、字符串初始化重点C 语言字符串就是char数组必须以\0结尾。1. 最常用、最推荐char str[] hello;大小自动算6内容h e l l o \02. 用字符数组一个个写了解char str[] {h,e,l,l,o,\0};必须手动写\0不然不是字符串。3. 指针方式常用char *str hello;注意这是字符串常量不能改内容。4. 指定大小char str[10] hello;后面自动补\0剩下填 0。五、你必须背下来的 4 句int arr[5] {0};→ 全 0int arr[] {1,2,3};→ 自动长度char str[] hello;→ 最标准字符串char *str hello;→ 指针字符串三,switch 完整结构switch (变量) { case 常量1: 语句; break; case 常量2: 语句; break; default: 语句; break; }给你一个能直接背的小例子int a 2; switch (a) { case 1: printf(星期一); break; case 2: printf(星期二); break; case 3: printf(星期三); break; default: printf(其他); break; }你只需要记住 3 条铁律超级重要switch 里面只能放整数、字符不能放 float、字符串每个 case 结束必须写 break不然会 “穿透” 往下跑default 可要可不要但写上更安全