练习8-2 计算两数的和与差

本题要求实现一个计算输入的两数的和与差的简单函数。
函数接口定义:

  1. void sum_diff( float op1, float op2, float *psum, float *pdiff );

其中op1op2是输入的两个实数,*psum*pdiff是计算得出的和与差。
裁判测试程序样例:

  1. #include <stdio.h>
  2. void sum_diff( float op1, float op2, float *psum, float *pdiff );
  3. int main()
  4. {
  5. float a, b, sum, diff;
  6. scanf("%f %f", &a, &b);
  7. sum_diff(a, b, &sum, &diff);
  8. printf("The sum is %.2f\nThe diff is %.2f\n", sum, diff);
  9. return 0;
  10. }
  11. /* 你的代码将被嵌在这里 */

输入样例:

  1. 4 6

输出样例:

  1. The sum is 10.00
  2. The diff is -2.00

解题思路:指针传参修改,非常简单。

  1. void sum_diff(float op1,float op2,float *psum,float *pdiff) {
  2. *psum = op1 + op2;
  3. *pdiff = op1 - op2;
  4. }

运行结果:

Case Hint Result Run Time Memory
0 sample等价,输入为正,输出有正负 Accepted 4 ms 384 KB
1 负数输入 Accepted 4 ms 296 KB
2 op1 = op2 = 0 Accepted 3 ms 224 KB

习题8-1 拆分实数的整数与小数部分

本题要求实现一个拆分实数的整数与小数部分的简单函数。
函数接口定义:

  1. void splitfloat( float x, int *intpart, float *fracpart );

其中x是被拆分的实数(0≤x<10000),`*intpart`和`*fracpart`分别是将实数x拆分出来的整数部分与小数部分。
裁判测试程序样例:

  1. #include <stdio.h>
  2. void splitfloat( float x, int *intpart, float *fracpart );
  3. int main()
  4. {
  5. float x, fracpart;
  6. int intpart;
  7. scanf("%f", &x);
  8. splitfloat(x, &intpart, &fracpart);
  9. printf("The integer part is %d\n", intpart);
  10. printf("The fractional part is %g\n", fracpart);
  11. return 0;
  12. }
  13. /* 你的代码将被嵌在这里 */

输入样例:

  1. 2.718

输出样例:

  1. The integer part is 2
  2. The fractional part is 0.718

解题步骤:考察强制类型转换和指针知识。

  • 整数部分:使用 (int)x 强制类型转换即可得到整数部分 intpart
  • 小数部分:用原来的浮点数 x - intpart 就得到小数部分。 :::tips 实际上这样操作是不对的,很容易发生精度问题。一般采用转换为字符串,也就是通过 "%f" 格式化为字符串形式获得整数和小数部分。但是本题主要目的在于考察指针通过函数赋值的操作,因此懒得转换为字符串后再转换回 int/float :::
    1. void splitfloat(float x, int *intpart, float *fracpart) {
    2. *intpart = (int)x;
    3. *fracpart = x - *intpart;
    4. }
    | Case | Hint | Result | Score | Run Time | Memory | | —- | —- | —- | —- | —- | —- | | 0 | sample,小数和整数部分都有 | Accepted | 9 | 3 ms | 384 KB | | 1 | 全为0 | Accepted | 1 | 2 ms | 296 KB | | 2 | 整数部分为0 | Accepted | 2 | 2 ms | 384 KB | | 3 | 小数部分为0 | Accepted | 2 | 2 ms | 368 KB | | 4 | x取最大 | Accepted | 1 | 3 ms | 224 KB |

习题8-5 使用函数实现字符串部分复制

本题要求编写函数,将输入字符串t中从第m个字符开始的全部字符复制到字符串s中。
函数接口定义:

  1. void strmcpy( char *t, int m, char *s );

函数strmcpy将输入字符串char *t中从第m个字符开始的全部字符复制到字符串char *s中。若m超过输入字符串的长度,则结果字符串应为空串。
裁判测试程序样例:

  1. #include <stdio.h>
  2. #define MAXN 20
  3. void strmcpy( char *t, int m, char *s );
  4. void ReadString( char s[] ); /* 由裁判实现,略去不表 */
  5. int main() {
  6. char t[MAXN], s[MAXN];
  7. int m;
  8. scanf("%d\n", &m);
  9. ReadString(t);
  10. strmcpy( t, m, s );
  11. printf("%s\n", s);
  12. return 0;
  13. }
  14. /* 你的代码将被嵌在这里 */

