【问题标题】:Struggle with loops与循环斗争
【发布时间】:2021-10-30 08:56:00
【问题描述】:

所以我对编码非常陌生,并且正在学习本教程系列,这里的第一个任务是为包括大写/小写字母、数字和符号的密码创建一个检查器,但我还是被困在了最开始的地方。 ..所以这里有一些代码和我的问题:

int main()
{    
     int pw[21];
     int pwVUpper = 0;
     int pwnum = 0;

     printf("Please choose a password.\n");
     printf("Make sure it includes at least one number, lower and upper case letter and one of the symbols: !, _, $, -, /.\n");    
     scanf(" %c", pw);

     while((pwnum<=21)){
        if(isupper(pw[pwnum])){
                printf("lol!");
                pwnum++;
        }
     }    
     return 0;
}

所以这只是检查大写字母的开始,我想让循环遍历“pw”数组的每个字母,然后才打印“lol!”,如果它检查大写字母,但是,它只检查数组中的第一个字母,并且只打印一次“lol!”,即使该数组在任何时候都恰好有 2 个大写字母。

我尝试将数组字母编号与变量 pwnum 关联,并且随着循环的进行,变量增加,因此将检查下一个字母。

提个醒:从各种搜索中,我发现对于我正在尝试做的事情有更好的解决方案,但是很多关键字我还没有完成,我想完成这个正如教程系列所建议的那样,只有有限的知识,我似乎误解了循环或其他东西,此时我真的开始感到大脑受损,可能是吧!

【问题讨论】:

  • pw 数组有 21 个元素,索引为 0 - 20。尝试访问索引 21 超出范围并调用未定义行为。
  • 注意缩进样式(你在哪里放置你的大括号)可以帮助你理解代码的结构。这应该可以帮助您找到问题。
  • 格式化对于提高可读性很重要。在这里为您编辑。
  • pwnum++; 应该在该代码块之外 - 因为当isupper() 为假时,循环将停止。
  • int pw[21]; 应该是 char pw[21];scanf(" %c", pw); 应该是 scanf("%20s", pw); 你也可以检查 uninitialised 数组元素。

标签: arrays c loops while-loop new-operator


【解决方案1】:

一些笔记。

如果意图创建密码字符串,则代码should在分析之前读入C string。改变这个:

int pw[21];
...
scanf(" %c", pw);

到这里:

char pw[21] = {0}; //initialize to all zeros
...
scanf("%20s", pw);//width modifier '20' will prevent overflowing buffer

接下来从if(...){...} 语句内部删除索引。改变这个:

     while((pwnum<=21)){
         if(isupper(pw[pwnum])){
            printf("lol!");
            pwnum++;
         }
     }    

到这里:

     while((pwnum<=20)){//changed to 20 to prevent out-of-bounds
         if(isupper(pw[pwnum])){
            printf("lol!");
         }
         pwnum++;
     }    

如果您的工具箱中还没有它们,您还可以了解islower()isdigit()。请注意,可能还需要使用type casting。 (例如if(isdigit((int)pw[pwnum]))...

最后,要跟踪 3 个不同的标准,数字、上限和下限,您可以定义一些布尔变量和 #define...

#define PW_GOOD upper&&lower&&digit

bool upper = false;//init all three
bool lower = false;
bool digit = false;
....
if(!upper) {  //enter only once 
    if(isupper(pw[pwnum])){
       upper = true;     
    }//do the same for lower and digit
}

稍后在代码中使用

测试您的三个标准
if(PW_GOOD)
{
     printf("lol!");
     ... 

【讨论】:

  • 非常感谢!这非常有帮助!也感谢您的快速响应,知道代码真的很粗糙和未经修饰,但现在我几乎已经完成并且可以工作了!真的很感谢额外的技巧,看看它们如何也可以融入其他东西! :))
【解决方案2】:

问题来了

 while((pwnum<=21)){
    if(isupper(pw[pwnum])){
            printf("lol!");
            pwnum++;
    }
 }  

请注意,if 语句控制的花括号内有 两个 语句。即,对printf() 的调用和pwnum 的增量。这意味着您只有在打印“lol”时才增加pwnum——当您找到一个大写字母时。

像这样重构代码:

 while((pwnum<=21)){
    if(isupper(pw[pwnum])){
            printf("lol!");
    }
    pwnum++;
 }  

现在无论您是否找到大写字母,索引pwnum 都会递增。这意味着程序将继续查看下一个字母。

预计到达时间 有人指出(感谢@ryyker)数组索引也有一个问题。您确实想尝试读取 pw[21] 的值,因为在 21 个元素的数组中,有效索引为 0 到 20(含)。因此,您应该按如下方式修改循环:

 while((pwnum<21))...

代码还有其他问题,但希望这能让您摆脱当前的问题。

【讨论】:

  • 这也是for 循环的好地方,而不是while 循环。虽然while 将实现目标,并且任何初学者都应该理解,但for 循环也很重要。在这种情况下:for (pwnum = 0; pwnum &lt;= 20; pwnum++) { ... }
  • @Chris 同意了,但 OP 要求提供一个不使用不熟悉关键字的解决方案,所以我把它省略了。
  • 这就是为什么我只是将其添加为评论而不是答案。他们都是陌生的……直到他们不熟悉。 ;)
  • 非常感谢您的提示和快速响应!我知道这一切都是非常新手和未经打磨的,但现在几乎所有事情都完成了! :)) for 循环确实要好得多,我确实可以看到,但是很多示例都使用 for 循环,而我已经使用 for 循环做了一个,所以我尝试用 while 循环挑战自己,只是为了得到更好的理解!
【解决方案3】:

问题在于,只有在找到大写字母时才会增加 pwnum,而这是您不想要的。因为,一旦你找到一个小写字母,它就会进入一个无限循环,因为 pwnum 不会增加。一种解决方案是将 pwnum 放在 Tim Randall 提到的 if 语句之外。在这种情况下,更好的解决方案是使用 for 循环而不是 while 循环。另请注意,最大索引长度为 1,这样您就不会越界。

除了循环问题,要存储字符串,应该使用 char 数组而不是 int 数组。并且要输入一个字符串,你应该使用 %s 而不是 %c。

希望对你有帮助

【讨论】:

  • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
【解决方案4】:

我认为主要问题是您对scanf 的调用使用%c 作为格式化字符串,它只读取一个字符。应该是%s,直到你按下回车键。

此外,还有一些其他问题:

  1. while 条件应为pwnum &lt; 21 以避免溢出,而不是pwnum&lt;=21
  2. pw 的类型应该赌char[] 而不是int[]。这可能会导致某些系统出现问题。
  3. while 循环应该搜索到空字符 0x0'\0' ,以防用户没有输入 21 个字符。否则,它将继续读取数组末尾未初始化的元素。

【讨论】:

    【解决方案5】:
    1. scanf(" %c", pw);: %c 格式说明符用于字符,对于字符串,您可以使用scanf("%20[^\n]",pw);%20是为了避免bufferrun。

    2. while((pwnum&lt;=21)){: 你试图用它访问越界的数组元素。更好的方法是将其替换为 while(pw[pwnum]!='\0'){

    if(isupper(pw[pwnum])){
          printf("lol!");
          pwnum++;
    }
    

    只有在找到大写字母时才会增加pwnum,如果pw 中的所有字母都不是大写字母,则会导致无限循环。尝试将pwnum++ 移出if 语句。

    【讨论】: