正如您所发现的,由于并非字符串中的所有字符都保证是字母数字字符,因此您将其letters
用作计数器和索引是有缺陷的。当您遇到一个不是 alpha 也不是数字的字符时,if (isalnum(text[letters]))
测试为 false 并且letters
永远不会增加,从而导致此时出现无限循环。(你在下一次迭代中再次测试同一个角色——结果相同——而且风景永远不会改变......)
正如所有其他非常好的和非常正确的答案所建议的那样,只需使用一个单独的循环计数器变量(或指针)并递增它来迭代你的字符串。
您可能会做的另一件事来验证您的逻辑(在输出isalnum()
字符时)是简单地取消重新打印原始字符串printf
(您的条目就在您面前),而是输出与您的条件匹配的字符. 例如:
for (int i = 0; text[i]; i++) {
if (isalnum((unsigned char)text[i])) {
putchar (text[i]);
letters++;
}
}
这只是您的输出的一个微小变化,它提供双重职责,提供您的输出,并提供与所用标准匹配的每个字符的确认。
另请注意,没有必要,#include <string.h>
因为在您的代码中没有需要包含它的功能。通过这些更改,一个简单的示例可能是:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
int main(void) {
int letters = 0;
string text = get_string("Text: ");
for (int i = 0; text[i]; i++) {
if (isalnum((unsigned char)text[i])) {
putchar (text[i]);
letters++;
}
}
printf (", %d\n", letters);
}
示例使用/输出
$ ./bin/ltrcountcs50-1
Text: 123.abc-456_def_*.*_789
123abc456def789, 15
将计数移动到函数中
您可以轻松地将字母数字字符的计数移动到函数中。将字符串传递给函数的一个好处是函数接收到的指针是指针的副本main()
(C 是按值传递)。这使您可以简单地使用参数进行迭代并返回字母数字字符的计数,例如
int countalnum (const char *s)
{
int letters = 0;
while (*s)
if (isalnum((unsigned char)*s++))
letters++;
return letters;
}
(注意:您必须传递参数 asconst char *
以使用指向常量 char 的指针。您不能使用const string
cs50 typedef。如果您不更改函数中传递的值,传递 asconst
允许编译器进行优化,否则不会能够制作)
使用上面的函数,您的代码可以简化为:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
int countalnum (const char *s)
{
int letters = 0;
while (*s)
if (isalnum((unsigned char)*s++))
letters++;
return letters;
}
int main(void) {
string text = get_string("Text: ");
printf ("%s, %d\n", text, countalnum(text));
}
示例使用/输出
$ ./bin/ltrcountcs50-1
Text: 123.abc-456_def_*.*_789
123.abc-456_def_*.*_789, 15
但是在这里,使用该函数会导致将整个原始字符串打印在main()
. 您可以根据需要调整输出。