【问题标题】:Newline Issues taking input after clearing Stdin with getchar() [Solved]使用 getchar() 清除 Stdin 后输入的换行问题 [已解决]
【发布时间】:2020-08-10 16:32:55
【问题描述】:
while ((eat = getchar()) != '\n' && eat != EOF); // where 'eat' is long long eat

这是我正在使用的线路。

问题,你问?啊哈!我必须按[ENTER] 两次,才能真正将输入“发送”到我的程序。 (我希望这是在 scanf 和 fgets 之后工作的函数中)

这似乎让人想起单独使用 getchar() ,但我是新手,我会通过删除 getchar() 来解决这些问题,这当然不能在这里完成。 p>

我很困惑该怎么做,以及是否有可能实现一个不强制用户按两次[ENTER] 键的简单解决方案.

更大更好的代码 sn-p:

int num,q=0; static int pins[8]; char pswd[9]; char bad =1,Y_N;    
while(bad == 1) {
        printf("\nEnter (8 char) Password : ");
        getchar();
        fgets(pswd,sizeof(pswd),stdin); 
        int len = strlen(pswd); 
        if(pswd[len-1] == '\n'){
            pswd[len-1] = '\0'; 
            len--;
        }
        if(len < 8)
            printf("\nPassword less than 8 characters.\nPlease Retry.\n");
    
        else
            bad = 0;
    }
    while ((eat = getchar()) != '\n' && eat != EOF);

编辑:

我犯了一个愚蠢的错误,这个错误不是由循环本身引起的,而是因为函数(该代码是其中的一部分)被调用的代码。那个地方的一个额外的getchar() 导致了这个错误。它通过删除额外的getchar() 来解决。感谢所有帮助我解决此问题的人,我向你们所有人道歉。

【问题讨论】:

  • @pmg 这当然是个好建议,我打算坚持下去,但我需要一些适用于两者的东西
  • 您需要显示更多代码,很难说为什么这不起作用。
  • @Barmar 它可能无法正常工作,因为我使用了 scanf ?
  • 这取决于您如何使用scanf()。例如,请参阅stackoverflow.com/questions/15740024/…。
  • 不要while(!feof()) ...见stackoverflow.com/questions/5431941/…

标签: c while-loop buffer stdin getchar


【解决方案1】:

可以使用fgets(,,stdin); 和一个简单的while(){...} 构造来简化代码

int main(int argc, char *argv[])
{ 
    int bad = 1;
    char pswd[20]={0};//2x strlen of proper password + \n + NULL
    
    while(bad == 1) 
    {
         //prompt user
         printf("Enter password (8 characters) : " );
         //read user input value
         fgets(pswd, sizeof(pswd), stdin);
         //remove newline from user input
         pswd[strcspn(pswd, "\n")] = 0;
         //(replaces the need for the while loop at bottom of original post.)

         if(strlen(pswd) == 8)//test input for length
         {
              bad = 0;//exit loop if pswd good
         }
    }
    return 0;
}

您可以添加一些重试代码来处理不正确的密码

【讨论】:

  • ryyker,删除 getchar() 会导致它完全跳过输入。
  • ryyker 你是对的,循环可能不是问题,我用的是我的另一个旧程序,即使使用 scanf 也运行良好
  • pswd[9] 对于“(8 字符)密码”和'\n'、'\0' 来说太小了。
  • 旁白:我会使用至少 2 倍的缓冲区来帮助吃更久、更糟糕的密码,以便在下次尝试时提供一个空的 stdin。然而,如果用户输入的密码真的很长,我会退出。
  • @user13863346 许多键盘接受crtl @,或通过管道输入,或其他方式。关键是健壮的代码不会成为恶意用户的牺牲品。高级用户可能会担心,现在可以忽略。
【解决方案2】:

char pswd[9]; 太小,无法读取 8 个字符的密码 '\n' 并另存为 字符串 附有'\0'。 OP 需要更长的输入缓冲区。

关键问题是如果恶意用户输入了长密码怎么办?把它全部吃掉再试一次? IMO,尝试输入非常长的密码的用户应被视为敌对,而不仅仅是“哎呀”。使输入缓冲区成为读取预期输入行所需的 (8+1+1) 的 2 倍到 4 倍。如果输入已满,则退出。如果输入密码长度!= 8,允许用户重试。


BTW if(pswd[len-1] == '\n'){ 如果读取的第一个字符是 空字符,则为 UB。

【讨论】:

  • 您确实意识到,任何 安全、安全 的输入方式不会导致缓冲区溢出,pswd 占用的字符数不会超过 8 个字符,从而为 '/0' 留出空间,然后运行 while 循环来清理 stdin 并吃掉其他所有东西。所以如果 evil 用户输入长密码 ,前 8 个字符将被存储,其余的被吃掉。
  • @user13863346 这只是稍微接近所涉及的大量问题。
  • 这就是重点,我不想要'\n'。如果它最终进入,我实际上会删除它。它的大小为 [9] 以占用 only 8 个字符并为 '\0' 留出空间。如果恶意用户(或无害用户)输入 huge 密码,则只占用前 8 个字符,其余字符被吃掉。这不是很好吗?我真的在问.. 另外,第一个字符怎么可能是NULL?
  • @user13863346 1) 当前面的代码已经读取了'\n' 时,while ((eat = getchar()) != '\n' &amp;&amp; eat != EOF); 的意义不大。 2) "第一个读取的字符怎么可能是 NULL" --> 用户首先输入一个 null 字符 - 很棘手,但可行。为什么你认为用户不能输入 null 字符?
  • Chux,我不知道这是可能的(可能是因为我使用的是 MacBook,它似乎不允许这样做),谢谢通知我!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多