输入样例:

  1. 7
  2. happy new year

输出样例:

  1. new year

解题思路:题目给定的 m 是顺序个数,从 1 开始计数,因此等于下标 idx + 1

  1. 判断 m 与字符串长度 n 的关系:如果 PTA函数—指针 - 图1,则开始复制范围为 PTA函数—指针 - 图2;否则为 PTA函数—指针 - 图3。不管如何都需要在字符数组 s 之后添加 '\0' ,因为 main 函数中没有进行初始化操作。
    1. void strmcpy(char *t, int m, char *s) {
    2. int n = strlen(t);
    3. for (t = m <= n ? t + m - 1 : t + n; (*s = *t) != '\0'; t++, s++);
    4. }
    运行结果
Case Hint Result Run Time Memory
0 sample等价,t有空格 Accepted 3 ms 440 KB
1 t长度超过题面的20,全复制 Accepted 3 ms 296 KB
2 m等于长度 Accepted 3 ms 296 KB
3 m超过长度 Accepted 3 ms 240 KB
4 只有1个字符,m为1 Accepted 3 ms 328 KB

习题8-6 删除字符

本题要求实现一个删除字符串中的指定字符的简单函数。
函数接口定义:

  1. void delchar( char *str, char c );

其中char *str是传入的字符串,c是待删除的字符。函数delchar的功能是将字符串str中出现的所有c字符删除。
裁判测试程序样例:

  1. #include <stdio.h>
  2. #define MAXN 20
  3. void delchar( char *str, char c );
  4. void ReadString( char s[] ); /* 由裁判实现,略去不表 */
  5. int main() {
  6. char str[MAXN], c;
  7. scanf("%c\n", &c);
  8. ReadString(str);
  9. delchar(str, c);
  10. printf("%s\n", str);
  11. return 0;
  12. }
  13. /* 你的代码将被嵌在这里 */

输入样例:

  1. a
  2. happy new year

输出样例:

  1. hppy new yer

解题思路:本例是直接在字符数组上进行删除,可使用一个字符索引记录,因为最多删除整个字符串。类似想法就是将非 c 的字符放入另一个字符数组中,但是由于填充字符永远小于等于字符串的长度,因此可以直接在原字符串的基础上进行而不发生覆盖。(类似还有数组元素去重)

  1. void delchar(char *str, char c) {
  2. int idx = 0;
  3. for (int i = 0; str[i] != '\0'; i++) {
  4. if (str[i] != c) {
  5. str[idx++] = str[i];
  6. }
  7. }
  8. str[idx] = '\0';
  9. }

运行结果

Case Hint Result Run Time Memory
0 sample等价,有空格,有删除 Accepted 3 ms 296 KB
1 删除字符在首尾,长度超过20 Accepted 3 ms 384 KB
2 删除后字符串为空 Accepted 4 ms 296 KB
3 被删除的字符不存在 Accepted 3 ms 368 KB
4 字符串为空 Accepted 2 ms 308 KB

习题8-8 判断回文字符串

本题要求编写函数,判断给定的一串字符是否为“回文”。所谓“回文”是指顺读和倒读都一样的字符串。如“XYZYX”和“xyzzyx”都是回文。
函数接口定义:

  1. bool palindrome( char *s );

函数palindrome判断输入字符串char *s是否为回文。若是则返回true,否则返回false
裁判测试程序样例:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define MAXN 20
  4. typedef enum {false, true} bool;
  5. bool palindrome( char *s );
  6. int main()
  7. {
  8. char s[MAXN];
  9. scanf("%s", s);
  10. if ( palindrome(s)==true )
  11. printf("Yes\n");
  12. else
  13. printf("No\n");
  14. printf("%s\n", s);
  15. return 0;
  16. }
  17. /* 你的代码将被嵌在这里 */

输入样例1:

  1. thisistrueurtsisiht

