As you have found, since not all characters in your string are guaranteed to be alpha-number characters, your use of letters
as a counter and an index is flawed. When you encounter a character that is not alpha and not a number, if (isalnum(text[letters]))
tests false and letters
is never incremented resulting in an infinite loop at that point. (you test the same character again on the next iteration -- with the same result -- and the scenery never changes....)
As all of the other very good and very correct answers suggest, just use a separate loop counter variable (or a pointer) and increment that to iterate over your string.
One other thing you might do to validate your logic (while outputting the isalnum()
characters) is simply to do away with reprinting the original string with printf
(you have that right in front of you from your entry), and instead output the characters that match your criteria. For example:
for (int i = 0; text[i]; i++) {
if (isalnum((unsigned char)text[i])) {
putchar (text[i]);
letters++;
}
}
That is just a slight variation on your output which serves double-duty providing your output and also providing confirmation of each character that matched the criteria used.
Also note, there is no need to #include <string.h>
as there are no functions requiring its inclusion used in your code. With those changes a quick example could be:
#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);
}
Example Use/Output
$ ./bin/ltrcountcs50-1
Text: 123.abc-456_def_*.*_789
123abc456def789, 15
Moving Count Into A Function
You can move your counting of alpha-num characters into a function easily. One benefit of passing your string to a function is the pointer received by the function is a copy of the pointer from main()
(C is pass-by-value). That allows you to simply iterate with the parameter and return the count of alpha-num characters, e.g.
int countalnum (const char *s)
{
int letters = 0;
while (*s)
if (isalnum((unsigned char)*s++))
letters++;
return letters;
}
(note: you must pass the parameter as const char *
to use a pointer to constant char. You cannot use const string
using the cs50 typedef. If you will not be changing the value passed in the function, passing as const
allows the compiler to make optimization it would not otherwise be able to make)
With the function above, your code reduces to:
#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));
}
Example Use/Output
$ ./bin/ltrcountcs50-1
Text: 123.abc-456_def_*.*_789
123.abc-456_def_*.*_789, 15
But here, using the function results in printing the entire original string in main()
. You can adjust the output as desired.