我的 C 程序代码运行流畅,除了一个“else if”语句 [关闭]

My C program code run smoothly except one "else if" statement [closed]

提问人:Ahmad Fudhail 提问时间:11/11/2023 最后编辑:chqrlieAhmad Fudhail 更新时间:11/12/2023 访问量:122

问:


想改进这个问题吗?通过编辑这篇文章添加详细信息并澄清问题。

10天前关闭。

这是我的整个代码:

#include <stdio.h>
#include <string.h>                             

void display_instructions();

int validword();

int offensive();

int main() 
{
    char puzzle[50] = {" T H\nC L N\n U A"};  
    char guess[50]; 
    int isalpha(); 
    char found_words[100][10];
    int found_words_count = 0;  

    while (1) {       //use while(1) to apply break when user want to exit
        int choice;
        printf("Welcome to Spelling Bee! Choose:\n");
        printf("1: New Game\n");
        printf("2: Help\n");
        printf("3: Exit\n");
        printf("Enter your choice: ");
        scanf("%d", &choice);

        if (choice == 1) {
            found_words_count = 0;  

            while (1) {
                printf("--------------------\n");
                printf("Here is your puzzle:\n");
                printf("%s\n", puzzle);
                printf("----------------------------\n");
                printf("Guess a word or END to quit: ");
                scanf("%s", guess);

                if (strcmp(guess, "END") == 0) {  
                    break;  // Exit the game
                }

                if (!isalpha(guess[0])) {   
                    printf("\"%s\" : Consists of numbers/symbols\n", guess);  
                } else {             //when the user enter the alphabet, now the loop when user         enter alphabet will start,
                    int valid = 0;  //initialize the valid number inserted as 0
                    for (int i = 0; i < found_words_count; i++) {
                        if (strcmp(found_words[i], guess) == 0) {
                            printf("%s: You already made that word.\n", guess);
                            valid = -1;
                            break;
                        }
                    }

                    if (valid != -1) {
                        if (offensive(guess)) {
                            printf("%s: Offensive word\n", guess);
                        } else if (strlen(guess) < 4) {
                            printf("%s: Too short\n", guess);
                            //will put pangram here
                        } else if (!validword(guess)) {
                            printf("Inside else if (!validword(guess)) block\n");
                            printf("%s: Invalid word\n\n", guess);
                        } else {
                            strcpy(found_words[found_words_count], guess);
                            printf("%s: Valid word\n", guess);
                            printf("You made the following words so far:\n");
                            printf("-----------------------------------\n");

                            for (int i = 0; i <= found_words_count; i++) {
                                printf("%s ", found_words[i]);
                            }

                            printf("\n");
                            found_words_count++;
                        }
                    }
                }
            }
        } else if (choice == 2) {
            display_instructions();
        } 
        else if (choice == 3) {
            break;
        } else {
            printf("Invalid choice. Please choose 1, 2, or 3.\n");
        }
    }
}

//function definition
void display_instructions()
{
    printf("\n");
    printf("Spelling Bee Game Instructions:\n");
    printf("-----------------------------------------------\n");
    printf("1. You will be given a 7-letter puzzle.\n");
    printf("2. Enter a valid word using the given letters.\n");
    printf("3. Words must be at least 4 letters long.\n");
    printf("4. You cannot use the same word twice.\n");
    printf("5. The word must not be offensive.\n");
    printf("6. To exit the game, type 'END' and press Enter.\n");
    printf("\n");
}

