我的if语句返回意外结果

时间:2016-08-24 18:11:39

标签: c if-statement

我正在学习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语句有什么问题。 谢谢你的帮助

4 个答案:

答案 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!会怎样? }?

第一课 ,在尝试用户输入时,请勿尝试微输入输入数组大小。为您的输入选择适当大小的缓冲区(64128256字符就可以了。如果您使用内存非常有限的嵌入式系统,请确保减少,但正常使用时,一些额外的字节永远不会受到伤害。

第二课 - 始终检查是否已读取整行,并且其他字符不会保持未读状态,等待您在下次阅读时将其搞砸。你怎么做到这一点?很简单,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

将拼图的所有部分组合在一起,并将agegender数组放在一边以说明重点,以及其他一些提示,您可以使用代码执行以下操作:

#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

仔细看看,如果您有任何疑问,请告诉我。希望其中一些有用。