CS50-Week2

文章发布时间:

最后更新时间:

文章总字数:
2.1k

预计阅读时间:
10 分钟

Lab2 Array

程序除了语法错误以外竟然一次跑通,写的时候很崩溃因为牵扯到 ASCII 码,不是很熟,但是没想到 oj 竟然一次过了,真的巨激动!

小错误:忘记设置返回值,等号判断符写错,打印漏引号

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
55
56
57
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

// Points assigned to each letter of the alphabet
int POINTS[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10};

int compute_score(string word);

int main(void)
{
// Get input words from both players
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");

// Score both words
int score1 = compute_score(word1);
int score2 = compute_score(word2);

// TODO: Print the winner
if (score1 > score2)
{
printf("Player 1 wins!");
}
else if (score1 < score2)
{
printf("Player 2 wins!");
}
else if (score1 == score2)
{
printf("Tie!");
}
}

int compute_score(string word)
{
// TODO: Compute and return score for string
int n = strlen(word);
int m = 0;
int score = 0;
for (int i = 0; i <= n; i++)
{
if (word[i] >= 65 && word[i] <= 90)
{
m = word[i] - 65;
score = score + POINTS[m];
}
else if (word[i] >= 97 && word[i] <= 122)
{
m = word[i] - 97;
score = score + POINTS[m];
}
}
return score;
}

Problem Sets

但是问题集就不轻松了,不过也不难

文本难度判断 Readibity

需要数出一段文本的字母,单词,句子数量。计算可读性指数,四舍五入,不考虑例如 Mr.之类的句点的用法,设置初始值和输入

1
2
3
4
5
6
7
8
9
10
11
#include <cs50.h>
#include <stdio.h>

int main(void)
{
string text = get_string("Text:");
int letter = 0;
int word = 1;
int sent = 0;
int index = 0;
}


先看数字母,可以在 while 循环中运行,C 语言字符串型在末尾会自行添加结束标识符\0,可以基于此作为循环条件,单词数需要在末尾加 1,因为若 word 从 0 开始计数,利用空字符检测 word 数的方法会在句子末尾\0处失效,漏掉最后一个 word。循环代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{//此尖括号表示main函数体
int i = 0;
while (text[i] != '\0')
{
if ((text[i] >= 65 && text[i] <= 90) || (text[i] >= 97 && text[i] <= 122))
{
letter++;
}
else if (text[i] == ' ')
{
word++;
}
else if ((text[i] == 33) || (text[i] == 46) || (text[i] == 63))
{
sent++;
}
i++;
}
}

此后是可读性指数计算,计算过程考虑小数,并需要四舍五入,引入delat参数计算浮点数与其整数部分的差值,若大于 0.5 则进一,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{//此尖括号表示main函数体
float L = (float) letter / word * 100;
float S = (float) sent / word * 100;
float in = 0.0588 * L - 0.296 * S - 15.8;
index = (float) 0.0588 * L - 0.296 * S - 15.8;
float delat = in - (float) index;
// printf("index %d\n in %f",index,in);
if (index < 1)
{
printf("Before Grade 1\n");
}
else if (index > 16)
{
printf("Grade 16+\n");
}
else if (delat >= 0.5)
{
printf("Grade %i\n", index + 1);
}
else if (delat < 0.5)
{
printf("Grade %i\n", index);
}
}

完成


注意:if 条件语句对 or 的表示与使用需要管道符与条件括号


选做 #3 substitution

用户打开程序同时输入密钥,即 26 个字母打乱,得到的新顺序的字母依次继承 ABCD……的意思

程序内用户输入明文,打印密文

思路 假设一个 key,明文为 hello,则找 key 中第 7 位对应的字母,不换行打印循环到\0

错误预防 key 必须是 26 个字母,我们只能对字母加密,明文与密文大小写相同


首先,读取 key,key 的位置在argv[1],获取这个字符串内的值即argv[1][i]

读取明文的每一个字母,其字母所在位置指向 key 的对应字母,依次输出,同时考虑大小写,可以使用ctype.h库进行大小写转换,虽然手写也不难就是了。

明文每个字母有对应的 ASCII 码,将他们大小写统一再剪掉一个常数,就能得到 A-Z 的顺序 0-25,用这个指数去读取 key,打印结果时再将大小写还原

或者,使用 if 对大小写分开操作似乎更为简便,标点符号正常打印,末尾换行。

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
string ori = get_string("plaintext:");

printf("ciphertext: ");
int i = 0;
int n = 0;
int m = strlen(ori);