int validword(char *word)
{
    char *dictionary[] = {  
        "CEIL", "CEILI", "CELL", "CELLI", "CELLO", "CELT", "CIEL", "CILL",
        "CITE", "CITO", "CIVE", "CIVET", "CIVIC", "CIVIL", "CLEEVE", "CLEVE",
        "CLITIC", "CLOT", "CLOVE", "COCCI", "COCCO", "COCO", "COCOTTE",
        "COIL", "COIT", "COLE", "COLIC", "COLL", "COLLECT", "COLLECTIVE",
        "COLLET", "COLLIE", "COLT", "COOEE", "COOL", "COOLIE", "COOT", "COOTIE",
        "COTE", "COTT", "COVE", "COVET", "ECCE", "ECCO", "ECLECTIC", "ELECT",       
        "ELECTIVE", "ELICIT", "ETIC", "EVICT", "ICICLE", "ILLICIT", "LICE",
        "LICIT", "LOCI", "LOCO", "LOTIC", "OCELLI", "OCELOT", "OCOTILLO", "OCTET",
        "OLEIC", "OOLITIC", "OTIC", "TELCO", "TELIC", "TICE", "TOCO", "VELOCE",
        "VICE", "VOICE" };
    
    int dictionary_size = 100;  //declare variable

    for (int i = 0; i < dictionary_size; i++) {
        if (strcmp(dictionary[i], word) == 0) {
            return 1;
        }
    }

    return 0;
}

int offensive(char *word)
{
    char *offensive_words[] = { "SHIT", "FUCK", "BITCH", "MOTHERFUCKER", "BARUA", "BABI", "BUTO" };

    int offensive_words_count = 7;

    for (int i = 0; i < offensive_words_count; i++) {
        if (strcmp(offensive_words[i], word) == 0) {
            return 1;
        }
    }

    return 0;
}

