[英]How to count only letters in string?
我正在嘗試編寫一個計算字符串中多個元素的程序。 其中第一個是字母。
該作業是 CS50 第 2 周問題集的一部分,因此包含庫。
使用while
條件我能夠計算每個字符,但是一旦我添加了isalnum
(檢查字符是否為字母數字),代碼就會停止工作。
我究竟做錯了什么?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void) {
string text = get_string("Text: ");
printf("%s, \n", text);
int letters = 0;
while (text[letters] != '\0') {
if (isalnum(text[letters])) {
letters++;
}
}
printf("%i \n", letters);
}
這里展示了如何定義正確的循環
size_t letters = 0;
for ( size_t i = 0; text[i] !='\0'; i++ )
{
if ( isalnum( ( unsigned char )text[i] ) )
{
letters++;
}
}
printf( "%zu\n", letters );
如果你想使用一個while循環,那么它可以看起來像
size_t letters = 0;
size_t i = 0;
while ( text[i] !='\0' )
{
if ( isalnum( ( unsigned char )text[i++] ) )
{
letters++;
}
}
printf( "%zu\n", letters );
注意 function isalnum
檢測字母和數字。 如果您只需要計算字母,請使用 function isalpha
。
如果您只想計算字母:
size_t count_letters(const char *str)
{
size_t count = 0;
while(*str)
{
count += !!isalpha(*str++);
}
return count;
}
或者如果你更喜歡for
循環
size_t count_letters_for_loop(const char *str)
{
size_t count = 0;
for(; *str; str++)
{
count += !!isalpha(*str);
}
return count;
}
正如大衛建議的那樣:
!!
操作在邏輯上否定該值的兩倍。 由於任何邏輯運算都會給出 0 或 1,因此這種雙重否定對任何非零值給出1
,或對零給出0
。 需要它,因為 isalpha function Returns non-zero value if c is an alphabet, else it returns 0.
嘗試將這樣的邏輯移動到單獨的函數中。 是C
語言中非常重要的技能
您的while
循環有一個缺陷:您使用相同的變量來計算字母數字字符並索引字符串。 它僅在所有字符都是字母數字的情況下才有效,否則您將獲得無限循環,因為您停止遞增letter
。
您應該使用帶有索引i
的for
循環。
還要注意isalnum()
所有來自<ctype.h>
的函數對於負值都是未定義的,除了EOF
。 在默認情況下對char
進行簽名的平台上,字符串中的某些字符可能具有負值,如果將它們傳遞給isalnum()
會導致未定義的行為。 您應該將char
值轉換為(unsigned char)
以避免這種情況。
這是修改后的版本。
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
int main(void) {
string text = get_string("Text: ");
printf("%s, \n", text);
int letters = 0;
for (int i = 0; text[i] != '\0'; i++) {
if (isalnum((unsigned char)text[i])) {
letters++;
}
}
printf("%i\n", letters);
return 0;
}
正如您所發現的,由於並非字符串中的所有字符都保證是字母數字字符,因此您將letters
用作計數器和索引是有缺陷的。 當您遇到一個不是 alpha 也不是數字的字符時, if (isalnum(text[letters]))
測試為 false 並且letters
永遠不會遞增,從而導致此時出現無限循環。 (你在下一次迭代中再次測試同一個角色——結果相同——而且風景永遠不會改變......)
正如所有其他非常好的和非常正確的答案所建議的那樣,只需使用一個單獨的循環計數器變量(或指針)並遞增它來迭代你的字符串。
您可能會做的另一件事來驗證您的邏輯(在輸出isalnum()
字符時)只是取消使用printf
重新打印原始字符串(從您的條目中您可以看到它),而不是 output 字符符合您的標准。 例如:
for (int i = 0; text[i]; i++) {
if (isalnum((unsigned char)text[i])) {
putchar (text[i]);
letters++;
}
}
這只是您的 output 的一個細微變化,它提供雙重任務,提供您的 output 並提供與所用標准匹配的每個字符的確認。
另請注意,沒有必要#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
將計數移入 A Function
您可以輕松地將字母數字字符的計數移動到 function 中。 將字符串傳遞給 function 的一個好處是 function 接收的指針是來自main()
的指針的副本(C 是按值傳遞)。 這使您可以簡單地使用參數進行迭代並返回字母數字字符的計數,例如
int countalnum (const char *s)
{
int letters = 0;
while (*s)
if (isalnum((unsigned char)*s++))
letters++;
return letters;
}
(注意:您必須將參數作為const char *
傳遞以使用指向常量 char 的指針。您不能使用 cs50 typedef 使用const string
。如果您不更改 function 中傳遞的值,則作為const
傳遞允許編譯器進行優化,否則將無法進行)
使用上面的 function,您的代碼可簡化為:
#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
但是在這里,使用 function 會導致在main()
中打印整個原始字符串。 您可以根據需要調整 output。
你說是字母,然后你用isalnum
? 因此,在您的情況下,數字將被計為字母,並且您增加循環計數的字母的值,僅當它是字母時才迭代字符串,以便在條件為假時導致無限循環這里是一個解決方案:
#include <stdio.h>
#include <ctype.h>
int countLetters(char *str) {
int letters = 0, ind = 0;
while(str[ind] != '\0')
isalpha((unsigned char)str[ind++]) && letters++;
return letters;
}
int main(void) {
char text[100];
fgets(text, sizeof(text), stdin);
printf("%i", countLetters(text));
return 0;
}
// input: hello 15-p */x
// output: 7
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.