确定密码是否有效的代码的效率如何?

时间:2018-12-31 21:04:27

标签: c

要求密码必须包含大写字母,数字和“ $”符号。一切正常(除非用户出于某种原因输入空格,否则将不胜感激),但是idk我的代码有多有效。我是C的新手,有什么建议吗? (除了将密码设置为非常高的值或强迫用户遵守限制之外,还有其他方法可以为我的密码设置“最大长度”吗?)

int main(void){

int maxlength = 15;
char password[maxlength];
int index = 0;
int x = 0;
int y = 0;
int z = 0;

printf("Enter Password: "); //Mike$4
scanf(" %s", password);

do{ // If index is strlen, then we checked every char of pw
    // Ex. Password is length 6, then index 0 - 5 will be checked

    if(index == strlen(password) && x>0 && y>0 && z>0){
        printf("Good password!");
        break;
    }
    if(index == strlen(password) && (x==0 || y==0 || z==0)){
        printf("BAD PASSWORD");
        break;
    }

    if(isupper(password[index]) ||  isdigit(password[index]) ||
       password[index] == '$'){

         if(isupper(password[index])){
                x++; index++;
                continue;}
         if(isdigit(password[index])){
                y++; index++;
                continue;}
         if(password[index] == '$'){
                z++; index++;
                continue;}
    }else{index++;
          continue;
          }
}while(index <= strlen(password));
return 0;}

基本上,每次满足要求时,我只是通过增加x,y或z来指出它,如果在密码末尾,它们都至少有1,那么这是一个很好的密码。

谢谢!

我在问是否有更好的方法编写此代码,因为我在学校的下一门CS课程也将根据效率进行评分,因此我想确保我知道是什么使C代码有效。当然,如何处理密码中的空格。

1 个答案:

答案 0 :(得分:1)

  

我的代码效率如何....

常见的编码陷阱是性能,而C代码却具有未定义行为(UB)。首先修复UB,然后解决效率问题。

缓冲区溢出

scanf(" %s", password);没有提供宽度限制。 15个字符(或更多)的密码将通过尝试在password[]外部写入来调用UB。

char

在编码早期,人们不太可能遇到char带有负值的情况,但是当它们发生时,is...(int ch)函数是一个问题。在这里,ch的值必须在unsigned char范围或EOF范围内,否则UB会再次出现。

// isupper(password[index])
isupper((unsigned char) password[index])

考虑到UB,scanf(" %s", password);可以轻松地花费while循环时间的100倍。因此,通过微优化优化代码边界。

避免使用O(n * n)代码

假设密码的长度为n,然后要查找字符串的长度,则必须通过n遍历所有strlen()字符。另外,代码还在执行n循环,每次迭代都调用strlen()。就是n*n时间。

当今许多编译器会发现password不会在循环中更改,因此将记住strlen(password)的结果,从而防止了n*n的迭代。

do{
  if(index == strlen(password) && x>0 && y>0 && z>0){
  ...
} while(index <= strlen(password));

不过,在循环外替换一次非迭代代码或计算长度一样简单。

size_t len = strlen(password);

do {
  // if(index == strlen(password) ...
  if(password[index] != '\0' ...
  // or 
  if(index == len ...

  // }while(index <= strlen(password));
  } while(index <= len);

使用这样的短字符串,长度为int的类型就可以了,但是对于包括 string 在内的常规数组代码,size_t是用于数组索引的合适大小的类型和长度。

使用诸如upper_count之类的信息性名称而不是x可以产生更好的代码。

示例未经测试的备用代码。代码专门将fgetc()与其他输入方式结合使用,以此作为迈向安全性的一步-还有更多步骤。

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#define PWD_N 6

int main(void) {
  size_t maxlength = 15;
  char password[maxlength + 1]; // add 1 for \0
  bool upper = false;
  bool digit = false;
  bool dollar = false;
  bool length_ok = true;

  printf("Enter Password: "); //Mike$4
  fflush(stdout);

  size_t i = 0;
  for (;;) {
    int ch = fgetc(stdin);
    if (ch == '\n' || ch == EOF) {
      break;
    }
    if (i < sizeof password - 1) {
      password[i++] = ch;
      upper |= isupper(ch);
      digit |= isdigit(ch);
      dollar |= ch == '$';
    } else {
      length_ok = false; // too long
    }
  }
  password[i] = '\0';

  if (i == PWD_N && length_ok && upper && digit && dollar) {
    printf("Good password!\n");
  } else {
    printf("BAD PASSWORD\n");
  }
  return 0;
}