当我输入任何奇怪的单词或无效的单词时,循环将立即结束。我认为问题可能来自无效词的陈述。这是我认为问题来自的部分:else if

    if (valid != -1) {
        if (offensive(guess)) {
            printf("%s: Offensive word\n", guess);
        } else if (strlen(guess) < 4) {
            printf("%s: Too short\n", guess);
            //will put pangram here
   -->  } else if (!validword(guess)) {
            printf("Inside else if (!validword(guess)) block\n");
            printf("%s: Invalid word\n\n", guess);
   -->  } else {
            strcpy(found_words[found_words_count], guess);
            printf("%s: Valid word\n", guess);
            printf("You made the following words so far:\n");
            printf("-----------------------------------\n");

            for (int i = 0; i <= found_words_count; i++) {
                printf("%s ", found_words[i]);
            }

            printf("\n");
            found_words_count++;
  • 所以我使用 .现在它可以检测到无效的单词。新的问题是它只能检测到我的字典中的几个单词(,,,)。除此之外,它会认为该词无效。dictionary_sizesizeof"CEIL""CEILI""CELL""CELLI"
数组 c 字符串 循环 if 语句

评论

1赞 Ted Lyngmo 11/11/2023
尝试再次正确格式化它。Tripple-backticks-newline-<paste>-newline-tripple-backticks 就可以了。
1赞 Allan Wind 11/11/2023
我正在重新格式化您的代码,然后您删除了您的问题......那么你要再次删除它吗?
1赞 Allan Wind 11/11/2023
你的程序对我来说是段错误的,因为你的字典有 79 个元素,但你声称有 100 个元素。用于让编译器为您推断数组大小。dictionary_size = 100sizeof dictionary / sizeof *dictionary
1赞 Allan Wind 11/11/2023
另外,不要发布代码两次。您可以发表评论或告诉我们您认为问题出在哪里。由于它是一个交互式程序,因此您应该告诉我们您提供了哪些输入来触发问题。
1赞 Allan Wind 11/11/2023
读取字符串时,始终使用最大字段宽度 OR use everywhere 并用于解析数据。scanf()fgets()sscanf()

答:

3赞 Allan Wind 11/11/2023 #1

在您的数组中包含 79 个元素,但您将其硬编码为,当您随后搜索超过 79 个元素时,这会导致缓冲区溢出。让编译器通过以下命令推断数组的大小:validword()dictionaryint dictionary_size = 100;

int dictionary_size = sizeof dictionary / sizeof *dictionary;

您的程序对我进行了段错误,并且在进行此更改后我无法重现观察到的行为。

我还重新设计了您的程序以解决溢出(和),检查返回值(),处理恶意输入(),使用控制流消除标志(),使用符号常量和,提取(重复)功能到它们自己的函数中,并通过连接字符串来减少调用次数,用于不变的值。scanf("%s", ...)found_wordsscanf()flush()validenumprintf()const

#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int search(size_t words_len, const char *words[words_len], const char *word);

#define array_len(a) (sizeof (a) / sizeof (*a))
#define FOUND_WORDS_LEN 100
#define GUESS_LEN 49
#define GUESS_MIN_LEN 4
#define str(s) str2(s)
#define str2(s) #s

enum {
    NEW_GAME=1,
    HELP,
    EXIT
};

void display_instructions() {
    printf(
        "\n"
        "Spelling Bee Game Instructions:\n"
        "-----------------------------------------------\n"
        "1. You will be given a 7-letter puzzle.\n"
        "2. Enter a valid word using the given letters.\n"
        "3. Words must be at least 4 letters long.\n"
        "4. You cannot use the same word twice.\n"
        "5. The word must not be offensive.\n"
        "6. To exit the game, type 'END' and press Enter.\n"
        "\n"
    );
}

void free_found_words(size_t n, char *words[]) {
    for(size_t i = 0; i < n; i++)
        free(words[i]);

}

int flush() {
    for(;;) {
        int ch = getchar();
        if(ch == '\n' || ch == EOF)
            return ch;
    }
}

int isalpha_all(const char *word) {
    for(size_t i = 0; word[i]; i++)
        if(!isalpha(word[i]))
            return 0;
    return 1;
}

int new_game(const char *puzzle) {
    // consider storing data like this in a file so it's easy to update
    static const char *dictionary[] = {
        "CEIL", "CEILI", "CELL", "CELLI", "CELLO", "CELT", "CIEL", "CILL",
        "CITE", "CITO", "CIVE", "CIVET", "CIVIC", "CIVIL", "CLEEVE", "CLEVE",
        "CLITIC", "CLOT", "CLOVE", "COCCI", "COCCO", "COCO", "COCOTTE",
        "COIL", "COIT", "COLE", "COLIC", "COLL", "COLLECT", "COLLECTIVE",
        "COLLET", "COLLIE", "COLT", "COOEE", "COOL", "COOLIE", "COOT", "COOTIE",
        "COTE", "COTT", "COVE", "COVET", "ECCE", "ECCO", "ECLECTIC", "ELECT",
        "ELECTIVE", "ELICIT", "ETIC", "EVICT", "ICICLE", "ILLICIT", "LICE",
        "LICIT", "LOCI", "LOCO", "LOTIC", "OCELLI", "OCELOT", "OCOTILLO", "OCTET",
        "OLEIC", "OOLITIC", "OTIC", "TELCO", "TELIC", "TICE", "TOCO", "VELOCE",
        "VICE", "VOICE"};
    static const char *offensive_words[] = {"SHIT", "FUCK", "BITCH","MOTHERFUCKER","BARUA","BABI","BUTO"};

    char guess[GUESS_LEN+1];
    char *found_words[FOUND_WORDS_LEN];
    size_t found_words_count = 0;
    for(;;) {
        printf(
            "--------------------\n"
            "Here is your puzzle:\n"
            "%s\n"
            "----------------------------\n"
            "Guess a word or END to quit: ",
            puzzle
        );
        if(scanf("%" str(GUESS_LEN) "s", guess) != 1) {
            if(flush() == EOF) {
                free_found_words(found_words_count, found_words);
                return 1;
            }
            continue;
        }
        if(!strcmp(guess, "END"))
            break;
        if (!isalpha_all(guess))
            printf("\"%s\" : Consists of numbers/symbols\n", guess);
        else if(search(found_words_count, (const char **) found_words, guess))
            printf("%s: You already made that word.\n", guess);
        else if (search(array_len(offensive_words), offensive_words, guess))
            printf("%s: Offensive word\n", guess);
        else if (strlen(guess) < GUESS_MIN_LEN)
            printf("%s: Too short\n", guess);
        else if (!search(array_len(dictionary), dictionary, guess))
            printf("%s: Invalid word\n\n", guess);
        else {
            if(found_words_count >= FOUND_WORDS_LEN) {
                printf("Too many words were found\n");
                break;
            }
            found_words[found_words_count++] = strdup(guess);
            printf(
                "%s: Valid word\n"
                "You made the following words so far:\n"
                "-----------------------------------\n",
                guess
            );
            for (size_t i = 0; i < found_words_count; i++)
                printf("%s ", found_words[i]);
            printf("\n");
        }
    }
    free_found_words(found_words_count, found_words);
    return 0;
}

// Or use lsearch() from search.h
int search(size_t words_len, const char *words[words_len], const char *word) {
    for (size_t i = 0; i < words_len; i++)
        if (!strcmp(words[i], word))
            return 1;
    return 0;
}

int main(void) {
    const char puzzle[] = {" T H\nC L N\n U A"};
    for(;;) {
        printf(
            "Welcome to Spelling Bee! Choose:\n"
            "1: New Game\n"
            "2: Help\n"
            "3: Exit\n"
            "Enter your choice: "
        );
        int choice;
        if(scanf("%d", &choice) != 1) {
            printf("choice is invalid\n");
            if(flush() == EOF)
                break;
            continue;
        }
        if(choice == NEW_GAME) {
            if(new_game(puzzle))
                break;
        } else if (choice == HELP)
            display_instructions();
        else if(choice == EXIT)
            break;
        else
            printf("Invalid choice. Please choose 1, 2, or 3.\n");
    }
}

我改为主要重用该功能。它将使用更少的内存。缺点是您需要在返回之前打电话。char found_words[100][10];char *found_words[FOUND_WORDS_LEN];search()free_found_words()new_game()

评论

0赞 Harith 11/11/2023
dictionary_size作为 .size_t
1赞 Allan Wind 11/11/2023
@Harith是的,但我还必须更改循环变量以避免有关比较有符号和无符号值的警告。Op 是初学者,所以决定让它做一个最小的改变。
0赞 Allan Wind 11/11/2023
如果回答了您的问题,请单击复选标记以接受它。否则,请让我知道提供的解决方案有什么问题。
1赞 Allan Wind 11/12/2023
@chqrlie 当然可以。固定。
-1赞 Fe2O3 11/12/2023 #2

我重新编写了您的代码以缩短它(并消除了许多已遇到和尚未遇到的问题。这是作为“学习资源”提供给 OP 的,以了解解决挑战的另一种方法。

下面的代码只有几条注释,所以这里有一些值得注意的功能:

  1. "定义的函数是声明的函数。在使用函数之前定义函数意味着不需要单独的函数原型(在像这样的简单单文件程序中)。减少维护。
  2. puts()比 更简单。读者知道没有必要寻找格式说明符和参数。printf()
  3. 这将两个“词典”的搜索组合成一个函数。“DRY”代表“不要重复自己”。
  4. NULL标记每个词典的末尾。遍历列表时索引的便捷替代方法。(未来的增强功能:手动“排序”两个词典中的单词,然后尽早退出线性搜索。字谜列表将很短。(排序!)冒犯性词语列表可能值得使用二叉搜索方案......
  5. 你做得很好,从中分解了 3 个函数,但随后让程序的实质 - 玩游戏 - 缩进,而不是在它自己的独立函数中。main()
  6. scanf()对于初学者来说是个坏消息。请注意以下代码中的用法。fgets()
  7. (意见)扫描代码时,(非必需的)大括号的细丝可能会分散注意力。需要一些纪律来确保陈述清晰简洁并适当缩进(以显示它们与控制性表达的关系)。我更喜欢更少的大括号。在适当的时候使用它们,而不是教条地使用它们。
  8. 我使用了幻数,让呼叫者选择应该搜索 2 个词典中的哪一个。我把它留给 OP 练习,用常量代币替换这些代币。01

该程序的“流程”与 OP 的版本相比略有改动。这是为了满足我对游戏应该如何玩的品味。

一个明显的问题是,“有效字谜”列表不适合用户被告知使用的字母。这是OP的问题或本答案中没有涉及的难题。

#include <stdio.h>
#include <string.h>

void display_instructions( void ) {
    puts(
        "\n"
        "Instructions:\n"
        "-------------\n"
        "You will be given a 7-letter puzzle.\n"
        "Enter a valid word using the given letters.\n"
        "Words must be at least 4 letters long.\n"
        "You cannot use the same word twice.\n"
        "The word must not be offensive.\n"
        "To exit the game, type 'END' and press Enter.\n"
    );
}

char *lookup( char *word, int dictOff ) {
    char *off[] = {
        "shit", "fuck", "bitch", "motherfucker", "barua", "babi", "buto",
        NULL
    };

    char *dict[] = {
        "ceil", "ceili", "cell", "celli", "cello", "celt", "ciel", "cill",
        "cite", "cito", "cive", "civet", "civic", "civil", "cleeve", "cleve",
        "clitic", "clot", "clove", "cocci", "cocco", "coco", "cocotte",
        "coil", "coit", "cole", "colic", "coll", "collect", "collective",
        "collet", "collie", "colt", "cooee", "cool", "coolie", "coot", "cootie",
        "cote", "cott", "cove", "covet", "ecce", "ecco", "eclectic", "elect",
        "elective", "elicit", "etic", "evict", "icicle", "illicit", "lice",
        "licit", "loci", "loco", "lotic", "ocelli", "ocelot", "ocotillo", "octet",
        "oleic", "oolitic", "otic", "telco", "telic", "tice", "toco", "veloce",
        "vice", "voice",
        NULL,
    };

    char **p = dictOff ? dict : off;
    for( ; *p && stricmp( *p, word ); p++ ) {}
    return *p; // NULL means "not in list"
}

void play( void ) {
    char *cp, *found[100] = { NULL }; // 100 pointers into dictionary, not copies.
    size_t foundCnt = 0;

    while( foundCnt < sizeof found/sizeof *found ) {
        printf(
            "\n"
            "--------------------\n"
            "Here is your puzzle:\n"
            "%s\n"
            "----------------------------\n"
            "Guess a word or type 'end': ", " T H\nC L N\n U A" );

        char guess[50];
        fgets( guess, sizeof guess, stdin );
        guess[ strcspn( guess, "\n" ) ] = '\0';

        if( 0 == stricmp( guess, "end" ) )
            break;

        printf( "\n'%s': ", guess );
        if( strlen( guess ) < 4 )
            puts( "Too short" );

        else if( lookup( guess, 0 ) )
            puts( "Offensive" );

        else if( ( cp = lookup( guess, 1 ) ) == NULL )
            puts( "Invalid" );

        else {
            size_t i = 0;
            for( ; found[i] && 0 != stricmp( found[i], guess ); i++ ) {}

            if( found[i] )
                puts( "You already made that word." );
            else {
                puts( "Valid!" );
                found[ foundCnt++ ] = cp;
            }

            puts(
                "You have found these words:\n"
                "-----------------------------------" );
            for( i = 0; found[i]; i++ )
                printf( "(%d)%s ", i, found[i] );
            puts( "" );
        }
    }
}

int main( void ) {
    for( ;; ) {
        printf(
            "Welcome to Anagram!  Choose:\n"
            "'Exit'\n"
            "'Game'\n"
            "'Help'\n"
            "Your choice: "
        );

        char in[128];
        fgets( in, sizeof in, stdin );

        if( 0 == stricmp( in, "exit\n" ) )
            break;

        if( 0 == stricmp( in, "game\n" ) )
            play();

        else if( 0 == stricmp( in, "help\n" ) )
            display_instructions();

        else
            puts( "Invalid choice." );
    }

    return 0;
}

如果用户实际使用提供的字母的任意组合输入了 100 个“有效”字谜,则此版本将静默终止。这个版本的这个有限方面需要解决(如果有人能提供可以产生 100 个字谜的字母选择。