提问人:Ahmad Fudhail 提问时间:11/11/2023 最后编辑:chqrlieAhmad Fudhail 更新时间:11/12/2023 访问量:122
我的 C 程序代码运行流畅,除了一个“else if”语句 [关闭]
My C program code run smoothly except one "else if" statement [closed]
问:
这是我的整个代码:
#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_size
sizeof
"CEIL"
"CEILI"
"CELL"
"CELLI"
答:
在您的数组中包含 79 个元素,但您将其硬编码为,当您随后搜索超过 79 个元素时,这会导致缓冲区溢出。让编译器通过以下命令推断数组的大小:validword()
dictionary
int dictionary_size = 100;
int dictionary_size = sizeof dictionary / sizeof *dictionary;
您的程序对我进行了段错误,并且在进行此更改后我无法重现观察到的行为。
我还重新设计了您的程序以解决溢出(和),检查返回值(),处理恶意输入(),使用控制流消除标志(),使用符号常量和,提取(重复)功能到它们自己的函数中,并通过连接字符串来减少调用次数,用于不变的值。scanf("%s", ...)
found_words
scanf()
flush()
valid
enum
printf()
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()
评论
dictionary_size
作为 .size_t
我重新编写了您的代码以缩短它(并消除了许多已遇到和尚未遇到的问题。这是作为“学习资源”提供给 OP 的,以了解解决挑战的另一种方法。
下面的代码只有几条注释,所以这里有一些值得注意的功能:
- "定义的函数是声明的函数。在使用函数之前定义函数意味着不需要单独的函数原型(在像这样的简单单文件程序中)。减少维护。
puts()
比 更简单。读者知道没有必要寻找格式说明符和参数。printf()
- 这将两个“词典”的搜索组合成一个函数。“DRY”代表“不要重复自己”。
NULL
标记每个词典的末尾。遍历列表时索引的便捷替代方法。(未来的增强功能:手动“排序”两个词典中的单词,然后尽早退出线性搜索。字谜列表将很短。(排序!)冒犯性词语列表可能值得使用二叉搜索方案......- 你做得很好,从中分解了 3 个函数,但随后让程序的实质 - 玩游戏 - 缩进,而不是在它自己的独立函数中。
main()
scanf()
对于初学者来说是个坏消息。请注意以下代码中的用法。fgets()
- (意见)扫描代码时,(非必需的)大括号的细丝可能会分散注意力。需要一些纪律来确保陈述清晰简洁并适当缩进(以显示它们与控制性表达的关系)。我更喜欢更少的大括号。在适当的时候使用它们,而不是教条地使用它们。
- 我使用了幻数,让呼叫者选择应该搜索 2 个词典中的哪一个。我把它留给 OP 练习,用常量代币替换这些代币。
0
1
该程序的“流程”与 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 个字谜的字母选择。
评论
dictionary_size = 100
sizeof dictionary / sizeof *dictionary
scanf()
fgets()
sscanf()