所以,我是C的新手,这是我第一个上课的项目。 我基本上需要一个程序,询问用户他想要多少问题,然后检索一个正的最大8位数,可以是oct / dec / hex(它是随机的),然后要求用户将其转换为随机基数。 例如,如果我得到一个十进制数字它将随机要求我将其转换为hex或八进制。 在每个问题的最后,它表示如果我的转换是对还是错,并且在程序结束时它会显示我正确的问题。
一切顺利,直到我开始输入随机字母/字符,当它要求我转换为hex以外。 例如,如果它要求我将八进制转换为十进制,如果我输入单个字母,它有时会说它是正确的,它也会跳过问题并继续循环直到它变为hex。
我无法弄清楚我能做些什么。 这是我的代码:
#include #include #include int main() { int rightanswers = 0; int answer; int nquestions; printf("Number of questions:"); scanf("%d", &nquestions); srand((unsigned int) time(NULL)); unsigned char questions[nquestions]; for (int i=1; i<=nquestions; i++) { questions[i] = (rand()%255)+1; int randomnumb = (rand()%6)+1; switch(randomnumb) { case 1: printf("nConvert 0%o to base 10:", questions[i]); scanf("%d", &answer); if (answer == questions[i]) { rightanswers++; printf("Right!"); } else { printf("Wrong!"); } break; case 2: printf("nConvert 0%o to base 16:", questions[i]); scanf("%x", &answer); if (answer == questions[i]) { rightanswers++; printf("Right!"); } else { printf("Wrong!"); } break; case 3: printf("nConvert %d to base 8:", questions[i]); scanf("%o", &answer); if (answer == questions[i]) { rightanswers++; printf("Right!"); } else { printf("Wrong!"); } break; case 4: printf("nConvert %d to base 16:", questions[i]); scanf("%x", &answer); if (answer == questions[i]) { rightanswers++; printf("Right!"); } else { printf("Wrong!"); } break; case 5: printf("nConvert 0x%x to base 8:", questions[i]); scanf("%o", &answer); if (answer == questions[i]) { rightanswers++; printf("Right!"); } else { printf("Wrong!"); } break; case 6: printf("nConvert 0x%x to base 10:", questions[i]); scanf("%d", &answer); if (answer == questions[i]) { rightanswers++; printf("Right!"); } else { printf("Wrong!"); } break; } } printf("nYou got %d conversions right!", rightanswers); return 0; }
继续我的评论。 scanf
(和系列)给新的C程序员带来了用户输入的麻烦,因为与scanf
相关的众多陷阱。 主要是因为转换说明符在处理前导space
(例如space
, tab
, newline
等)方面表现不同,并且程序员无法validation返回 。 返回validation很关键,因为输入缓冲区中剩下的内容(例如stdin
)取决于是否成功进行转换。
scanf
返回成功转换的次数。 (例如scanf ("%s %d", strvar, &intvar)
)包含2
转换说明符 ( %s
和%d
)。 如果字符串和整数成功转换并存储在提供的变量中,则返回值为2
。 任何较少表示匹配失败或输入失败或用户通过Ctrl + D (或windoze上的Ctrl + Z )手动生成EOF
取消输入。
如果转换失败,或者由于匹配失败 (输入类型和转换说明符不匹配)或输入失败 (每个转换说明符没有足够的输入),从stdin
读取停止,则不会从输入读取其他字符缓冲区和所有字符都留下了 – 只是等待你下次调用scanf
。
此外,您必须考虑每次调用scanf
后留在输入缓冲区中的'n'
(由用户按Enter键生成)。 一些格式说明符将消耗前导空格而其他格式说明 符 (例如字符格式说明符不会),实际上%c
将很乐意将stdin
的'n'
作为下一个输入 。
具体来说,数字格式说明符(例如%d, %x, %o, %lf, ...
)都将忽略前导空格,因此您不必在下一次scanf
调用之前专门删除空格。 对于其他所有人。 这对于stdin
剩余(或可能保留)的内容的计算对于使用scanf
进行输入至关重要。 否则你只是要求输出看起来被跳过或者……无限循环。 (您可以按照制作格式字符串的方式处理空格)
所有这些都是为什么像fgets
这样的面向行的输入函数是处理用户输入的推荐方法。 它将读取并包括尾部'n'
,它可以简单地检查用户提供的所有输入字符是否正确读取。 (在validation用户输入之后,然后从fgets
(或POSIX getline
)填充的缓冲区中解析所需的任何内容
但是,由于您将多次遇到scanf
,因此非常值得花时间阅读(并理解) man scanf
。 是的,它读起来有点干,但它是唯一可以准确解释scanf
陷阱的位置。
考虑到这一点,下面提供了两个示例(对代码的修改),向您展示如何使用scanf
处理输入。 nquestions
的第一个读数只显示了使用scanf
validation整数输入,检查返回,处理用户取消(生成EOF
),最后清空任何保留有帮助函数empty_stdin()
字符的一般方法stdin
直到'n'
(由用户按Enter键生成)或找到EOF
。
用户输入的其余部分由辅助函数getintvalue
处理(因为您不希望在代码中反复复制validation代码)。 getintvalue
将提示显示并将格式字符串作为参数,但基本上只是为nquestions
中的nquestions
做了同样的事情。
其他变化。 questions[]
不需要数组。 一个简单的int
值就可以了。 在每种case
,您都不需要重复代码。 (已经移到了最后)。 其余的变化和问题在下面的评论中得到了解决:
#include #include #include #define PRMTSZ 128 /* if you need a constant define one */ /* or use an enum to define several */ enum { NSWITCH = 6, QMAX = 256 }; /* function to get integer value from user. * prompt user with 'prompt', read value with format 'fmt'. * returns int value or EOF on user cancelation of input. */ int getintvalue (const char *prompt, const char *fmt); /* simple function to empty remaining chars from stdin */ void empty_stdin(); int main (void) { int rightanswers = 0, nquestions = 0; srand (time(NULL)); /* example input loop -- loop continually until valid input or EOF */ for (;;) { int rtn = 0; printf ("Number of questions: "); if ((rtn = scanf ("%d", &nquestions)) == EOF) { fprintf (stderr, "warning: user canceled input.n"); return 1; } empty_stdin(); /* remove all remaining chars from stdin */ if (rtn == 1) /* good input */ break; /* handle matching or input failure */ fprintf (stderr, "error: invalid input.n"); } /* loops are ZERO based in C */ for (int i = 0; i < nquestions; i++) { /* declarations 1st in each block, for C89 portability - Win7, etc. */ char prompt[PRMTSZ] = ""; /* buffer for prompt */ int randomnumb = rand() % NSWITCH, /* values 0 - 5 */ question = rand() % QMAX, /* values 0 - 255 */ answer = 0; switch (randomnumb) { case 0: sprintf (prompt, "nConvert 0%o to base 10: ", question); /* let's use a getintvalue to validate user int input */ if ((answer = getintvalue (prompt, "%d")) == EOF) return 1; break; case 1: sprintf (prompt, "nConvert 0%o to base 16: ", question); if ((answer = getintvalue (prompt, "%x")) == EOF) return 1; break; case 2: sprintf (prompt, "nConvert %d to base 8: ", question); if ((answer = getintvalue (prompt, "%o")) == EOF) return 1; break; case 3: sprintf (prompt, "nConvert %d to base 16: ", question); if ((answer = getintvalue (prompt, "%x")) == EOF) return 1; break; case 4: sprintf (prompt, "nConvert 0x%x to base 8: ", question); if ((answer = getintvalue (prompt, "%o")) == EOF) return 1; break; case 5: sprintf (prompt, "nConvert 0x%x to base 10: ", question); if ((answer = getintvalue (prompt, "%d")) == EOF) return 1; break; default: fprintf (stderr, "error: something went wrong in switch.n"); goto badswitch; break; } if (answer == question) { rightanswers++; printf ("Right!n"); } else printf ("Wrong!n"); badswitch:; } /* always end with 'n' for POSIX compiant EOF */ printf("nYou got %d conversions right!n", rightanswers); return 0; } int getintvalue (const char *prompt, const char *fmt) { int value = 0; /* input loop -- loop continually until valid input or EOF */ for (;;) { int rtn = 0; printf ("%s: ", prompt); if ((rtn = scanf (fmt, &value)) == EOF) { fprintf (stderr, "warning: user canceled input.n"); return rtn; } empty_stdin(); /* remove all remaining chars from stdin */ if (rtn == 1) /* good input */ break; /* handle matching or input failure */ fprintf (stderr, "error: invalid input.n"); } return value; } void empty_stdin() { int c; do c = getchar(); while (c != 'n' && c != EOF); }
以下是各种validation运行,显示在程序的各个阶段正确处理错误输入或用户取消。
示例当一切顺利
$ ./bin/inttestscanf Number of questions: 4 Convert 218 to base 16: : da Right! Convert 0325 to base 10: : 213 Right! Convert 0xe to base 10: : 14 Right! Convert 0x39 to base 8: : 71 Right! You got 4 conversions right!
用户取消问题数量时的示例
$ ./bin/inttestscanf Number of questions: foo error: invalid input. Number of questions: bar error: invalid input. Number of questions: warning: user canceled input.
用户输入无效输入时的示例
$ ./bin/inttestscanf Number of questions: 4 Convert 023 to base 16: : no good error: invalid input. Convert 023 to base 16: : 13 Right! Convert 0xc7 to base 8: : foo error: invalid input. Convert 0xc7 to base 8: : 307 Right! Convert 0353 to base 16: : eb Right! Convert 0x76 to base 10: : f8 error: invalid input. Convert 0x76 to base 10: : 118 Right! You got 4 conversions right!
( 注意:想想如果scanf
需要hex值并且用户输入以af
开头的任意字符串会发生什么?)
仔细看看,如果您有其他问题,请告诉我。
如果scanf
遇到无法分配的内容,它会停止并返回。 您尝试分配的变量不会更改 – 但您检查其值是否已被读取。 它将简单地包含之前的任何内容或随机内容。
要使用scanf,您需要始终检查其返回值 ,它会告诉您已分配了多少变量。 只有当此计数显示您的变量已真正分配时,才应访问其内容。
请注意,扫描失败后,“不可读”的数据仍将在输入流中,下一个scanf将尝试再次读取相同的数据。
以上就是c/c++开发分享C – 尝试扫描hex/十进制/八进制值以检查它们是否等于用户输入相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/522048.html