简体   繁体   English

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

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

I came up with this solution with some help regarding the CS50 Week 2 Problem set password.在有关 CS50 第 2 周问题设置密码的一些帮助下,我想出了这个解决方案。 The prompt is to use 2 function to come up with a simple password checker, verifying an input string has 1 uppercase letter, 1 lowercase letter, 1 number, and 1 symbol.提示是使用 2 function 想出一个简单的密码检查器,验证输入的字符串是否包含 1 个大写字母、1 个小写字母、1 个数字和 1 个符号。 The suggestion was to use bools.建议是使用布尔值。 However, I have 3 questions on how and why this works:但是,我有 3 个关于它如何以及为何起作用的问题:

  1. Bools... I still am struggling with them. Bools ......我仍然在与他们作斗争。 Why don't I have to put the =true part?为什么我不必放置 =true 部分? Are bools just assumed to have to be true?是否只是假定布尔值必须为真?
  2. Doing some research, I understand now that the last statement in an if clause doesn't have to be else , because that can't be specified.做一些研究,我现在明白if子句中的最后一个语句不必是else ,因为不能指定。 But why does one if and three else if work?但是为什么一个if和三个else if有效呢? I originally anticipated that it would be a sort of nested if statements instead.我最初预计它会是一种嵌套的if语句。
  3. Does the bool valid(string password) function take false and true as input because it's defined as using bool? 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... I still am struggling with them. Bools ......我仍然在与他们作斗争。 Why don't I have to put the =true part?为什么我不必放置 =true 部分? Are bools just assumed to have to be true?是否只是假定布尔值必须为真?

I assume you are actually asking why you don't have to do == true as in if(hasupper && haslower) .我假设你实际上是在问为什么你不必像if(hasupper && haslower)那样做== true This isn't really related to the bool type as such, but to the if and similar selection statements in C. Any plain variable or pointer type passed to these gets evaluated as "if non-zero then true, otherwise false".这与 bool 类型本身并不真正相关,而是与 C 中的if和类似选择语句相关。传递给这些的任何普通变量或指针类型都会被评估为“如果非零则为真,否则为假”。 Similarly the logic operators like == return either 1 or 0 .同样,像==这样的逻辑运算符返回10 This goes way back to a time before C even had a bool type.这可以追溯到 C 甚至没有bool类型之前的时间。

However, it is considered good style to only use variables of type bool in that manner.但是,以这种方式仅使用bool类型的变量被认为是一种很好的风格。 if(mybool) is ok some coding standards frown at code such as if(mypointer) and instead encourage to be explicit if(mypointer != NULL) . if(mybool)一些编码标准不赞成 if( if(mypointer) ) 之类的代码,而是鼓励明确if(mypointer != NULL)

Also note that the bool type in C has the built-in ability to convert any non-zero integer value into true / false .另请注意, C 中的bool类型具有将任何非零值 integer 转换为true / false的内置功能。 So bool b=123;所以bool b=123; results in true (which in turn equals 1 ).结果为true (又等于1 )。


  1. Doing some research, I understand now that the last statement in an if clause doesn't have to be else, because that can't be specified.做一些研究,我现在明白 if 子句中的最后一个语句不必是 else,因为不能指定。 But why does one if and three else if work?但是为什么一个 if 和三个 else if 有效呢? I originally anticipated that it would be a sort of nested if statements instead.我最初预计它会是一种嵌套的 if 语句。

else is always optional at the end of an if . elseif的末尾总是可选的。 Now as it happens, there is actually nothing in C called else if , it's just a very common coding style convention.现在碰巧的是, C 中实际上没有任何东西被称为else if ,它只是一种非常常见的编码风格约定。 Each else always belongs to the previous if , so your code is actually using else , and it can be rewritten 100% equivalent (but harder to read) like this:每个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;
      }

This works because every if or else can accept one statement on the next line without braces.这是有效的,因为每个ifelse可以在下一行接受一个不带大括号的语句。 You could type out the braces explicitly too, but that's even less readable:您也可以显式地键入大括号,但这样的可读性更差:

// 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;
      }
    }
  }
}

The else if coding style convention reduces the amount of indention and braces, so it is very widely used as a "de facto" standard coding style. else if编码风格约定减少了缩进和大括号的数量,因此它被广泛用作“事实上的”标准编码风格。 (In fact it is one of the very few style-related matters that all C programmers agree on.) (事实上 ,这是所有 C 程序员都同意的极少数与样式相关的事情之一。)


  1. Does the bool valid(string password) function take false and true as input because it's defined as using bool? bool valid(string password) function 是否将 false 和 true 作为输入,因为它被定义为使用 bool?

The type in front of the function name declares the return type (output) from the function. The input to the function is specified by the parameters, in this case string password . function 名称前面的类型声明了 function 的返回类型(输出)。function 的输入由参数指定,在本例中为string password Which is CS50's dysfunctional way of writing char* password .这是 CS50 编写char* password的功能失调方式。 An even better way would be to use const correctness - since this function shouldn't modify the string, it should be declared as bool valid (const char* password);更好的方法是使用const 正确性——因为这个 function 不应该修改字符串,它应该声明为bool valid (const char* password); . .

