Как вы обнаружили, поскольку не все символы в вашей строке гарантированно являются буквенно-цифровыми символами, использование вами letters
в качестве счетчика и индекса является ошибочным. Когда вы встречаетесь с символом, который не является альфа и не числом, if (isalnum(text[letters]))
проверяет ложь, а letters
никогда не увеличивается, что приводит к бесконечному l oop в этой точке. (вы снова тестируете того же персонажа на следующей итерации - с тем же результатом - и декорации никогда не меняются ....)
Как и предполагают все другие очень хорошие и очень правильные ответы, просто используйте отдельную переменную счетчика l oop (или указатель) и увеличивайте ее для итерации по вашей строке.
Еще одна вещь, которую вы можете сделать для проверки вашего logi c (при выводе символов 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;
}
( примечание: вы должны передать параметр как const char *
, чтобы использовать указатель на константный символ. Вы не можете использовать const string
, используя определение типа cs50. Если вы не будете изменять значение, переданное в функции, передача const
позволяет компилятору выполнить оптимизацию, которую иначе он не смог бы сделать)
С помощью функции выше ваш код сокращается до:
#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()
. Вы можете настроить мощность по своему усмотрению.