为什么我的 C 函数不能处理标点符号?

问题描述 投票:0回答:3

我正在尝试在 cs50 pset 第 2 周做一个简单的拼字游戏,函数“int compute_score(string word)”无法处理使用标点符号的输入,即使它与正确答案大致相同通过将所有输入转换为大写来使用更少的代码行。这是下面的代码,但您真正需要看的是我在上面命名的函数:

#include <ctype.h>
#include <cs50.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()
{
    // 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!\n");
    }
    else if (score1 < score2)
    {
        printf("Player 2 wins!\n");
    }
    else
    {
        printf("Tie!\n");
    }
}

int compute_score(string word)
{
    // TODO: Compute and return score for string
    //Initialize score
    int score = 0;

    //Convert array of chars to uppercase and solve
    for (int i = 0, N = strlen(word); i < N; i++)
    {
        score = score + POINTS[toupper(word[i]) - 65];
    }
    return score;
}

在谈到这一点之前,我在对单个字符使用 toupper 时遇到了麻烦,直到我观看了一段视频,该视频解释了使用 ASCII 图表的逻辑以及如何在讲座中迭代字符串中的字符。所以在 for 循环中,我写道:

//Convert array of chars to uppercase and solve
    for (int i = 0, N = strlen(word); i < N; i++)
    {
        score = score + POINTS[toupper(word[i]) - 65];
    }
    return score;

我决定将输入转换为全部大写,因为像“A”和“g”这样的字符与大写/非大写对应的字符具有相同的值,我认为转换它会更简单大写,以便逻辑更简单,更快,更有效地编写。在我的脑海里也更有意义了。但是,当我使用 check50 东西时,所有东西都会变成绿色,除了标点符号(最后有一个例外)。这是终端测试显示的内容:

terminal results

现在我完全不明白这个,因为在我眼里,它和正确答案几乎完全一样,就是:

for (int i = 0, N = strlen(word); i < N; i++)
{
    if (isupper(word[i]))
    {
        score += POINTS[word[i] - 'A'];
    }
    else if (islower(word[i]))
    {
        score += POINTS[word[i] - 'a'];
    }
}

我不知道为什么它不起作用。我在想,出于某种原因,它正在对标点符号进行评分。但这没有意义,因为 toupper 被设计为只处理字母字符,它应该排除特殊字符,将它们的值呈现为零。有人对出了什么问题有什么建议吗?

c function syntax cs50 ctype
3个回答
2
投票

…toupper 被设计为只适用于字母字符,它应该排除特殊字符,将它们的值呈现为零。

toupper
不会更改非字母字符。
toupper('!')
的计算结果与
'!
' 相同,而不是零。
toupper
在C 2018 76.4.2.2中指定,其中第3段说(粗体添加):

如果参数是一个字符,且

islower
为真,并且有一个或多个对应字符,如当前区域设置所指定,
isupper
为真,则
toupper
函数返回对应字符之一(对于任何给定的语言环境总是相同的); 否则,参数不变地返回。

即使

toupper
确实为非字母字符生成零,您的表达式
POINTS[toupper(word[i]) - 65]
也会计算为
POINTS[0 - 65]
,这不是您想要的。 (此外,除非在特殊情况下,例如在字符集之间进行转换,否则永远不要将
65
写成
'A'
。在普通源代码中,使用
'A'
作为“A”的代码。)

您必须编写代码来测试非字母字符,而不是为它们增加分数。


1
投票

当您将标点符号传递给

toupper()
时,它将返回该值不变。

然后您的代码将其用作

POINTS
数组的数组索引,该数组只有 26 个条目...导致 undefined behavior.

您想修改代码,使其跳过任何非大写或小写字母的字符。这是您的尝试与“正确”代码之间的主要区别。

不过,在拼字游戏的上下文中,最好的办法可能是使用返回值为零的

compute_score()
“退出”,因为标点字符无效。


0
投票

来自C标准(7.4.1.2 The isalpha function)

2 isalpha 函数测试任何字符为 isupper 或 islower 为真,或者是特定于语言环境的集合之一的任何字符 没有 iscntrl、isdigit、ispunct 的字母字符, 或 isspace 为真。200) 在“C”语言环境中,isalpha 仅返回真 对于 isupper 或 islower 为真的字符。

和(7.4.1.7 islower函数)

2 islower 函数测试任何小写字符 字母或是一组特定于语言环境的字符之一,其中没有 iscntrl、isdigit、ispunct 或 isspace 中的一个为真。 在“C”语言环境中, islower 仅对小写字母 返回真(定义在 5.2.1).

和(7.4.1.11 isupper 函数)

2 isupper 函数测试任何大写字符 字母或是一组特定于语言环境的字符之一,其中没有 iscntrl、isdigit、ispunct 或 isspace 中的一个为真。 在“C”语言环境中, isupper 仅对大写字母 返回 true(如定义在 5.2.1).

所以在这段代码中

for (int i = 0, N = strlen(word); i < N; i++)
{
    if (isupper(word[i]))
    {
        score += POINTS[word[i] - 'A'];
    }
    else if (islower(word[i]))
    {
        score += POINTS[word[i] - 'a'];
    }
}

在“C”语言环境中只处理字母。

在此代码片段中

//Convert array of chars to uppercase and solve
for (int i = 0, N = strlen(word); i < N; i++)
{
    score = score + POINTS[toupper(word[i]) - 65];
}

已处理所有符号。

你可以这样写

//Convert array of chars to uppercase and solve
for (int i = 0, N = strlen(word); i < N; i++)
{
    if ( isalpha( ( unsigned char )word[i] ) )
    {
        score = score + POINTS[toupper(word[i]) - 'A'];
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.