端午大礼包 - C 语言练习题完整解析
本篇文章整理了 C 语言”端午大礼包”练习题共 12 道,分为三个部分:
- 填空题(3 道):在
SPACE标记处填入正确代码 - 改错题(5 道):找出
FOUND标记处的错误并修正 - 编程题(4 道):在
Program标记处编写函数实现
每道题均包含题目描述、解题思路、完整代码(带详细注释)、错误分析(改错题)、关键知识点。涉及的考点覆盖字符串处理、指针运算、数组操作、ASCII 码、循环结构等 C 语言核心知识。
一、填空题
填空题要求在 /***********SPACE***********/ 标记的位置填入正确的代码,使程序能正常运行并得到预期结果。
填空题1 - 字符串中数字累加和
题目描述
给定程序中,函数 fun 的功能是:将形参 s 所指字符串中的数字字符转换成对应的数值,计算出这些数值的累加和作为函数值返回。
例如,形参 s 所指的字符串为 abs5def126jkm8,程序执行后的输出结果为 22。
计算过程:5 + 1 + 2 + 6 + 8 = 22
解题思路
- 遍历字符串中的每一个字符
- 使用
isdigit()函数判断当前字符是否为数字字符('0'~'9') - 若是数字字符,则通过
*s - 48(或*s - '0')将字符转换为对应的数值 - 将转换后的数值累加到
sum中 - 移动指针到下一个字符,直到字符串结束
- 最后返回累加和
完整代码
#include <stdio.h>#include <string.h>#include <ctype.h>
int fun(char* s){ int sum = 0; while (*s) // 遍历字符串,直到遇到 '\0' { if (isdigit(*s)) // isdigit() 判断是否为数字字符 '0'~'9' /***********SPACE***********/ sum += *s - 48; // 【填空1】数字字符转数值并累加 // '0' 的 ASCII 码是 48,所以 *s - 48 等价于 *s - '0' // 例如 '5' 的 ASCII 码是 53,53 - 48 = 5 /***********SPACE***********/ s++; // 【填空2】指针后移,处理下一个字符 } /***********SPACE***********/ return sum; // 【填空3】返回累加和}
main(){ char s[81]; int n; printf("\nEnter a string:\n\n"); gets(s); n = fun(s); printf("\nThe result is: %d\n\n", n);}填空答案
| 填空 | 答案 | 说明 |
|---|---|---|
| 填空1 | sum += *s - 48; | 字符转数值并累加,48 是 '0' 的 ASCII 码 |
| 填空2 | s++; | 指针后移到下一个字符 |
| 填空3 | return sum; | 返回累加结果 |
关键知识点
isdigit()函数:声明在<ctype.h>,用于判断字符是否为十进制数字字符- 字符转数值:数字字符
'0'57,因此'9'的 ASCII 码为 48ch - '0'或ch - 48可得到对应数值 - 指针遍历字符串:通过
while (*s)配合s++逐个访问字符,直到遇到字符串结束符'\0'
填空题2 - 插入字符
题目描述
下列给定程序中,函数 fun 的功能是:在形参 s 所指字符串中寻找与参数 c 相同的字符,并在其后插入一个与之相同的字符,若找不到相同的字符则不做任何处理。
例如:若 s 所指字符串为 "baacda",c 中的字符为 a,执行后 s 所指字符串为 "baaaacdaa"。
插入过程:每个
a后面都插入一个a,所以 3 个a变成对应位置后各插一个
解题思路
- 用
for循环遍历字符串s中的每个字符 - 当
s[i] == c时,需要在该位置后插入一个字符c - 插入前需要计算从当前位置到字符串末尾的长度
n(用于确定后移范围) - 将插入位置后的所有字符整体后移一位,腾出插入空间
- 在腾出的位置写入字符
c - 插入后
i = i + 1跳过刚插入的字符,避免被当作”原字符”再次处理导致死循环
完整代码
#include <stdio.h>
void fun(char* s, char c){ int i, j, n; /***********SPACE***********/ for (i = 0; s[i] != '\0'; i++) // 【填空1】遍历整个字符串 if (s[i] == c) // 找到与 c 相同的字符 { /***********SPACE***********/ n = i; // 【填空2】从当前位置开始计算字符串剩余长度 while (s[i + 1 + n] != '\0') // 注意:此循环计算的是 i+1+n 位置 n++; // n 最终表示从 i 开始到结尾的字符数(不含'\0') for (j = i + n + 1; j > i; j--) // 从后往前把字符后移一位 s[j + 1] = s[j]; // s[j+1] = s[j],腾出 i+1 的位置 /***********SPACE***********/ s[j + 1] = c; // 【填空3】在原字符后插入相同的字符 c i = i + 1; // 跳过刚插入的字符,避免重复处理 }}
main(){ char s[80] = "baacda", c; printf("\nThe string: %s\n", s); printf("\nInput a character: "); scanf("%c", &c); fun(s, c); printf("\nThe result is: %s\n", s);}填空答案
| 填空 | 答案 | 说明 |
|---|---|---|
| 填空1 | for (i = 0; s[i] != '\0'; i++) | 遍历字符串直到结束符 |
| 填空2 | n = i; | 初始化 n 为当前位置,配合后续 while 计算剩余长度 |
| 填空3 | s[j + 1] = c; | 在腾出的位置插入字符 c |
关键知识点
- 字符插入操作:插入前必须先将后续字符后移,从后往前移动避免覆盖
- 避免重复处理:插入字符后要将循环变量
i加 1,跳过新插入的字符 - 字符串后移技巧:
for (j = end; j > pos; j--) s[j+1] = s[j];是经典的字符后移模板
填空题3 - 最长字符串
题目描述
给定程序中,函数 fun 的功能是:求出形参 ss 所指字符串数组中最长字符串的长度,其余字符串左边用字符 * 补齐,使其与最长的字符串等长。字符串数组中共有 M 个字符串,且串长小于 N。
例如字符串数组 {"shanghai","guangzhou","beijing","tianjing","cchongqing"},最长的是 "cchongqing"(10 个字符),其余字符串左边补 * 到 10 个字符。
解题思路
- 第一遍遍历:找出最长字符串的长度
n及其索引k - 第二遍遍历:对每个非最长字符串
ss[i](i != k):- 先将该字符串的内容(含
'\0')整体右移到与最长串对齐的位置 - 再在左侧空出的位置填充字符
'*'
- 先将该字符串的内容(含
完整代码
#include <stdio.h>#include <string.h>
#define M 5#define N 20
void fun(char (*ss)[N]){ int i, j, k = 0, n, m, len; // 第一遍:找出最长字符串及其长度 for (i = 0; i < M; i++) { len = strlen(ss[i]); if (i == 0) n = len; // 第一个字符串的长度作为初始值 if (len > n) { /***********SPACE***********/ n = len; k = i; // 【填空1】更新最大长度 n 和最长串索引 k } } // 第二遍:对其余字符串左补 '*' for (i = 0; i < M; i++) if (i != k) // 跳过最长字符串本身 { m = n; // m 用于从右端开始放置字符 len = strlen(ss[i]); // 当前字符串长度 /***********SPACE***********/ for (j = len; j >= 0; j--) // 【填空2】将原字符串(含'\0')右移到对齐位置 ss[i][m--] = ss[i][j]; // 从 ss[i][len] 开始(含'\0'),整体右移 for (j = 0; j < n - len; j++) // 左侧空出的 n-len 个位置 /***********SPACE***********/ ss[i][j] = '*'; // 【填空3】填充 '*' }}
main(){ char ss[M][N] = { "shanghai","guangzhou","beijing","tianjing","cchongqing" }; int i; printf("\nThe original strings are :\n"); for (i = 0; i < M; i++) printf("%s\n", ss[i]); printf("\n"); fun(ss); printf("\nThe result:\n"); for (i = 0; i < M; i++) printf("%s\n", ss[i]);}运行结果示例
The original strings are :shanghaiguangzhoubeijingtianjingcchongqing
The result:**shanghaiguangzhou***beijing*tianjingcchongqing填空答案
| 填空 | 答案 | 说明 |
|---|---|---|
| 填空1 | n = len; k = i; | 记录最长串的长度和索引 |
| 填空2 | for (j = len; j >= 0; j--) | 从字符串末尾(含 '\0')开始右移 |
| 填空3 | ss[i][j] = '*'; | 左侧空位填充 '*' |
关键知识点
- 二维字符数组作函数参数:
char (*ss)[N]是指向含N个元素的字符数组的指针,等价于char ss[][N] - 字符串右对齐填充:先右移原内容(含结束符
'\0'),再在左侧补字符 strlen()函数:声明在<string.h>,返回字符串长度(不含'\0')
二、改错题
改错题在 /***********FOUND***********/ 标记处存在错误,需要找出并修正。下面每道题先分析可能的错误形式,再给出正确代码。
改错题1 - 统计0的个数
题目描述
下列给定程序中,函数 fun 实现的功能是:统计一个无符号整数中各位数字值为 0 的个数,通过形参传回主函数,并把该整数中各位上最大的数字值作为函数值返回。
例如:若输入无符号整数 30800,则数字值为 0 的位的个数为 3,各位上数字值最大的是 8。
30800 的各位:3、0、8、0、0,其中 0 出现 3 次,最大数字是 8
错误分析
| 错误位置 | 可能的错误形式 | 错误原因 | 正确写法 |
|---|---|---|---|
| FOUND 1 | if (t = 0) | 把比较运算符 == 误写成赋值运算符 =,导致条件恒为假(且破坏 t 的值) | if (t == 0) |
| FOUND 2 | zero = count; | zero 是指针,应通过解引用 *zero 修改主调函数的变量;直接赋值给指针是错误的 | *zero = count; |
解题思路
- 使用
do-while循环依次取出整数的每一位(至少执行一次,处理n=0的情况) n % 10取最低位数字,n / 10去掉最低位- 统计值为
0的位数到count - 同时记录出现过的最大数字到
max - 通过指针参数
*zero返回 0 的个数,函数返回最大数字
完整代码
#include <stdio.h>
int fun(unsigned n, int* zero){ int count = 0, max = 0, t; do { t = n % 10; // 取出最低位数字 /***********FOUND***********/ if (t == 0) // 【修正】比较运算符用 ==,不能用 = count++; // 若该位为 0,计数器加 1 if (max < t) // 若该位比 max 大,更新 max max = t; n = n / 10; // 去掉最低位 } while (n); // 直到 n 为 0 时结束循环 /***********FOUND***********/ *zero = count; // 【修正】通过解引用指针,把 count 传回主函数 return max; // 返回最大数字}
main(){ unsigned n; int zero, max; printf("\nInput n(unsigned): "); scanf("%d", &n); max = fun(n, &zero); printf("\nThe result: max=%d\n zero=%d\n", max, zero);}关键知识点
==与=的区别:==是比较运算符,=是赋值运算符,在if条件中混用是常见错误- 指针参数传回结果:要通过函数参数修改主调函数的变量,必须传入变量地址,并在函数内通过
*指针解引用 do-while循环:先执行后判断,至少执行一次,适合”至少处理一位”的场景- 取位运算:
n % 10取个位,n / 10去个位,是处理整数各位的经典套路
改错题2 - 第一个字母改大写
题目描述
下列给定程序的功能是:读入一个英文文本行,将其中每个单词的第一个字母改成大写,然后输出此文本行(这里”单词”是指由空格隔开的字符串)。
例如:若输入 "I am a student to take the examination",则应输出 "I Am A Student To Take The Examination"。
错误分析
| 错误位置 | 可能的错误形式 | 错误原因 | 正确写法 |
|---|---|---|---|
| FOUND | void upfst(char p) | 参数应为字符指针(数组名),写成 char p 只能传单个字符,无法遍历字符串 | void upfst(char* p) |
解题思路
- 使用标志位
k区分当前是否在单词内部:k = 0:表示在单词开头(下一个非空格字符是首字母,需大写)k = 1:表示已在单词中间
- 遍历字符串:
- 若
k == 1(在单词中):遇到空格则k = 0,表示即将进入新单词 - 若
k == 0(在单词开头):遇到非空格字符,则将其转为大写并置k = 1
- 若
- 使用
toupper()函数将小写字母转换为大写
完整代码
#include <stdlib.h>#include <string.h>#include <conio.h>#include <ctype.h>#include <stdio.h>#include <string.h>
/***********FOUND***********/void upfst(char* p) // 【修正】参数必须是 char* 指针,才能遍历字符串{ int k = 0; // k=0 表示在单词开头,k=1 表示在单词中间 for (; *p; p++) // 遍历字符串直到 '\0' { if (k) // 若已在单词中间 { if (*p == ' ') // 遇到空格,说明下一个非空格是新单词首字母 k = 0; } else // 若在单词开头 { if (*p != ' ') // 当前字符非空格,即是单词首字母 { k = 1; // 标记已进入单词 *p = toupper(*p); // 将首字母转为大写 } } }}
void main(){ char chrstr[81]; system("CLS"); printf("\nPlease enter an English text line: "); gets(chrstr); printf("\nBofore changing:\n %s", chrstr); upfst(chrstr); // 数组名作实参,传递首地址 printf("\nAfter changing:\n %s\n", chrstr);}关键知识点
- 数组作函数参数:数组名传递时退化为指针,形参必须声明为
char*或char[],不能是char toupper()函数:声明在<ctype.h>,将小写字母转换为大写,非小写字母原样返回- 状态标志位:用一个整型变量
k记录”是否在单词内”的状态,是字符串处理的常用技巧
改错题3 - 查找字符串最后出现地址
题目描述
下列给定程序中函数 fun 的功能是:求出 s 所指字符串中最后一次出现的 t 所指字符串的地址,并通过函数值返回;若未找到,则函数值为 NULL。
例如:当字符串 s 中内容为 "abcdabfabcdx",t 中内容为 "ab" 时,输出结果应是 "abcdx"(最后一次出现的 ab 之后的内容)。当 t 中内容为 "abd" 时,输出 "Not found!"。
错误分析
| 错误位置 | 可能的错误形式 | 错误原因 | 正确写法 |
|---|---|---|---|
| FOUND 1 | a = s; 或缺少初始化 | 若初始化为 s,则未找到时返回的不是 NULL;若不初始化,a 是野指针 | a = NULL; |
| FOUND 2 | if (*r = *p) 或 if (r == p) | = 是赋值(恒为真导致死循环);r == p 比较的是指针地址而非字符内容 | if (*r == *p) |
解题思路
- 初始化
a = NULL,表示尚未找到匹配 - 外层循环:以
s中每个字符作为起始位置 - 内层循环:从该位置开始,逐个字符与
t比较- 字符相同则
r++、p++继续比较下一个 - 字符不同则
break退出内层循环
- 字符相同则
- 内层循环结束后,若
*r == '\0'说明t已全部匹配,更新a = s记录本次匹配地址 s++移动到下一个起始位置继续查找- 由于每次匹配都更新
a,循环结束后a保存的是最后一次匹配的地址
完整代码
#include <stdio.h>#include <string.h>
char* fun(char* s, char* t){ char* p, * r, * a; /***********FOUND***********/ a = NULL; // 【修正】初始化为 NULL,未找到时返回 NULL while (*s) // 遍历 s 中每个位置作为起始点 { p = s; // p 指向 s 当前位置 r = t; // r 指向 t 开头 while (*r) // 只要比对未到 t 的结尾 /***********FOUND***********/ if (*r == *p) // 【修正】比较字符内容,用 == 而非 = { r++; // t 的指针后移 p++; // s 的指针后移 } else // 字符不匹配 break; // 退出内层循环 if (*r == '\0') // 若 t 全部匹配完成 a = s; // 更新 a 为当前匹配的首地址 s++; // s 后移一位,继续查找下一个位置 } return a; // 返回最后一次匹配的首地址(或 NULL)}
main(){ char s[100], t[100], * p; printf("\nPlease enter string S :"); scanf("%s", s); printf("\nPlease enter substring t :"); scanf("%s", t); p = fun(s, t); if (p) // 若 p 非 NULL printf("\nThe result is : %s\n", p); else // 若 p 为 NULL printf("\nNot found !\n");}关键知识点
- 字符串查找算法:双层循环实现子串查找,外层遍历主串起点,内层逐字符比对
- “最后一次”的实现技巧:不中断循环,每次找到都更新记录变量,循环结束后自然得到最后一次的结果
NULL指针:表示”未找到”的常用约定,使用前需判断是否为NULL==与=的陷阱:在if条件中误用=会导致赋值且条件恒为该值的真值
改错题4 - 找到最长子串
题目描述
下列给定程序中函数 fun 的功能是:从 N 个字符串中找出最长的串,并将其地址作为函数值返回。各字符串在主函数中输入,并放入一个字符串数组中。
错误分析
| 错误位置 | 可能的错误形式 | 错误原因 | 正确写法 |
|---|---|---|---|
| FOUND 1 | char fun(char (*sq)[M]) | 返回类型应为 char*(返回的是字符串地址),写成 char 只能返回单个字符 | char* fun(char (*sq)[M]) |
| FOUND 2 | return sq; 或缺少 return | sq 是整个数组指针,类型不匹配;缺少 return 则函数无返回值 | return sp; |
解题思路
- 函数参数
char (*sq)[M]是指向含M个元素的字符数组的指针,即指向二维字符数组的行 - 初始化
sp = sq[0],让sp指向第一个字符串 - 遍历所有
N个字符串,用strlen()比较长度 - 若发现更长的字符串,则更新
sp为该字符串的地址sq[i] - 循环结束后
sp指向最长字符串,返回sp
完整代码
#include <stdio.h>#include <string.h>
#define N 5#define M 81
/***********FOUND***********/char* fun(char (*sq)[M]) // 【修正】返回类型为 char*,因为要返回字符串地址{ int i; char* sp; sp = sq[0]; // 初始化 sp 指向第一个字符串 for (i = 0; i < N; i++) if (strlen(sp) < strlen(sq[i])) // 若当前最长串比第 i 个串短 sp = sq[i]; // 更新 sp 为第 i 个串的地址 /***********FOUND***********/ return sp; // 【修正】返回 sp(最长串地址),不能返回 sq}
main(){ char str[N][M], * longest; int i; printf("Enter %d lines :\n", N); for (i = 0; i < N; i++) gets(str[i]); printf("\nThe %d string :\n", N); for (i = 0; i < N; i++) puts(str[i]); longest = fun(str); // str 是二维数组名,传递给 sq printf("\nThe longest string :\n"); puts(longest);}关键知识点
- 指向数组的指针:
char (*sq)[M]是”指向含 M 个 char 元素的数组的指针”,与char* sq[M](指针数组)完全不同 - 二维数组与指针:二维数组名
str作为实参传递时,形参声明为char (*sq)[M]或char sq[][M] - 返回字符串地址:函数返回类型声明为
char*,返回的字符串地址在主调函数中仍有效(因为指向的是主调函数中的数组)
改错题5 - 调整ASCII最大字符放首位
题目描述
下列给定程序中函数 fun 的功能是:从 p 所指字符串中找出 ASCII 码值最大的字符,将其放在第一个位置上,并将该字符前的原字符向后顺序移动。
例如:调用 fun 函数之前给字符串输入 "ABCDeFGH",调用后字符串中的内容应为 "eABCDFGH"。
‘e’ 的 ASCII 码(101)最大,原在位置 4,前移到首位后,“ABCD” 顺序后移一位
错误分析
| 错误位置 | 可能的错误形式 | 错误原因 | 正确写法 |
|---|---|---|---|
| FOUND 1 | q = p[i]; | p[i] 是字符值,应赋给 max;q 是指针,应保存地址 | q = p + i; |
| FOUND 2 | while (q < p) 或 while (q >= p) | 方向反了(q 在 p 之后,应 q > p);>= 会多移一位覆盖首位 | while (q > p) |
解题思路
- 第一次遍历:找出 ASCII 码最大的字符及其位置
- 假设第一个字符最大
max = p[0] - 遍历字符串,若发现更大的字符,更新
max并用指针q记录其地址q = p + i
- 假设第一个字符最大
- 第二次循环(字符后移):从最大字符位置
q向前,将前一个字符后移while (q > p):只要q还没退到首位*q = *(q - 1):把前一个字符复制到当前位置q--:指针前移
- 最后
p[0] = max,将最大字符放到首位
字符移动示例
以 "ABCDeFGH" 为例,max = 'e',q 指向 p[4]:
初始: A B C D e F G H ↑ p (q 指向 e)
第1次后移 (q=p+4): A B C D e F G H -> A B C D D F G H (把 D 复制到 e 位置)第2次后移 (q=p+3): A B C D D F G H -> A B C C D F G H (把 C 复制到 D 位置)第3次后移 (q=p+2): A B C C D F G H -> A B B C D F G H (把 B 复制到 C 位置)第4次后移 (q=p+1): A B B C D F G H -> A A B C D F G H (把 A 复制到 B 位置)现在 q == p,退出循环p[0] = max: e A B C D F G H (把 e 放到首位)完整代码
#include <stdio.h>
void fun(char* p){ char max, * q; int i = 0; max = p[i]; // 假设第一个字符最大 while (p[i] != 0) // 遍历字符串(0 即 '\0') { if (max < p[i]) // 若发现更大的字符 { max = p[i]; // 更新最大字符值 /***********FOUND***********/ q = p + i; // 【修正】q 是指针,要保存地址 p+i,不能赋字符值 } i++; } /***********FOUND***********/ while (q > p) // 【修正】q 在 p 之后,循环条件应为 q > p { *q = *(q - 1); // 把前一个字符后移到当前位置 q--; // 指针前移 } p[0] = max; // 将最大字符放到首位}
main(){ char str[80]; printf("Enter a string: "); gets(str); printf("\nThe original string: "); puts(str); fun(str); printf("\nThe string after moving: "); puts(str); printf("\n\n");}关键知识点
- 指针与数组的关系:
p + i等价于&p[i],是第i个元素的地址 - 字符顺序移动:从后往前逐个复制
*q = *(q-1); q--;,避免从前往后移动导致的覆盖问题 - ASCII 码比较:字符比较的本质是比较 ASCII 码值,小写字母(97
122)大于大写字母(6590)
三、编程题
编程题要求在 /**********Program**********/ 与 /********** End **********/ 之间编写函数实现,不能修改 main 函数和其他函数。
编程题1 - 二维数组变一维
题目描述
请编写函数 fun,该函数的功能是:将 M 行 N 列的二维数组中的字符数据,按列的顺序依次放到一个字符串中。
例如:若二维数组中的数据为
W W W WS S S SH H H H则字符串中的内容应是:WSHWSHWSHWSH。
按列顺序:先取第0列(W,S,H),再第1列(W,S,H)…共4列
解题思路
- 外层循环控制列
j从0到N-1 - 内层循环控制行
i从0到M-1 - 每次取出
s[i][j]放入一维数组b[k],k递增 - 全部放完后在末尾添加字符串结束符
'\0'
完整代码
#include<stdio.h>
#define M 3#define N 4
void fun(char (*s)[N], char* b){ /**********Program**********/ int i, j, k = 0; for (j = 0; j < N; j++) // 外层循环控制列(先列后行 = 按列顺序) { for (i = 0; i < M; i++) // 内层循环控制行 { b[k++] = s[i][j]; // 取第 j 列第 i 行的元素放入 b } } b[k] = '\0'; // 添加字符串结束符 /********** End **********/}
void main(){ char a[100]; char w[M][N] = { { 'W', 'W', 'W', 'W'},{'S', 'S', 'S', 'S'}, {'H', 'H', 'H', 'H'} }; int i, j; printf("The matrix:\n"); for (i = 0;i < M;i++) { for (j = 0;j < N;j++) printf("%3c", w[i][j]); printf("\n"); } fun(w, a); printf("The A string:\n"); puts(a); printf("\n\n");}关键知识点
- 二维数组按列遍历:外层循环列、内层循环行,即可实现按列优先顺序读取
- 二维数组作函数参数:
char (*s)[N]接收二维字符数组,第二维大小N必须指定 - 字符串结束符:手动构造字符串时,末尾必须添加
'\0',否则puts、printf("%s")等会越界读取
编程题2 - 删除字符
题目描述
编写函数 fun,其功能是:将 s 所指字符串中 ASCII 值为奇数的字符删除,剩余字符形成的新串放在 t 所指数组中。
例如:若 s 所指字符串中的内容为 "ABCDEFG12345",其中字符 A(ASCII 65,奇数)、字符 1(ASCII 49,奇数)都应当删除,其它依此类推。最后 t 所指的数组中的内容应是 "BDF24"。
保留偶数 ASCII 字符:B(66) D(68) F(70) 2(50) 4(52)
解题思路
- 遍历字符串
s中的每个字符 - 用
s[i] % 2 == 0判断 ASCII 值是否为偶数 - 将 ASCII 值为偶数的字符依次复制到数组
t中 - 注意:遍历结束后必须在
t末尾添加'\0',否则t不是合法字符串
易错点:原题代码未添加
'\0',会导致输出结果错误(t数组末尾有未初始化的脏数据)。下面给出修正后的完整版本。
完整代码
#include <stdio.h>#include <string.h>
void fun(char* s, char t[]){ /**********Program**********/ int i, j = 0; for (i = 0; s[i] != '\0'; i++) // 遍历字符串 s { if (s[i] % 2 == 0) // ASCII 值为偶数时保留 { t[j++] = s[i]; // 复制到 t 数组 } } t[j] = '\0'; // 必须添加字符串结束符! /********** End **********/}
void main(){ char s[100], t[100]; printf("\nPlease enter string S:"); scanf("%s", s); fun(s, t); printf("\nThe result is: %s\n", t);}关键知识点
- ASCII 码奇偶性判断:
ch % 2 == 0判断偶数,ch % 2 != 0判断奇数 - 字符过滤模板:用两个下标,
i遍历原串,j指向新串写入位置,符合条件的才复制 - 字符串结束符的重要性:构造新字符串必须以
'\0'结尾,否则字符串函数无法正确判断边界
编程题3 - 统计数字个数
题目描述
请编写函数 fun,其功能是:统计 s 所指字符串中的数字字符个数,并作为函数值返回。
例如:s 所指字符串中的内容是 "2def35adh25 3kjsdf 7/kj8655x",函数 fun 返回值为 11。
数字字符:2、3、5、2、5、3、7、8、6、5、5,共 11 个
解题思路
- 遍历字符串中的每个字符
- 使用条件
s[i] >= '0' && s[i] <= '9'判断是否为数字字符 - 每找到一个数字字符,计数器加 1
- 遍历结束后返回计数器的值
完整代码
#include <stdio.h>
int fun(char *s){ /**********Program**********/ int i, count = 0; for (i = 0; s[i] != '\0'; i++) // 遍历字符串 { if (s[i] >= '0' && s[i] <= '9') // 判断是否为数字字符 '0'~'9' { count++; // 计数器加 1 } } return count; // 返回数字字符个数 /********** End **********/}
void main(){ char *s = "2def35adh25 3kjsdf 7/kj8655x"; printf("%s\n", s); printf("%d\n", fun(s));}关键知识点
- 数字字符判断:
s[i] >= '0' && s[i] <= '9',也可使用isdigit(s[i])(需<ctype.h>) - 计数器模式:初始化
count = 0,满足条件时count++,最后返回count - 字符范围判断:利用字符的有序性,通过比较运算符判断字符属于哪个范围
编程题4 - 返回n-1的数
题目描述
编写函数 fun,w 是一个大于 10 的无符号整数,若 w 是 n(n≥2)位的整数,则函数求出 w 的后 n-1 位的数作为函数值返回。
例如:w 值为 5923,则函数返回 923;若 w 值为 923,则函数返回 23。
5923 有 4 位,返回后 3 位 923;923 有 3 位,返回后 2 位 23
解题思路
- 先计算
w的位数对应的 10 的幂t- 复制
w到n,循环n = n / 10直到n == 0,每次循环t *= 10 - 例如
w = 5923:循环 4 次后t = 10000(比w多一位)
- 复制
t / 10得到与w位数相同的 10 的幂(如1000)w % (t / 10)取余,得到去掉最高位后的数(如5923 % 1000 = 923)
计算过程示例
以 w = 5923 为例:
| 循环次数 | n 的值 | t 的值 |
|---|---|---|
| 初始 | 5923 | 1 |
| 第1次 | 592 | 10 |
| 第2次 | 59 | 100 |
| 第3次 | 5 | 1000 |
| 第4次 | 0 | 10000 |
循环结束,t = 10000,t / 10 = 1000,5923 % 1000 = 923。
完整代码
#include<conio.h>#include<stdio.h>#include<stdlib.h>
unsigned fun(unsigned w){ /**********Program**********/ int n = w, t = 1; // n 用于统计位数,t 用于累乘 10 while (n > 0) // 循环直到 n 为 0 { t = t * 10; // t 每次乘 10 n = n / 10; // n 去掉最低位 } // 循环结束后,t 是 w 位数 +1 位的 10 的幂 // 例如 w=5923(4位),t=10000(5位) return w % (t / 10); // t/10 得到与 w 同位的 10 的幂,取余去掉最高位 /********** End **********/}
void main(){ unsigned x; printf("Enter a unsigned integer number: "); scanf("%u", &x); printf("The original data is:%u\n", x); if (x < 10) // w 必须大于 10(至少 2 位) printf("Data error! "); else printf("The result :%u\n", fun(x));}关键知识点
- 求整数位数:通过
n = n / 10循环除以 10,直到为 0,循环次数即为位数 - 10 的幂计算:在统计位数的同时累乘 10,可得到对应位数的 10 的幂
- 取余去高位:
w % (10^(n-1))可以去掉最高位,保留后 n-1 位 %u格式符:用于输入输出无符号整数(unsigned)
总结
知识点回顾
| 类别 | 涉及知识点 |
|---|---|
| 字符串处理 | isdigit()、toupper()、strlen()、gets()、puts()、字符串结束符 '\0' |
| 指针 | 指针遍历字符串、指针参数传回结果(*p 解引用)、返回指针的函数、指向数组的指针 char (*p)[N] |
| 数组 | 二维数组按列遍历、二维数组作函数参数、字符数组操作 |
| ASCII 码 | 字符与数值转换(ch - '0')、ASCII 奇偶性判断、字符大小比较 |
| 循环结构 | do-while、while、for 的选用;双层循环实现子串查找 |
| 常见错误 | = 与 == 混用、指针未初始化、缺少 '\0'、参数类型错误(char 与 char*) |
解题技巧
- 填空题:先理解程序整体功能,再分析空格处应有的逻辑,注意变量类型匹配
- 改错题:重点关注
FOUND标记附近,常见错误类型有:运算符错误(=/==)、类型错误(指针/非指针)、初始化错误(NULL)、循环条件错误(方向、边界) - 编程题:理清输入输出和函数签名,先用伪代码描述算法,再翻译为 C 代码,注意边界处理和字符串结束符
易错点提醒
- 构造新字符串时必须在末尾添加
'\0' - 函数参数若要通过形参修改实参,必须传地址并用
*解引用 if条件中比较相等用==,赋值用=,二者不可混用- 指针使用前必须初始化,未找到目标时返回
NULL是良好习惯 - 二维数组作参数时,第二维大小必须指定(如
char (*s)[N])
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时












