我正在学习C. 我希望我的程序做的是提示三个变量使用if语句将它们与特定值进行比较并返回true并仅在(所有)比较为真时打印欢迎消息。其他任何东西都返回false并打印一条遗憾的消息。 但是当我编译并运行代码时,如下所示。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
int years;
char name[15];
char gender[7];
char evaluation[7];
char age[2];
printf ("enter name, please ");
fgets (name, 15, stdin);
printf ("enter gender, please ");
fgets (gender, 7, stdin);
printf ("enter evaluation, please ");
fgets (evaluation, 20, stdin);
printf ("Please enter age ");
fgets (age, 2, stdin);
years = strlen (age);
{
if ((strcmp (gender, "male") == 1)
&& (strcmp (evaluation, "good") == 1) && years < 50)
printf ("welcome volunteer, %s . You're fit to participate\n",
name);
else
printf ("Sorry, %s. You're not fit to participate/n", name);
}
return (0);
}
- 编译时没有错误,也没有警告。 但, - 如果前两个比较(性别和评估)中的任何一个为真,则if语句返回true。
但是, - 当all都为false时返回false。 和 - 当前两个比较,性别和评估都是假的,第三个比较,年龄,是真的,它返回错误。
我想知道我的if语句有什么问题。 谢谢你的帮助
答案 0 :(得分:2)
strcmp
无法按照您认为的方式运作。如果字符串相同,则返回0(不是1),如果第一个字符串排序低于第二个字符串,则返回小于1的值(通常为-1
,但不依赖于它)如果第二个更高,则值大于0(可能为1,也可能不为1)。
因此,当您检查字符串是否相等时,您实际检查的是字符串的非常特殊的不等式。它们可能是你的程序行为不端的原因。
通常,每当函数返回意外结果时,请务必查看该函数的文档,以确保不会滥用它。
答案 1 :(得分:1)
你没有达到你的条件,因为当你得到一个匹配时,你期望从strcmp
获得不同的回报。
来自strcmp
联机帮助页:
如果找到s1(或其前n个字节),则strcmp()和strncmp()函数返回小于,等于或大于零的整数,小于,匹配或为大于s2。
尝试对strcmp
中使用的字符串进行否定测试。
if (!strcmp(gender_str, "male"))
答案 2 :(得分:1)
你有一些错误。正如其他人所说,如果字符串相等,strcmp
应返回0。
第二件事,在读入值
后删除换行符 gender[strlen(gender) - 1] = '\0';
evaluation[strlen(evaluation) - 1] = '\0';
第三,years = strlen (age);
应为years = atoi(age)
答案 3 :(得分:1)
通过尝试将缓冲区大小限制为适合的范围,您无意中将自己射入脚中。例如,char gender[7];
将保留female\0
,但输入结束时'\n'
会发生什么?
它仍未读入输入缓冲区(stdin
此处),等待您下次调用fgets
时出现问题(有疑问为什么当您输入female
代码时跳过 age
提示符?)如果一只猫踩到键盘并输入kkkkkkkkkkkkkkkkkkkkkkkkk
gender
,或者一个坚果用户输入you go figure it out!
会怎样? }?
第一课 ,在尝试用户输入时,请勿尝试微输入输入数组大小。为您的输入选择适当大小的缓冲区(64
,128
或256
字符就可以了。如果您使用内存非常有限的嵌入式系统,请确保减少,但正常使用时,一些额外的字节永远不会受到伤害。
第二课 - 始终检查是否已读取整行,并且其他字符不会保持未读状态,等待您在下次阅读时将其搞砸。你怎么做到这一点?很简单,fgets
读取直到并包括下一个 '\n'
(或size
中指定的最大字符数,包括 nul-byte < / em>的)。如果您检查的是最后一个字符且不是'\n'
,则表示您遇到了 短读 ,并且输入缓冲区中还有其他字符仍然存在未读。
第三课 - fgets
读取,包括下一个 '\n'
。比较时你认为会发生什么:
if (strcmp ("male\n", "male") == 0)
您需要检查并删除输入末尾的'\n'
(如果存在)。
如何?由于这是你将为每个输入做的事情,因此有一个你可以调用的函数来检查输入结尾是否存在newline
是否有意义,如果是,覆盖 '\n'
带有无终止字符(简称为0
或等效'\0'
表单)。如果您的输入中没有'\n'
,您知道它在输入缓冲区中仍未读取,因此您需要读取&amp;如果剩余部分不需要或读取&amp;读取,则丢弃该输入行中的所有剩余字符。进程输入,如果是的话。您可以使用以下内容完成此操作:
void check_eol (char *s)
{
if (!s || !*s) return; /* validate pointer & non-empty s */
if (*s == '\n') { *s = 0; return; } /* avoid strlen call if 1st is \n */
size_t len = strlen (s); /* get lenth and check if last char is \n */
if (s[len - 1] == '\n')
s[len - 1] = 0; /* if so, overwrite '\n' with nul-char */
else { /* otherwise '\n' remains in input buffer, read rest */
int c; /* of line, to prevent failure on next call to fgets */
while ((c = getchar()) != '\n' && c != EOF) {}
}
}
(您可以添加FILE *
参数并使用fgetc
代替getchar()
,如果您的阅读时间不是stdin
)
将拼图的所有部分组合在一起,并将age
和gender
数组放在一边以说明重点,以及其他一些提示,您可以使用代码执行以下操作:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* use constants instead of 'magic' numbers in your code.
* since you know the limit of age and gender, you can tailor
* the size, otherwise, it is better to create a buffer large
* enough to handle any name or evaluation.
*/
enum { MAXA = 4, MAXG = 8, MAXE = 32, MAXC = 256 };
void check_eol (char *s);
int main (void) {
/* int years = 0; */
char name[MAXC] = "", /* initializing char arrays all 0 can insure */
gender[MAXG] = "", /* nul-terminated strings if you forget :) */
evaluation[MAXE] = "",
age[MAXA] = "";
printf ("enter name, please (max: %3d) : ", MAXC - 1);
fgets (name, MAXC, stdin);
check_eol (name);
printf ("enter gender, please (max: %3d) : ", MAXG - 1);
fgets (gender, MAXG, stdin);
check_eol (gender);
printf ("enter evaluation, please (max: %3d) : ", MAXE - 1);
fgets (evaluation, MAXE, stdin);
check_eol (evaluation);
printf ("Please enter age (max: %3d) : ", MAXA - 1);
fgets (age, MAXA, stdin);
check_eol (age);
if (*age < '0' || '9' < *age) { /* make sure 1st char is a number */
fprintf (stderr, "error: non-numeric age entered.\n");
return 1;
}
// years = strlen (age); /* WTF?? */
if ((strcmp (gender, "male") == 0)
&& (strcmp (evaluation, "good") == 0) && *age < 5 + '0')
printf ("\nwelcome volunteer, %s . You're fit to participate\n",
name);
else
printf ("\nSorry, '%s'. You're not fit to participate\n", name);
return (0);
}
/** check for '\n' at end of 's', overwrite with 0 if present, otherwise
* read remaining chars from stdin.
*/
void check_eol (char *s)
{
if (!s || !*s) return; /* validate pointer & non-empty s */
if (*s == '\n') { *s = 0; return; } /* avoid strlen call if 1st is \n */
size_t len = strlen (s); /* get lenth and check if last char is \n */
if (s[len - 1] == '\n')
s[len - 1] = 0; /* if so, overwrite '\n' with nul-char */
else { /* otherwise '\n' remains in input buffer, read rest */
int c; /* of line, to prevent failure on next call to fgets */
while ((c = getchar()) != '\n' && c != EOF) {}
}
}
( 注意: 检查age < 50
只检查age
的第一个字符是否小于5
,测试可以简单地写成*age < '5'
,它目前的编写方式是等效的吗?为什么/为什么不呢?)
示例使用/输出
适合 - 男性,良好,&lt; 50$ ./bin/rfmt
enter name, please (max: 255) : Somebody With Avery-Longname
enter gender, please (max: 7) : male
enter evaluation, please (max: 31) : good
Please enter age (max: 3) : 49
welcome volunteer, Somebody With Avery-Longname . You're fit to participate
不合适 - 男,好,= 50
$ ./bin/rfmt
enter name, please (max: 255) : Somebody With Avery-Longname
enter gender, please (max: 7) : male
enter evaluation, please (max: 31) : good
Please enter age (max: 3) : 50
Sorry, 'Somebody With Avery-Longname'. You're not fit to participate
不适合 - unknown
,好,&lt; 50
$ ./bin/fgets_user_input
enter name, please (max: 255) : Somebody With Avery-Longname
enter gender, please (max: 7) : unknown
enter evaluation, please (max: 31) : good
Please enter age (max: 3) : 49
Sorry, 'Somebody With Avery-Longname'. You're not fit to participate
仔细看看,如果您有任何疑问,请告诉我。希望其中一些有用。