do
{
if (ori[i] >= 97 && ori[i] <= 122)
{
n = ori[i] - 97;
printf("%c", tolower(argv[1][n]));
}

else if (ori[i] >= 65 && ori[i] <= 90)
{
n = ori[i] - 65;
printf("%c", toupper(argv[1][n]));
}
else
{
printf("%c", ori[i]);
}
if (i == m - 1)
{
printf("\n");
}
i++;
}
while (i <= m);

另外,针对错误输入要有反馈,若 key 长度不等于 26(string 库),返回什么;其他格式错误返回什么

比如:传入参数数量不等于一,给出格式提示,key 长度不对,给出长度提示,两种错误同样有优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(int argc, string argv[])
{
if (argc != 1)
{
printf("Usage: ./substitution key");
return 1;
}
else if (strlen(argv[1]) != 26)
{
printf("Key must contain 26 characters.");
return 1;
}


//其他代码
}

注意,key 判断语句应该最先执行


主体的完成很简单,但是 debug 相当痛苦,key 中不能有重复的字符,且不能出现字母以外的符号

排除重复可以这样写,创建一个 26 位的数组,遇到一个字母就在对应位置+1,将小写统一为大写,大于 1 即有重复,写在一开始的 key 检测部分

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
//no duplicate characters
int alphabeta[26];
int index = 0;
for (int i = 0;i <= 26;i++)
{
if (argv[1][i] < 65 || (argv[1][i] > 90 && argv[1][i] < 97) || argv[1][i]>122)
{ //only ABC
return 1;
}

alphabeta[i] = 0;
if (argv[1][i] >= 65 && argv[1][i] <= 90)
{
index = argv[1][i] - 65;
alphabeta[index]++;
}
else if (argv[1][i] >= 97 && argv[1][i] <= 122)
{
argv[1][i] = toupper(argv[1][i]);
index = argv[1][i] - 65;
alphabeta[index]++;
}

if (alphabeta[i] > 1)
{
return 1;
}
}


提交一下

WTF!下面的修好了上面的有错了!?

给每个 return 1 写个输出看一下

1
2
3
4
5
if (argv[1][i] < 65 || (argv[1][i] > 90 && argv[1][i] < 97) || argv[1][i]>122)
{ //only ABC
printf("the %d char %c is not ABC.",i,argv[1][i]);
return 1;
}

在此次返回了the 26 char is not ABC.

数组从 0 计数,i 到 26 时自然为空,将 i 的上限改为 25,提交评测机
报错
嗯?还有高手!?

上次正确的部分这次又错了[吐血]

问问 ddb

[code]为什么不起作用

ddb
看起来你正在尝试检查 argv[1]中的字符是否有重复。你的代码中有一些可能的问题。

首先,你的 alphabeta 数组的大小应该是 26,而不是 25,因为英文字母有 26 个。

其次,你在检查 alphabeta[i]是否大于 1 时,你应该检查的是 alphabeta[index],因为 index 是你实际更新的数组索引。

最后,你在将小写字母转换为大写字母后,应该再次检查 alphabeta[index]是否大于 1,因为在转换后,可能会有新的重复字母出现。

希望这些建议能帮助你解决问题。

哦~数组大小就是 26

哦~~~index 写成 i 了

提交评测机

过~~~啦!!!!

完整源代码

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: ./substitution key");
return 1;
}
else if (strlen(argv[1]) != 26)
{
printf("Key must contain 26 characters.");
return 1;
}

// no duplicate characters
int alphabeta[26];
int index = 0;
for (int i = 0; i < 26; i++)
{
if (argv[1][i] < 65 || (argv[1][i] > 90 && argv[1][i] < 97) || argv[1][i] > 122)
{ // only ABC
// printf("the %d char %c is not ABC.",i,argv[1][i]);
return 1;
}

alphabeta[i] = 0;
if (argv[1][i] >= 65 && argv[1][i] <= 90)
{
index = argv[1][i] - 65;
alphabeta[index]++;
}
else if (argv[1][i] >= 97 && argv[1][i] <= 122)
{
argv[1][i] = toupper(argv[1][i]);
index = argv[1][i] - 65;
alphabeta[index]++;
}

if (alphabeta[index] > 1)
{
// printf("no AABBCC.");
return 1;
}
}

string ori = get_string("plaintext:");

printf("ciphertext: ");
int i = 0;
int n = 0;
int m = strlen(ori);

do
{
if (ori[i] >= 97 && ori[i] <= 122)
{
n = ori[i] - 97;
printf("%c", tolower(argv[1][n]));
}

else if (ori[i] >= 65 && ori[i] <= 90)
{
n = ori[i] - 65;
printf("%c", toupper(argv[1][n]));
}
else
{
printf("%c", ori[i]);
}
if (i == m - 1)
{
printf("\n");
}
i++;
}
while (i <= m);

return 0;
}