繁体   English   中英

C 中关于 bool 和 if/else if 的代码审查

[英]Code review in C regarding bools and if/else if

在有关 CS50 第 2 周问题设置密码的一些帮助下,我想出了这个解决方案。 提示是使用 2 function 想出一个简单的密码检查器,验证输入的字符串是否包含 1 个大写字母、1 个小写字母、1 个数字和 1 个符号。 建议是使用布尔值。 但是,我有 3 个关于它如何以及为何起作用的问题:

  1. Bools ......我仍然在与他们作斗争。 为什么我不必放置 =true 部分? 是否只是假定布尔值必须为真?
  2. 做一些研究,我现在明白if子句中的最后一个语句不必是else ,因为不能指定。 但是为什么一个if和三个else if有效呢? 我最初预计它会是一种嵌套的if语句。
  3. bool valid(string password) function 是否将 false 和 true 作为输入,因为它被定义为使用 bool?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>

bool valid(string password);

int main(void)
{
    string password = get_string("Enter your password: ");
    if (valid(password))
    {
        printf("Your password is valid!\n");
    }
    else
    {
        printf("Your password needs at least one uppercase letter, lowercase letter, number and symbol\n");
    }
}
bool valid(string password)
{
    bool haslower = false;
    bool hasupper = false;
    bool hasdigit = false;
    bool haspunct = false;
    int i;

    for (i = 0; password[i] != '\0'; i++)
    {
        if (isupper(password[i]))
        {
            hasupper = true;
        }
        else if (islower(password[i]))
        {
            haslower = true;
        }
        else if (isdigit(password[i]))
        {
            hasdigit = true;
        }
        else if (ispunct(password[i]))
        {
            haspunct = true;
        }
    }

    if (hasupper && haslower && hasdigit && haspunct)
    {
        return true;
    }

    return false;
}
  1. Bools ......我仍然在与他们作斗争。 为什么我不必放置 =true 部分? 是否只是假定布尔值必须为真?

我假设你实际上是在问为什么你不必像if(hasupper && haslower)那样做== true 这与 bool 类型本身并不真正相关,而是与 C 中的if和类似选择语句相关。传递给这些的任何普通变量或指针类型都会被评估为“如果非零则为真,否则为假”。 同样,像==这样的逻辑运算符返回10 这可以追溯到 C 甚至没有bool类型之前的时间。

但是,以这种方式仅使用bool类型的变量被认为是一种很好的风格。 if(mybool)一些编码标准不赞成 if( if(mypointer) ) 之类的代码,而是鼓励明确if(mypointer != NULL)

另请注意, C 中的bool类型具有将任何非零值 integer 转换为true / false的内置功能。 所以bool b=123; 结果为true (又等于1 )。


  1. 做一些研究,我现在明白 if 子句中的最后一个语句不必是 else,因为不能指定。 但是为什么一个 if 和三个 else if 有效呢? 我最初预计它会是一种嵌套的 if 语句。

elseif的末尾总是可选的。 现在碰巧的是, C 中实际上没有任何东西被称为else if ,它只是一种非常常见的编码风格约定。 每个else总是属于前面的if ,所以你的代码实际上是在使用else ,它可以像这样被 100% 等价地重写(但更难阅读):

// harder to read
if (isupper(password[i]))
{
  hasupper = true;
}
else 
  if (islower(password[i]))
  {
    haslower = true;
  }
  else 
    if (isdigit(password[i]))
    {
      hasdigit = true;
    }
    else 
      if (ispunct(password[i]))
      {
        haspunct = true;
      }

这是有效的,因为每个ifelse可以在下一行接受一个不带大括号的语句。 您也可以显式地键入大括号,但这样的可读性更差:

// even harder to read
if (isupper(password[i]))
{
  hasupper = true;
}
else 
{
  if (islower(password[i]))
  {
    haslower = true;
  }
  else 
  {
    if (isdigit(password[i]))
    {
      hasdigit = true;
    }
    else 
    {
      if (ispunct(password[i]))
      {
        haspunct = true;
      }
    }
  }
}