You can also eliminate the if/else use entirely by assigning the result of the comparison directly to the variable, because the result of a comparison operation is a value that can be assigned, just like x + 5 can be assigned:您还可以通过将比较结果直接分配给变量来完全消除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);
}

The code does have to be more complex than just has* = is*(password[i]);代码确实必须比has* = is*(password[i]);更复杂。 because once any of the has* variables are true it has to remain true .因为一旦任何has*变量为true ,它就必须保持为true Each new value of the has* variables from each char of password has to be or 'd with the previous value of that has* variable.来自每个password charhas*变量的每个新值都必须与该has*变量的先前值进行or 'd。

And because the ||而且因为|| operator short-circuits, once any of the has* variables is true, the corresponding is*() function doesn't need to be and won't be called any more.运算符短路,一旦任何has*变量为真,相应is*() function 就不需要也不会再被调用。

C does not have any ||= compound operator, so you can't write C 没有任何||=复合运算符,所以你不能写

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

You could use the bitwise-or compound operator |= , though不过,您可以使用按位或复合运算符|=

        hasupper |= isupper(password[i]);

although that doesn't short-circuit and the use of bitwise operators on bool values probably isn't good style.尽管这不会短路并且对bool值使用按位运算符可能不是好的风格。 One reason it's bad style is there's a critical difference in the symmetry between the ||它风格糟糕的一个原因是||之间的对称性存在重大差异。 and |= operators and the && and &= operators.|=运算符以及&&&=运算符。

Both the || || and |= operators will "carry through" a true value as used above because any setting of a non-zero value or bit will always carry through to a true end result: both 0 || 1|=运算符将“传递”一个如上所用的true值,因为任何非零值或位的设置都将始终传递到一个true的最终结果:两者都是0 || 1 0 || 1 and 0 | 2 0 || 10 | 2 0 | 2 are true . 0 | 2true But if you want to check if all characters are upper case, for example, &= is not equivalent to && : 1 && 2 is true , but 1 & 2 is false .但是如果你想检查是否所有字符都是大写的,例如&=等同于&&1 && 2true ,但是1 & 2false

  1. Bool or boolean is a primitive data type. Bool 或 boolean 是原始数据类型。 There are only two possible values, true or false, which can be denoted as 1 or 0. Booleans are used to denote whether something is true or not, yer or no, and in this case, either it is a valid password or its not.只有两个可能的值,true 或 false,可以表示为 1 或 0。布尔值用于表示某事是否为真,是或否,在这种情况下,它要么是有效密码,要么不是. Google more about this.谷歌更多关于这个。

  2. end?结尾? or else?要不然? if statements have the option to be chained together using elseif where the predicate is checked through several conditional statements. if 语句可以选择使用 elseif 链接在一起,其中通过多个条件语句检查谓词。 For example, lets say the predicate is age.例如,假设谓词是年龄。 If you "age < 21 no alcholo, else yes alcohol" In this case you only need 2. What if you want to check whether a student qualifies for an award and you must check several conditions to see if each are met.如果你“年龄 < 21 没有酒精,否则是酒精”在这种情况下你只需要 2. 如果你想检查学生是否有资格获得奖励并且你必须检查几个条件以查看是否满足每个条件怎么办。 If statements aren't required to be chained but they can very well be if needed. If 语句不需要被链接,但如果需要的话它们很可能被链接。 They can be nested within other ifs, loops as well and much more.它们可以嵌套在其他 if、循环等等中。 Google what you don't understand and gravitate towards official documentation after a while.谷歌你不明白的东西,一段时间后倾向于官方文档。

  3. No, Bool is the return type.不, Bool 是返回类型。 The function either returns true or false. function 返回 true 或 false。 The parameter takes in a string.该参数接受一个字符串。 So it takes in a set of characters and in this case a password.所以它接受一组字符,在本例中是一个密码。

You can call the function, or invoke the function in main or any other user defined function by calling the function valid and passing in a string argument.您可以调用 function,或调用 main 中的 function 或任何其他用户定义的 function,方法是调用有效的 function 并传入字符串参数。 The argument MUST be a string not a bool.参数必须是字符串而不是布尔值。 The function determines whether the password is indeed a valid password based on the conditional requirements you specified in your if statements. function 根据您在 if 语句中指定的条件要求确定密码是否确实是有效密码。 I'm surprised you wrote this but don't understand it but don't give up.我很惊讶你写了这篇文章但不理解但不要放弃。 Feel free to ask more questions.欢迎提出更多问题。 Be more specific about the lines you refer to next time as well!下次参考的台词也要更具体!

Are you watching the shorts from cs50 provided by Doug?你在看道格提供的cs50的短裤吗? They are very useful in helping explain the material further.它们对于帮助进一步解释材料非常有用。

Again, lots of jargon here, but google words and concepts you don't understand.同样,这里有很多行话,但是您不理解的谷歌单词和概念。

Best of luck!祝你好运!

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

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