输出样例1:

  1. Yes
  2. thisistrueurtsisiht

输入样例2:

  1. thisisnottrue

输出样例2:

  1. No
  2. thisisnottrue

解题思路:不管回文长度为奇数或者偶数,其必有首尾字符相等,如此进行首尾相消,当为奇数即 bab ,最后剩下一个肯定是回文,即此时 left=1, right=1 不需要检测就是回文。当为偶数即 bacb ,中间的 ac 一定需要检测。一旦在首尾相消过程中发现不相等,可以直接判断不成回文,否则成立。需要注意的就是 '\0' 即空串也是回文。

  1. bool palindrome(char *s) {
  2. for (int right = strlen(s) - 1, left = 0; left < right; left++, right--) {
  3. if (s[left] != s[right]) {
  4. return false;
  5. }
  6. }
  7. return true;
  8. }

运行结果:

Case Hint Result Run Time Memory
0 sample1等价,奇数字符中心对称 Accepted 4 ms 296 KB
1 sample2等价,完全不对称 Accepted 4 ms 384 KB
2 s长度超过题面的20,偶数字符对称 Accepted 4 ms 256 KB
3 最中心差1个字符 Accepted 3 ms 256 KB
4 只有1个字符 Accepted 3 ms 256 KB
5 只有2个字符 Accepted 4 ms 256 KB

习题8-9 分类统计各类字符个数

本题要求实现一个函数,统计给定字符串中的大写字母、小写字母、空格、数字以及其它字符各有多少。
函数接口定义:

  1. void StringCount( char *s );

其中 char *s 是用户传入的字符串。函数StringCount须在一行内按照

  1. 大写字母个数 小写字母个数 空格个数 数字个数 其它字符个数

的格式输出。
裁判测试程序样例:

  1. #include <stdio.h>
  2. #define MAXS 15
  3. void StringCount( char *s );
  4. void ReadString( char *s ); /* 由裁判实现,略去不表 */
  5. int main()
  6. {
  7. char s[MAXS];
  8. ReadString(s);
  9. StringCount(s);
  10. return 0;
  11. }
  12. /* Your function will be put here */

输入样例:

  1. aZ&*?
  2. 093 Az

输出样例:

  1. 2 2 1 3 4

解题思路:对于每个数分别进行统计即可。

  1. void StringCount(char *s) {
  2. int upper = 0, lower = 0, space = 0, digit = 0, other = 0;
  3. for (int i = 0; s[i] != '\0'; i++) {
  4. if ('A' <= s[i] && s[i] <= 'Z') {
  5. upper++;
  6. } else if ('a' <= s[i] && s[i] <= 'z') {
  7. lower++;
  8. } else if ('0' <= s[i] && s[i] <= '9') {
  9. digit++;
  10. } else if (' ' == s[i]) {
  11. space++;
  12. } else {
  13. other++;
  14. }
  15. }
  16. printf("%d %d %d %d %d\n", upper, lower, space, digit, other);
  17. }

运行结果

Case Hint Result Run Time Memory
0 sample 五种类型全有,数字和字母取边界 Accepted 4 ms 348 KB
1 10个空格 Accepted 4 ms 412 KB
2 16个数字有重复,MAXS重新定义 Accepted 3 ms 344 KB
3 10个大写字母有重复 Accepted 3 ms 296 KB
4 10个小写字母有重复 Accepted 3 ms 340 KB
5 其他字符的边界 Accepted 3 ms 300 KB

习题11-1 输出月份英文名

本题要求实现函数,可以返回一个给定月份的英文名称。
函数接口定义:

  1. char *getmonth( int n );

函数getmonth应返回存储了n对应的月份英文名称的字符串头指针。如果传入的参数n不是一个代表月份的数字,则返回空指针NULL。
裁判测试程序样例:

  1. #include <stdio.h>
  2. char *getmonth( int n );
  3. int main()
  4. {
  5. int n;
  6. char *s;
  7. scanf("%d", &n);
  8. s = getmonth(n);
  9. if ( s==NULL ) printf("wrong input!\n");
  10. else printf("%s\n", s);
  11. return 0;
  12. }
  13. /* 你的代码将被嵌在这里 */

输入样例1:

  1. 5

输出样例1:

  1. May

输入样例2:

  1. 15

输出样例2:

  1. wrong input!

解题思路:可以使用 switch-case 或者字符指针数组处理。

  1. char *getmonth(int n) {
  2. if (n > 12 || n <= 0) return NULL;
  3. char *Month[] = {"", "January", "February", "March", "April", "May", "June",
  4. "July", "August", "September", "October", "November", "December"};
  5. return Month[n];
  6. }
  7. char *getmonth( int n ) {
  8. switch (n) {
  9. case 1: return "January";
  10. case 2: return "February";
  11. case 3: return "March";
  12. case 4: return "April";
  13. case 5: return "May";
  14. case 6: return "June";
  15. case 7: return "July";
  16. case 8: return "August";
  17. case 9: return "September";
  18. case 10: return "October";
  19. case 11: return "November";
  20. case 12: return "December";
  21. default: return NULL;
  22. }
  23. }

运行结果:

Case Hint Result Run Time Memory
0 1月 Accepted 3 ms 256 KB
1 2月 Accepted 2 ms 304 KB
2 3月 Accepted 2 ms 364 KB
3 4月 Accepted 2 ms 368 KB
4 5月 Accepted 2 ms 360 KB
5 6月 Accepted 2 ms 364 KB
6 7月 Accepted 2 ms 296 KB
7 8月 Accepted 2 ms 296 KB
8 9月 Accepted 2 ms 260 KB
9 10月 Accepted 2 ms 256 KB
10 11月 Accepted 2 ms 256 KB
11 12月 Accepted 2 ms 256 KB
12 Accepted 2 ms 224 KB
13 小于1的负数 Accepted 2 ms 384 KB
14 大于12 Accepted 2 ms 376 KB

习题11-2 查找星期

本题要求实现函数,可以根据下表查找到星期,返回对应的序号。

序号 星期
0 Sunday
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday

函数接口定义:

  1. int getindex( char *s );

函数getindex应返回字符串s序号。如果传入的参数s不是一个代表星期的字符串,则返回-1。
裁判测试程序样例:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define MAXS 80
  4. int getindex( char *s );
  5. int main()
  6. {
  7. int n;
  8. char s[MAXS];
  9. scanf("%s", s);
  10. n = getindex(s);
  11. if ( n==-1 ) printf("wrong input!\n");
  12. else printf("%d\n", n);
  13. return 0;
  14. }
  15. /* 你的代码将被嵌在这里 */

输入样例1:

  1. Tuesday

输出样例1:

  1. 2

输入样例2:

  1. today

输出样例2:

  1. wrong input!

解题思路:考察 strcmp 函数

  1. int getindex(char *s) {
  2. if (0 == strcmp(s, "Sunday")) {
  3. return 0;
  4. } else if (0 == strcmp(s, "Monday")) {
  5. return 1;
  6. } else if (0 == strcmp(s, "Monday")) {
  7. return 1;
  8. } else if (0 == strcmp(s, "Tuesday")) {
  9. return 2;
  10. } else if (0 == strcmp(s, "Wednesday")) {
  11. return 3;
  12. } else if (0 == strcmp(s, "Thursday")) {
  13. return 4;
  14. } else if (0 == strcmp(s, "Friday")) {
  15. return 5;
  16. } else if (0 == strcmp(s, "Saturday")) {
  17. return 6;
  18. }
  19. return -1;
  20. }
Case Hint Result Score Run Time Memory
0 0 Accepted 2 2 ms 272 KB
1 1 Accepted 2 2 ms 296 KB
2 2 Accepted 2 3 ms 368 KB
3 3 Accepted 2 3 ms 296 KB
4 4 Accepted 2 3 ms 304 KB
5 5 Accepted 2 3 ms 256 KB
6 6 Accepted 2 3 ms 292 KB
7 wrong input! Accepted 1 3 ms 384 KB

习题11-3 计算最长的字符串长度

本题要求实现一个函数,用于计算有n个元素的指针数组s中最长的字符串的长度。
函数接口定义:

  1. int max_len( char *s[], int n );