else if编码风格约定减少了缩进和大括号的数量,因此它被广泛用作“事实上的”标准编码风格。 (事实上 ,这是所有 C 程序员都同意的极少数与样式相关的事情之一。)


  1. bool valid(string password) function 是否将 false 和 true 作为输入,因为它被定义为使用 bool?

function 名称前面的类型声明了 function 的返回类型(输出)。function 的输入由参数指定,在本例中为string password 这是 CS50 编写char* password的功能失调方式。 更好的方法是使用const 正确性——因为这个 function 不应该修改字符串,它应该声明为bool valid (const char* password); .

您还可以通过将比较结果直接分配给变量来完全消除if/else使用,因为比较操作的结果是可以分配的值,就像可以分配x + 5一样:

bool valid(const char *password)
{
    bool haslower = false;
    bool hasupper = false;
    bool hasdigit = false;
    bool haspunct = false;

    for (int i = 0; password[i] != '\0'; i++)
    {
        hasupper = hasupper || isupper(password[i]);
        haslower = haslower || islower(password[i]);
        hasdigit = hasdigit || isdigit(password[i]);
        haspunct = haspunct || ispunct(password[i]);
    }

    return(hasupper && haslower && hasdigit && haspunct);
}

代码确实必须比has* = is*(password[i]);更复杂。 因为一旦任何has*变量为true ,它就必须保持为true 来自每个password charhas*变量的每个新值都必须与该has*变量的先前值进行or 'd。

而且因为|| 运算符短路,一旦任何has*变量为真,相应is*() function 就不需要也不会再被调用。

C 没有任何||=复合运算符,所以你不能写

        hasupper ||= isupper(password[i]);

不过,您可以使用按位或复合运算符|=

        hasupper |= isupper(password[i]);

尽管这不会短路并且对bool值使用按位运算符可能不是好的风格。 它风格糟糕的一个原因是||之间的对称性存在重大差异。 |=运算符以及&&&=运算符。

|| |=运算符将“传递”一个如上所用的true值,因为任何非零值或位的设置都将始终传递到一个true的最终结果:两者都是0 || 1 0 || 10 | 2 0 | 2true 但是如果你想检查是否所有字符都是大写的,例如&=等同于&&1 && 2true ,但是1 & 2false

  1. Bool 或 boolean 是原始数据类型。 只有两个可能的值,true 或 false,可以表示为 1 或 0。布尔值用于表示某事是否为真,是或否,在这种情况下,它要么是有效密码,要么不是. 谷歌更多关于这个。

  2. 结尾? 要不然? if 语句可以选择使用 elseif 链接在一起,其中通过多个条件语句检查谓词。 例如,假设谓词是年龄。 如果你“年龄 < 21 没有酒精,否则是酒精”在这种情况下你只需要 2. 如果你想检查学生是否有资格获得奖励并且你必须检查几个条件以查看是否满足每个条件怎么办。 If 语句不需要被链接,但如果需要的话它们很可能被链接。 它们可以嵌套在其他 if、循环等等中。 谷歌你不明白的东西,一段时间后倾向于官方文档。

  3. 不, Bool 是返回类型。 function 返回 true 或 false。 该参数接受一个字符串。 所以它接受一组字符,在本例中是一个密码。

您可以调用 function,或调用 main 中的 function 或任何其他用户定义的 function,方法是调用有效的 function 并传入字符串参数。 参数必须是字符串而不是布尔值。 function 根据您在 if 语句中指定的条件要求确定密码是否确实是有效密码。 我很惊讶你写了这篇文章但不理解但不要放弃。 欢迎提出更多问题。 下次参考的台词也要更具体!

你在看道格提供的cs50的短裤吗? 它们对于帮助进一步解释材料非常有用。

同样,这里有很多行话,但是您不理解的谷歌单词和概念。

祝你好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM