部分答案参考了官方题解和网上的答案,仅供参考,可能也有部分bug未发现或解决。代码在gitee上面。
exercise2-1#
编写一个程序以确定分别由 signed 及 unsigned 限定的 char、short、int 与 long 类型变量的取值范围。采用打印标准头文件中的相应值以及直接计算两种方式实现。后一种方法的实现较困难一些,因为要确定各种浮点类型的取值范围。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| #include <stdio.h>
#include <limits.h>
int main() {
printf("Size of char %d\n", CHAR_BIT);
printf("Size of char max %d\n", CHAR_MAX);
printf("Size of char min %d\n", CHAR_MIN);
printf("Size of short min %d\n", SHRT_MIN);
printf("Size of short max %d\n", SHRT_MAX);
printf("Size of int min %d\n", INT_MIN);
printf("Size of int max %d\n", INT_MAX);
printf("Size of long min %ld\n", LONG_MIN);
printf("Size of long max %ld\n", LONG_MAX);
printf("Size of unsigned char %u\n", UCHAR_MAX);
printf("Size of unsigned short %u\n", USHRT_MAX);
printf("Size of unsigned int %u\n", UINT_MAX);
printf("Size of unsigned long %lu\n", ULONG_MAX);
return 0;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| Size of char 8
Size of char max 127
Size of char min -128
Size of short min -32768
Size of short max 32767
Size of int min -2147483648
Size of int max 2147483647
Size of long min -9223372036854775808
Size of long max 9223372036854775807
Size of unsigned char 255
Size of unsigned short 65535
Size of unsigned int 4294967295
Size of unsigned long 18446744073709551615
|
exercise2-2#
在不使用运算符&&或||的条件下编写一个与上面的 for 循环语句等价的循环语句。
1
2
| for (i = 0; ((i < lim - 1) + ((c = getchar()) != '\n') + (c != EOF)) == 3; i++)
s[i] = c;
|
或
1
2
| for (i = 0; i < lim - 1 ? ((c = getchar()) != EOF ? c != '\n' : 0) : 0; i++)
s[i] = c;
|
exercise2-3#
编写函数 htoi(s),把由十六进制数字组成的字符串(包含可选的前缀 0x或 0X)转换为与之等价的整型值。字符串中允许包含的数字包括:0~9、a~f 以及 A~F。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| #include <stdio.h>
#include <string.h>
#include <math.h>
#define MAXLINE 1024
int mpow(int a, int b) {
int ans = 1;
while (b--)
ans *= a;
return ans;
}
int calculate(char line[]) {
int len = strlen(line), ans = 0;
for (int i = 0; i < len; i++) {
ans += line[len - 1 - i] * mpow(16, i);
}
return ans;
}
int parse(char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return 10 + c - 'a';
if (c >= 'A' && c <= 'F')
return 10 + c - 'A';
return -1;
}
int Getline(char line[]) {
int len = 0, c, digit;
while ((c = getchar()) != '\n') {
if (len == 1 && (c == 'x' || c == 'X') && line[0] == 0) {
len = 0;
continue;
}
if ((digit = parse(c)) == -1) {
printf("Wrong input!\n");
return -1;
} else {
line[len++] = digit;
}
}
line[len] = 0;
return len;
}
int main() {
char line[MAXLINE];
while (Getline(line) != -1) {
printf("value is = %d\n", calculate(line));
}
}
|
1
2
3
4
5
6
| 0x43997a7b
value is = 1134131835
12345
value is = 74565
98765
value is = 624485
|
exercise2-4#
squeeze(s1, s2),将字符串 s1 中任何与字符串 s2 中字符匹配的字符都删除。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| #include <stdio.h>
#include <string.h>
void squeeze(char s1[], char s2[]) {
char count[256] = {0}; // 用来记录每个字符是否出现在s2中
int len1 = strlen(s1), len2 = strlen(s2);
char ans[len1 + 1];
int i, j;
while (len2--)
count[s2[len2]] = 1;
for (i = 0, j = 0; i < len1; i++)
if (count[s1[i]] == 0)
s1[j++] = s1[i];
s1[j] = '\0';
}
int main() {
char s1[] = "12345 6789";
char s2[] = "24 68";
printf("s1 = %s\ns2 = %s\n", s1, s2);
squeeze(s1, s2);
printf("ans = %s\n", s1);
}
|
结果
1
2
3
| s1 = 12345 6789
s2 = 24 68
ans = 13579
|
exercise2-5#
编写函数 any(s1, s2),将字符串 s2 中的任一字符在字符串 s1 中第一次出现的位置作为结果返回。如果 s1 中不包含 s2 中的字符,则返回-1。(标准库函数 strpbrk 具有同样的功能,但它返回的是指向该位置的指针。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| #include <stdio.h>
#include <string.h>
void any(char s1[], char s2[], int pos[]) {
// count存储字符在s2中第一次出现的位置,
int len1 = strlen(s1), len2 = strlen(s2), count[256];
for (int i = 0; i < 256; i++)
count[i] = -1;
for (int i = 0; i < len2; i++)
if (count[s2[i]] == -1)
count[s2[i]] = i;
// pos存储s1中每一个字符在s2中第一次出现的位置
// pos大小为s1的元素个数
for (int i = 0; i < len1; i++)
pos[i] = count[s1[i]];
}
int main() {
char s1[] = "abcdefga";
char s2[] = "aceg";
printf("s1 = %s\ns2 = %s\n", s1, s2);
int len = strlen(s1);
int pos[len];
for (int i = 0; i < len; i++)
pos[i] = -1;
any(s1, s2, pos);
printf("s1中每一个字符在s2中第一次出现的位置(按照s1中的下标):\n");
for (int i = 0; i < len; i++)
printf("%d ", pos[i]);
printf("\n");
return 0;
}
|
1
2
3
4
| s1 = abcdefga
s2 = aceg
s1中每一个字符在s2中第一次出现的位置(按照s1中的下标):
0 -1 1 -1 2 -1 3 0
|
exercise2-6#
编写一个函数 setbits(x, p, n, y),该函数返回对 x 执行下列操作后的结果值:将 x 中从第 p 位开始的 n 个(二进制)位设置为 y 中最右边 n 位的值,x 的其余 各位保持不变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| #include <stdio.h>
unsigned setbits(unsigned x, int p, int n, unsigned y) {
// 构建掩码,用于将x中的第p位开始的n位置为0
unsigned mask = ~(~0 << n) << (p + 1 - n);
// x中从第p位开始的n位置为0
x = x & ~mask;
// 取出y中最右边的n位,并将其移到合适的位置
unsigned yn = (y & ~(~0 << n)) << (p + 1 - n);
return x | yn;
}
int main() {
unsigned x = 0b10101011;
unsigned y = 0b00111010;
int p = 5;
int n = 3;
unsigned ans = setbits(x, p, n, y);
printf("setbits(%u(%08b), %d, %d, %u(%08b)) = %d(%08b)\n", x, x, p, n, y, y, ans, ans);
}
|
1
| setbits(171(10101011), 5, 3, 58(00111010)) = 147(10010011)
|
exercise2-7#
编写一个函数 invert(x, p, n),该函数返回对 x 执行下列操作后的结果值:将 x 中从第 p 位开始的 n 个(二进制)位求反(即,1 变成 0,0 变成 1),x 的其余各位保持不变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| #include <stdio.h>
unsigned invert(unsigned x, int p, int n) {
// 构建掩码,用于选定从第p位开始的n位
unsigned mask = (~(~0 << n)) << (p + 1 - n);
// 对选定的位进行求反,并保持其余位不变
return x ^ mask;
}
int main() {
unsigned x = 0b11011001;
int p = 4;
int n = 3;
unsigned ans = invert(x, p, n);
printf("invert(%u(%08b), %d, %d) = %u(%08b)\n", x, x, p, n, ans, ans);
}
|
1
| invert(217(11011001), 4, 3) = 197(11000101)
|
exercise2-8#
编写一个函数 rightrot(x, n),该函数返回将 x 循环右移(即从最右端移出的位将从最左端移入)n(二进制)位后所得到的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| #include <stdio.h>
unsigned rightrot(unsigned x, int n) {
// 制作掩码
unsigned mask = (~(~0 << n) & x) << (8 - n);
// 将x右移n位之后与掩码或操作
return mask | (x >> n);
}
int main() {
unsigned x = 0b00000111;
int n = 3;
unsigned ans = rightrot(x, n);
printf("rightrot(%u(%08b), %d) = %u(%08b)\n", x, x, n, ans, ans);
}
|
1
| rightrot(7(00000111), 3) = 224(11100000)
|
exercise2-9#
在求对二的补码时,表达式 x &= (x – 1)可以删除 x 中最右边值为 1 的一个二进制位。请解释这样做的道理。用这一方法重写 bitcount 函数,以加快其执行速度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| #include <stdio.h>
int bitcount(unsigned x) {
int ans = 0;
// 不断除去最右边的1,直至变为0
while (x != 0) {
x &= (x - 1);
ans++;
}
return ans;
}
int main() {
int x = 0b00100101;
int count = bitcount(x);
printf("bitcount(%u(%08b)) = %d\n", x, x, count);
}
|
1
| bitcount(37(00100101)) = 3
|
若有变量 x,在其最右边一个 1 之后比特位都为 0,若对其进行减一的操作,则在比特位上的表现为:将最后一个 1 及其右边的比特位全部反转,例如将 $00101000$变成 $00100111$,进行b & (b - 1)
操作之后,会将反转的位都变成 0,从而实现了去除最右边一个 1 的操作。
exercise2-10#
重新编写将大写字母转换为小写字母的函数 lower,并用条件表达式替代其中的 if-else 结构。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| #include <stdio.h>
#include <string.h>
#define MAXLINE 1024
void lower(char str[]) {
int len = strlen(str);
for (int i = 0; i < len; i++) {
str[i] += (str[i] >= 'A' && str[i] <= 'Z') ? 'a' - 'A' : 0;
}
}
int main() {
char str[MAXLINE];
scanf("%[^\n]", str); // 捕获直到换行符
lower(str);
printf("%s\n", str);
}
|
1
2
| This Is A GOOD idea
this is a good idea
|