其中n个字符串存储在s[]中,函数max_len应返回其中最长字符串的长度。
裁判测试程序样例:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #define MAXN 10
  5. #define MAXS 20
  6. int max_len( char *s[], int n );
  7. int main()
  8. {
  9. int i, n;
  10. char *string[MAXN] = {NULL};
  11. scanf("%d", &n);
  12. for(i = 0; i < n; i++) {
  13. string[i] = (char *)malloc(sizeof(char)*MAXS);
  14. scanf("%s", string[i]);
  15. }
  16. printf("%d\n", max_len(string, n));
  17. return 0;
  18. }
  19. /* 你的代码将被嵌在这里 */

输入样例:

  1. 4
  2. blue
  3. yellow
  4. red
  5. green

输出样例:

  1. 6

解题思路:个人认为应该重点考察指针数组和动态分配内存,但是本题是给出函数接口,因此总体上非常简单。

  1. int max_len(char *s[], int n) {
  2. int max_len = 0;
  3. for (int i = 0; i < n; i++) {
  4. int len = strlen(s[i]);
  5. max_len = max_len > len ? max_len : len;
  6. }
  7. return max_len;
  8. }
Case Hint Result Score Run Time Memory
0 sample, 唯一最长串 Accepted 9 3 ms 300 KB
1 有并列最长串 Accepted 2 3 ms 324 KB
2 重新定义MAXN和MAXS, 取最大边界, 答案超过20 Accepted 2 3 ms 360 KB
3 最小n和长度 Accepted 2 2 ms 296 KB

习题11-4 字符串的连接

本题要求实现一个函数,将两个字符串连接起来。
函数接口定义:

  1. char *str_cat( char *s, char *t );

函数str_cat应将字符串t复制到字符串s的末端,并且返回字符串s的首地址。
裁判测试程序样例:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define MAXS 10
  4. char *str_cat( char *s, char *t );
  5. int main()
  6. {
  7. char *p;
  8. char str1[MAXS+MAXS] = {'\0'}, str2[MAXS] = {'\0'};
  9. scanf("%s%s", str1, str2);
  10. p = str_cat(str1, str2);
  11. printf("%s\n%s\n", p, str1);
  12. return 0;
  13. }
  14. /* 你的代码将被嵌在这里 */

输入样例:

  1. abc
  2. def

输出样例:

  1. abcdef
  2. abcdef

解题思路:书本上有例题,注意考察指针操作实现 strcat 函数。以下进行简写,读者需要明白 *tmp++ 的具体含义。

  1. char *str_cat(char *s, char *t) {
  2. for (char *tmp = s + strlen(s); *tmp++ = *t++; );
  3. return s;
  4. }
Case Hint Result Score Run Time Memory
0 sample等价, 短字符串相接 Accepted 9 3 ms 296 KB
1 超长字符串相接 Accepted 2 2 ms 312 KB
2 t为空 Accepted 2 3 ms 256 KB
3 各有1个字符 Accepted 2 2 ms 256 KB

习题11-5 指定位置输出字符串

本题要求实现一个函数,对给定的一个字符串和两个字符,打印出给定字符串中从与第一个字符匹配的位置开始到与第二个字符匹配的位置之间的所有字符。
函数接口定义:

  1. char *match( char *s, char ch1, char ch2 );

函数match应打印s中从ch1ch2之间的所有字符,并且返回ch1的地址。
裁判测试程序样例:

  1. #include <stdio.h>
  2. #define MAXS 10
  3. char *match( char *s, char ch1, char ch2 );
  4. int main()
  5. {
  6. char str[MAXS], ch_start, ch_end, *p;
  7. scanf("%s\n", str);
  8. scanf("%c %c", &ch_start, &ch_end);
  9. p = match(str, ch_start, ch_end);
  10. printf("%s\n", p);
  11. return 0;
  12. }
  13. /* 你的代码将被嵌在这里 */

输入样例1:

  1. program
  2. r g

输出样例1:

  1. rog
  2. rogram

输入样例2:

  1. program
  2. z o

输出样例2:

  1. (空行)
  2. (空行)

输入样例3:

  1. program
  2. g z

输出样例3:

  1. gram
  2. gram

