- 练习8-2 计算两数的和与差">练习8-2 计算两数的和与差
- 习题8-1 拆分实数的整数与小数部分">习题8-1 拆分实数的整数与小数部分
- 习题8-5 使用函数实现字符串部分复制">习题8-5 使用函数实现字符串部分复制
- 习题8-6 删除字符">习题8-6 删除字符
- 习题8-8 判断回文字符串">习题8-8 判断回文字符串
- 习题8-9 分类统计各类字符个数">习题8-9 分类统计各类字符个数
- 习题11-1 输出月份英文名">习题11-1 输出月份英文名
- 习题11-2 查找星期">习题11-2 查找星期
- 习题11-3 计算最长的字符串长度">习题11-3 计算最长的字符串长度
- 习题11-4 字符串的连接">习题11-4 字符串的连接
- 习题11-5 指定位置输出字符串">习题11-5 指定位置输出字符串
- 习题11-6 查找子串">习题11-6 查找子串
练习8-2 计算两数的和与差
本题要求实现一个计算输入的两数的和与差的简单函数。
函数接口定义:
void sum_diff( float op1, float op2, float *psum, float *pdiff );
其中op1
和op2
是输入的两个实数,*psum
和*pdiff
是计算得出的和与差。
裁判测试程序样例:
#include <stdio.h>
void sum_diff( float op1, float op2, float *psum, float *pdiff );
int main()
{
float a, b, sum, diff;
scanf("%f %f", &a, &b);
sum_diff(a, b, &sum, &diff);
printf("The sum is %.2f\nThe diff is %.2f\n", sum, diff);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
4 6
输出样例:
The sum is 10.00
The diff is -2.00
解题思路:指针传参修改,非常简单。
void sum_diff(float op1,float op2,float *psum,float *pdiff) {
*psum = op1 + op2;
*pdiff = op1 - op2;
}
运行结果:
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 拆分实数的整数与小数部分
本题要求实现一个拆分实数的整数与小数部分的简单函数。
函数接口定义:
void splitfloat( float x, int *intpart, float *fracpart );
其中x
是被拆分的实数(0≤x
<10000),`*intpart`和`*fracpart`分别是将实数x拆分出来的整数部分与小数部分。
裁判测试程序样例:
#include <stdio.h>
void splitfloat( float x, int *intpart, float *fracpart );
int main()
{
float x, fracpart;
int intpart;
scanf("%f", &x);
splitfloat(x, &intpart, &fracpart);
printf("The integer part is %d\n", intpart);
printf("The fractional part is %g\n", fracpart);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
2.718
输出样例:
The integer part is 2
The fractional part is 0.718
解题步骤:考察强制类型转换和指针知识。
- 整数部分:使用
(int)x
强制类型转换即可得到整数部分intpart
- 小数部分:用原来的浮点数
x - intpart
就得到小数部分。 :::tips 实际上这样操作是不对的,很容易发生精度问题。一般采用转换为字符串,也就是通过"%f"
格式化为字符串形式获得整数和小数部分。但是本题主要目的在于考察指针通过函数赋值的操作,因此懒得转换为字符串后再转换回int/float
:::
| 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 |void splitfloat(float x, int *intpart, float *fracpart) {
*intpart = (int)x;
*fracpart = x - *intpart;
}
习题8-5 使用函数实现字符串部分复制
本题要求编写函数,将输入字符串t中从第m个字符开始的全部字符复制到字符串s中。
函数接口定义:
void strmcpy( char *t, int m, char *s );
函数strmcpy
将输入字符串char *t
中从第m
个字符开始的全部字符复制到字符串char *s
中。若m
超过输入字符串的长度,则结果字符串应为空串。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 20
void strmcpy( char *t, int m, char *s );
void ReadString( char s[] ); /* 由裁判实现,略去不表 */
int main() {
char t[MAXN], s[MAXN];
int m;
scanf("%d\n", &m);
ReadString(t);
strmcpy( t, m, s );
printf("%s\n", s);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
7
happy new year
输出样例:
new year
解题思路:题目给定的 m
是顺序个数,从 1
开始计数,因此等于下标 idx + 1
。
- 判断
m
与字符串长度n
的关系:如果,则开始复制范围为
;否则为
。不管如何都需要在字符数组
s
之后添加'\0'
,因为main
函数中没有进行初始化操作。
运行结果:void strmcpy(char *t, int m, char *s) {
int n = strlen(t);
for (t = m <= n ? t + m - 1 : t + n; (*s = *t) != '\0'; t++, s++);
}
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 删除字符
本题要求实现一个删除字符串中的指定字符的简单函数。
函数接口定义:
void delchar( char *str, char c );
其中char *str
是传入的字符串,c
是待删除的字符。函数delchar
的功能是将字符串str
中出现的所有c
字符删除。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 20
void delchar( char *str, char c );
void ReadString( char s[] ); /* 由裁判实现,略去不表 */
int main() {
char str[MAXN], c;
scanf("%c\n", &c);
ReadString(str);
delchar(str, c);
printf("%s\n", str);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
a
happy new year
输出样例:
hppy new yer
解题思路:本例是直接在字符数组上进行删除,可使用一个字符索引记录,因为最多删除整个字符串。类似想法就是将非 c
的字符放入另一个字符数组中,但是由于填充字符永远小于等于字符串的长度,因此可以直接在原字符串的基础上进行而不发生覆盖。(类似还有数组元素去重)
void delchar(char *str, char c) {
int idx = 0;
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] != c) {
str[idx++] = str[i];
}
}
str[idx] = '\0';
}
运行结果:
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”都是回文。
函数接口定义:
bool palindrome( char *s );
函数palindrome
判断输入字符串char *s
是否为回文。若是则返回true
,否则返回false
。
裁判测试程序样例:
#include <stdio.h>
#include <string.h>
#define MAXN 20
typedef enum {false, true} bool;
bool palindrome( char *s );
int main()
{
char s[MAXN];
scanf("%s", s);
if ( palindrome(s)==true )
printf("Yes\n");
else
printf("No\n");
printf("%s\n", s);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例1:
thisistrueurtsisiht
输出样例1:
Yes
thisistrueurtsisiht
输入样例2:
thisisnottrue
输出样例2:
No
thisisnottrue
解题思路:不管回文长度为奇数或者偶数,其必有首尾字符相等,如此进行首尾相消,当为奇数即 bab
,最后剩下一个肯定是回文,即此时 left=1, right=1
不需要检测就是回文。当为偶数即 bacb
,中间的 ac
一定需要检测。一旦在首尾相消过程中发现不相等,可以直接判断不成回文,否则成立。需要注意的就是 '\0'
即空串也是回文。
bool palindrome(char *s) {
for (int right = strlen(s) - 1, left = 0; left < right; left++, right--) {
if (s[left] != s[right]) {
return false;
}
}
return true;
}
运行结果:
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 分类统计各类字符个数
本题要求实现一个函数,统计给定字符串中的大写字母、小写字母、空格、数字以及其它字符各有多少。
函数接口定义:
void StringCount( char *s );
其中 char *s
是用户传入的字符串。函数StringCount
须在一行内按照
大写字母个数 小写字母个数 空格个数 数字个数 其它字符个数
的格式输出。
裁判测试程序样例:
#include <stdio.h>
#define MAXS 15
void StringCount( char *s );
void ReadString( char *s ); /* 由裁判实现,略去不表 */
int main()
{
char s[MAXS];
ReadString(s);
StringCount(s);
return 0;
}
/* Your function will be put here */
输入样例:
aZ&*?
093 Az
输出样例:
2 2 1 3 4
解题思路:对于每个数分别进行统计即可。
void StringCount(char *s) {
int upper = 0, lower = 0, space = 0, digit = 0, other = 0;
for (int i = 0; s[i] != '\0'; i++) {
if ('A' <= s[i] && s[i] <= 'Z') {
upper++;
} else if ('a' <= s[i] && s[i] <= 'z') {
lower++;
} else if ('0' <= s[i] && s[i] <= '9') {
digit++;
} else if (' ' == s[i]) {
space++;
} else {
other++;
}
}
printf("%d %d %d %d %d\n", upper, lower, space, digit, other);
}
运行结果:
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 输出月份英文名
本题要求实现函数,可以返回一个给定月份的英文名称。
函数接口定义:
char *getmonth( int n );
函数getmonth
应返回存储了n
对应的月份英文名称的字符串头指针。如果传入的参数n
不是一个代表月份的数字,则返回空指针NULL。
裁判测试程序样例:
#include <stdio.h>
char *getmonth( int n );
int main()
{
int n;
char *s;
scanf("%d", &n);
s = getmonth(n);
if ( s==NULL ) printf("wrong input!\n");
else printf("%s\n", s);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例1:
5
输出样例1:
May
输入样例2:
15
输出样例2:
wrong input!
解题思路:可以使用 switch-case
或者字符指针数组处理。
char *getmonth(int n) {
if (n > 12 || n <= 0) return NULL;
char *Month[] = {"", "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
return Month[n];
}
char *getmonth( int n ) {
switch (n) {
case 1: return "January";
case 2: return "February";
case 3: return "March";
case 4: return "April";
case 5: return "May";
case 6: return "June";
case 7: return "July";
case 8: return "August";
case 9: return "September";
case 10: return "October";
case 11: return "November";
case 12: return "December";
default: return NULL;
}
}
运行结果:
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 |
函数接口定义:
int getindex( char *s );
函数getindex
应返回字符串s
序号。如果传入的参数s
不是一个代表星期的字符串,则返回-1。
裁判测试程序样例:
#include <stdio.h>
#include <string.h>
#define MAXS 80
int getindex( char *s );
int main()
{
int n;
char s[MAXS];
scanf("%s", s);
n = getindex(s);
if ( n==-1 ) printf("wrong input!\n");
else printf("%d\n", n);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例1:
Tuesday
输出样例1:
2
输入样例2:
today
输出样例2:
wrong input!
解题思路:考察 strcmp
函数
int getindex(char *s) {
if (0 == strcmp(s, "Sunday")) {
return 0;
} else if (0 == strcmp(s, "Monday")) {
return 1;
} else if (0 == strcmp(s, "Monday")) {
return 1;
} else if (0 == strcmp(s, "Tuesday")) {
return 2;
} else if (0 == strcmp(s, "Wednesday")) {
return 3;
} else if (0 == strcmp(s, "Thursday")) {
return 4;
} else if (0 == strcmp(s, "Friday")) {
return 5;
} else if (0 == strcmp(s, "Saturday")) {
return 6;
}
return -1;
}
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中最长的字符串的长度。
函数接口定义:
int max_len( char *s[], int n );
其中n
个字符串存储在s[]
中,函数max_len
应返回其中最长字符串的长度。
裁判测试程序样例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXN 10
#define MAXS 20
int max_len( char *s[], int n );
int main()
{
int i, n;
char *string[MAXN] = {NULL};
scanf("%d", &n);
for(i = 0; i < n; i++) {
string[i] = (char *)malloc(sizeof(char)*MAXS);
scanf("%s", string[i]);
}
printf("%d\n", max_len(string, n));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
4
blue
yellow
red
green
输出样例:
6
解题思路:个人认为应该重点考察指针数组和动态分配内存,但是本题是给出函数接口,因此总体上非常简单。
int max_len(char *s[], int n) {
int max_len = 0;
for (int i = 0; i < n; i++) {
int len = strlen(s[i]);
max_len = max_len > len ? max_len : len;
}
return max_len;
}
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 字符串的连接
本题要求实现一个函数,将两个字符串连接起来。
函数接口定义:
char *str_cat( char *s, char *t );
函数str_cat
应将字符串t
复制到字符串s
的末端,并且返回字符串s
的首地址。
裁判测试程序样例:
#include <stdio.h>
#include <string.h>
#define MAXS 10
char *str_cat( char *s, char *t );
int main()
{
char *p;
char str1[MAXS+MAXS] = {'\0'}, str2[MAXS] = {'\0'};
scanf("%s%s", str1, str2);
p = str_cat(str1, str2);
printf("%s\n%s\n", p, str1);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
abc
def
输出样例:
abcdef
abcdef
解题思路:书本上有例题,注意考察指针操作实现 strcat
函数。以下进行简写,读者需要明白 *tmp++
的具体含义。
char *str_cat(char *s, char *t) {
for (char *tmp = s + strlen(s); *tmp++ = *t++; );
return s;
}
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 指定位置输出字符串
本题要求实现一个函数,对给定的一个字符串和两个字符,打印出给定字符串中从与第一个字符匹配的位置开始到与第二个字符匹配的位置之间的所有字符。
函数接口定义:
char *match( char *s, char ch1, char ch2 );
函数match
应打印s
中从ch1
到ch2
之间的所有字符,并且返回ch1
的地址。
裁判测试程序样例:
#include <stdio.h>
#define MAXS 10
char *match( char *s, char ch1, char ch2 );
int main()
{
char str[MAXS], ch_start, ch_end, *p;
scanf("%s\n", str);
scanf("%c %c", &ch_start, &ch_end);
p = match(str, ch_start, ch_end);
printf("%s\n", p);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例1:
program
r g
输出样例1:
rog
rogram
输入样例2:
program
z o
输出样例2:
(空行)
(空行)
输入样例3:
program
g z
输出样例3:
gram
gram
解题思路:
- 首先在
s
串中找到字符ch1
,必须注意可能找不到的情况,即遇到\0
结束。将寻找找到的结果标记次数可能为ch1
串所在的字符指针res
用于答案的返回。 - 开始打印
ch1->ch2
之间的字符串,那么条件结束判断也是在字符串\0
结束之前,且必定要有*s != ch2
的终止判断(引发的问题就是遍历结束后再继续判断是否当前*s == ch2
额外打印ch2
。 - 经历以上两个阶段,如果都没找到
char *res = '\0'
一定成立,那么也需要在最后打印换行符。
运行结果:char *match(char *s, char ch1, char ch2) {
// 1.除去前面不是 ch1 的字符
for (; *s != '\0' && *s != ch1; s++);
char *res = s;
// 2.打印 ch1->ch2 间的字符
for (; *s != '\0'; s++) {
printf("%c", *s);
if (*s == ch2) {
break;
}
}
// 3. 换行
printf("\n");
return res;
}
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 查找子串
本题要求实现一个字符串查找的简单函数。
函数接口定义:
char *search( char *s, char *t );
函数search
在字符串s
中查找子串t
,返回子串t在s
中的首地址。若未找到,则返回NULL。
裁判测试程序样例:
#include <stdio.h>
#define MAXS 30
char *search(char *s, char *t);
void ReadString( char s[] ); /* 裁判提供,细节不表 */
int main()
{
char s[MAXS], t[MAXS], *pos;
ReadString(s);
ReadString(t);
pos = search(s, t);
if ( pos != NULL )
printf("%d\n", pos - s);
else
printf("-1\n");
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例1:
The C Programming Language
ram
输出样例1:
10
输入样例2:
The C Programming Language
bored
输出样例2:
-1
解题思路:本题经典 strstr
查找子串方法,读者掌握暴力法就可应付考试,有兴趣可以了解 KMP,BM,滚动哈希算法等。
暴力法,双指针(索引)重复匹配,当存在模式串完全匹配时就证明找到结果,题意中明确当含有多个结果是返回最左边的一个即可。
char *search(char *s, char *t) {
int i = 0, j = 0; // 双指针暴力法
while ('\0' != s[i] && '\0' != t[j]) {
while ('\0' != s[i] && '\0' != t[j] && t[j] == s[i]) {
i++, j++;
}
if ('\0' == t[j]) {
return s + i - j;
} else {
i = i - j + 1; // i移动一个
j = 0; // j置0
}
}
return NULL;
}
另外需要提一点就是 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 |