【问题标题】:Why does my C program print messages twice if the user input is longer than 16 chars? [closed]如果用户输入超过 16 个字符,为什么我的 C 程序会打印两次消息? [关闭]
【发布时间】:2016-07-09 03:53:55
【问题描述】:

我正在尝试制作一个小型帐户注册程序。它提示用户输入userIDpassword。我正在处理userID 部分,但它似乎不对。如果我输入< 8 字符userID,它工作正常,但是当我输入超过16 字符的userID 时,要求用户输入不同userID 的消息会打印两次。这是为什么呢?

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main(void)
{
    // Setting up variables
    char userID[18];
    char passcode[51];

    // Firstly promt the user for user ID
    do // This loop is for asking the user to type another userID if his chosen one isn't approprite
    {
        printf("Please choose your user ID! (it must be between 6 - 16 charaters long)\n");
        for (int i = 0; i < 17; i++) // This loop store the userID into the character array
        {
            userID[i] = getchar(); // Store userID into array character by         character
            if (userID[i] == '\n')
            {
                userID[i+1] = '\0';
                break;
            }

        }
    }
    while (strlen(userID) < 7  ||  (strlen(userID) > 16  &&  userID[16] != '\n'));

    // Printing info on the screen.
    printf("Your acount info are:\n\tuserID  : %s\tpasscode: ", userID);

【问题讨论】:

  • 请发布代码以了解您的问题中的错误。谢谢。
  • T.T我是新手,所以我还不能发布图片T.T.你能看看链接吗:(。真的很感激
  • 您不必发布图片。您可以在问题本身中发布代码。
  • 除非最后一个字符是换行符,否则您不会终止输入字符串,如果字符串太长,最后一个字符不是换行符。这会导致未定义的行为。
  • 我的评论不是答案——它只是对问题的诊断(好吧,一个问题),而不是修复。您可能还没有足够的代表对 cme​​ts 进行投票,但在适当的时候您将能够这样做。别担心;如果我写了一个答案,那么情况会有所不同,但是 cmets 名义上是短暂的(即使它们可以持续数年)。

标签: c loops


【解决方案1】:

如果我输入 &lt; 5 字符 userID 效果很好,但是当我输入超过 16 字符的 userID 时,要求用户输入不同 userID 的消息会打印两次.这是为什么呢?

  • 当你输入超过16字符时,17字符被扫描到字符串userID中,因为你没有输入'\n',所以不会在字符串末尾放置空字符userID.

  • 然后,当您使用 strlen(userID) 时,这会调用 未定义的行为,因为末尾没有终止 \0 字符。尝试这样做:

  • 当您重新开始迭代时,剩余的额外整数将被纳入。


解决方案:

为避免上述问题:

  1. 在每次迭代中在index + 1 位置放置一个空字符。
  2. flushstdin 在每次迭代结束时。

    do
    {
        printf("Please choose your user ID! (it must be between 6 - 16 charaters long)\n");
    
        for (int i = 0; i < 17; i++)
        {
            userID[i] = getchar();
            userID[i+1] = '\0'; //placing null character at the position index+1
    
            if(userID[i] == '\n')
            {
                userID[i] = '\0';
                break;
            }    
    
        }
    
        fflush(stdin); //flushing the extra input at the end of each iteration
    
    } while (strlen(userID) < 7  ||  (strlen(userID) > 16  &&  userID[16] != '\n'));
    

示例输入:

more than 16 123456789
1123
123456789

样本输出:

Please choose your user ID! (it must be between 6 - 16 charaters long)
more than 16 123456789
Please choose your user ID! (it must be between 6 - 16 charaters long)
1123
Please choose your user ID! (it must be between 6 - 16 charaters long)
123456789

Your acount info are:
    userID  : 123456789
    passcode: 

注意:

避免使用fflussh(stdin),因为它存在comments@JonathanLeffler 所建议的可移植性问题。还有一个解释性帖子为什么不使用fflush(stdin)click

这是避免使用fflush(stdin)的代码实现

do
{
    int i;

    printf("Please choose your user ID! (it must be between 6 - 16 charaters long)\n");

    for (i = 0; (userID[i] = getchar()); i++)
    {

        userID[i+1] = '\0'; //placing null character at the position index+1

        if(userID[i] == '\n')
        {
            userID[i] = '\0';
            break;
        }

        //if user enters more than 16 characters then,
        //scan in 17th character for `strlen(userID)` purpose and
        //consume all other characters using an integer `c`
        if( i > 17)
        {
            int c;

            while( ((c = getchar())!= '\n') && (c!=EOF) );
            break;
        }
    }

} while ( (strlen(userID) < 7)  ||  (strlen(userID) > 16 ) );

【讨论】:

  • 注意Using fflush(stdin)的可移植性问题
  • @JonathanLeffler 感谢您编辑帖子和分享,在这种情况下,fflush() 的最佳替代品是什么……有吗?还是必须采用任何不同的方法?
  • 便携式替代品是int c; while ((c = getchar()) != EOF &amp;&amp; c != '\n') ;(其中最后的分号是一个空循环体,通常单独写在一行上,但我无法在评论中格式化)。严格来说,应该编写主输入循环以在分配给userID[i] 之前检查 EOF 的输入字符——人们可能会对这些事情感到厌烦(在 Windows 上连续输入几次 control-Z;或 control- D 在 Unix 上)。
  • @JonathanLeffler 我提供了一个避免fflush(stdin) 的实现,我有一点疑问...我应该替换第一个实现我的新版本作为答案(或)是否可以只需添加第二个实现以及前一个实现通知OP为什么不使用它(如我现在做了)...感谢您提供信息...虽然我做了一个后期编辑:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多