解题思路:

  1. 首先在 s 串中找到字符 ch1 ,必须注意可能找不到的情况,即遇到 \0 结束。将寻找找到的结果标记次数可能为 ch1 串所在的字符指针 res 用于答案的返回。
  2. 开始打印 ch1->ch2 之间的字符串,那么条件结束判断也是在字符串 \0 结束之前,且必定要有 *s != ch2 的终止判断(引发的问题就是遍历结束后再继续判断是否当前 *s == ch2 额外打印 ch2
  3. 经历以上两个阶段,如果都没找到 char *res = '\0' 一定成立,那么也需要在最后打印换行符。
    1. char *match(char *s, char ch1, char ch2) {
    2. // 1.除去前面不是 ch1 的字符
    3. for (; *s != '\0' && *s != ch1; s++);
    4. char *res = s;
    5. // 2.打印 ch1->ch2 间的字符
    6. for (; *s != '\0'; s++) {
    7. printf("%c", *s);
    8. if (*s == ch2) {
    9. break;
    10. }
    11. }
    12. // 3. 换行
    13. printf("\n");
    14. return res;
    15. }
    运行结果
Case Hint Result Run Time Memory
0 sample1, 正常截取中段, ch1重复出现 Accepted 3 ms 360 KB
1 sample2, ch1找不到, ch2找到 Accepted 3 ms 360 KB
2 sample3, ch1找到, ch2找不到 Accepted 3 ms 228 KB
3 超长s, 取整个字符串 Accepted 3 ms 296 KB
4 s只有1个字符 Accepted 4 ms 384 KB

习题11-6 查找子串

本题要求实现一个字符串查找的简单函数。
函数接口定义:

  1. char *search( char *s, char *t );

函数search在字符串s中查找子串t,返回子串t在s中的首地址。若未找到,则返回NULL。
裁判测试程序样例:

  1. #include <stdio.h>
  2. #define MAXS 30
  3. char *search(char *s, char *t);
  4. void ReadString( char s[] ); /* 裁判提供,细节不表 */
  5. int main()
  6. {
  7. char s[MAXS], t[MAXS], *pos;
  8. ReadString(s);
  9. ReadString(t);
  10. pos = search(s, t);
  11. if ( pos != NULL )
  12. printf("%d\n", pos - s);
  13. else
  14. printf("-1\n");
  15. return 0;
  16. }
  17. /* 你的代码将被嵌在这里 */

输入样例1:

  1. The C Programming Language
  2. ram

输出样例1:

  1. 10

输入样例2:

  1. The C Programming Language
  2. bored

输出样例2:

  1. -1

解题思路:本题经典 strstr 查找子串方法,读者掌握暴力法就可应付考试,有兴趣可以了解 KMP,BM,滚动哈希算法等。

暴力法,双指针(索引)重复匹配,当存在模式串完全匹配时就证明找到结果,题意中明确当含有多个结果是返回最左边的一个即可。

  1. char *search(char *s, char *t) {
  2. int i = 0, j = 0; // 双指针暴力法
  3. while ('\0' != s[i] && '\0' != t[j]) {
  4. while ('\0' != s[i] && '\0' != t[j] && t[j] == s[i]) {
  5. i++, j++;
  6. }
  7. if ('\0' == t[j]) {
  8. return s + i - j;
  9. } else {
  10. i = i - j + 1; // i移动一个
  11. j = 0; // j置0
  12. }
  13. }
  14. return NULL;
  15. }

另外需要提一点就是 pos - s 指针减法用法返回的是含有多少个字符,即字符串的长度,由于字符串开头从 0 算起,也就是打印结果是从序号 1 开始算起而不是 0 算起。
运行结果

Case Hint Result Run Time Memory
0 sample1等价, 找到唯一 Accepted 2 ms 296 KB
1 sample2等价, 找不到 Accepted 2 ms 264 KB
2 存在多个最短t Accepted 2 ms 364 KB
3 长度超过题面MAXS, t在结尾处 Accepted 2 ms 256 KB
4 只差1个字符找不到 Accepted 2 ms 256 KB
5 最短s,t比s长 Accepted 2 ms 256 KB