C:scanf输入单个字符并验证

时间:2017-12-18 04:38:42

标签: c scanf

我在C中验证单字符scanf输入时遇到问题而我找不到现有的解决方案...

场景是:一种方法只需要一个字母' char'键入输入然后验证此输入,如果不满足条件,则弹出错误消息并重新输入,否则返回此字符值。

我的代码是:

char GetStuff(void)
{
    char c;
    scanf("%c", &c);
    while(c != 'A' || c != 'P')
    {
          printf("invalid input, enter again (A for AM or P for PM): ");
          scanf ("%c", &dtChar);
    }
    return c;
}

然而,无论输入什么输入,我都得到了无限循环的错误信息。我读了一些其他帖子并猜测%c说明符在我点击时没有自动摆脱换行符的问题进入,到目前为止我尝试过:

  1. 在%c之前/之后放置一个空格,如:

    scanf(" %c", &c);
    
  2. 编写单独的方法或在此GetStuff方法中包含以清除换行符,如:

    void cleanBuffer(){
      int n;
      while((n = getchar()) != EOF && n != '\n' );
    }
    
  3. 有人可以帮我解决这个问题吗?提前谢谢。

5 个答案:

答案 0 :(得分:1)

在内部循环中,你正在dtChar中输入,但你的循环条件检查循环中没有更新的变量c,这会导致无限循环

你也会改变你的状况

while(c != 'A' || c != 'P')

while(c != 'A' && c != 'P') 

如果您希望用户输入“A' A'或者' P'

答案 1 :(得分:1)

#include <stdio.h>

char GetStuff(void) {
    char c;
    scanf("%c", &c);
    getchar();
    while ((c != 'A') && (c != 'a') && (c != 'P') && (c != 'p')) {
        printf("invalid input, enter again (A for AM or P for PM): ");
        scanf ("%c", &c);
        getchar();
    }
    return c;
}

int main(void) {
    printf("Calling GetStuff()...\n");
    char x = GetStuff();
    printf("User entered %c\n", x);
    return 0;
}

You are using while (c != 'A' || c != 'P') as your loop conditional, but this will always return true. What you meant to use is the && "and" operator, instead of the || "or" operator.

Also, call getchar() after your scanf statements, to capture the newline. This should work the way you want it to.

答案 2 :(得分:1)

Please consider the following snippet:

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

char GetStuff(void)
{
    char c;
    do {
          printf("Please enter A for AM or P for PM: ");
          scanf ("%c", &c);
          // clean input buffer (till the end of line)
          while(getchar()!='\n');
    } while(toupper(c) != 'A' && toupper(c) != 'P');
    return c;
}

int main(void)
{
    printf("Your input is'%c'\n", GetStuff());
    return 0;
}

Note the points:

  • condition while(c != 'A' || c != 'P') will be always true (just because one character cannot be 'A' and 'P' at the same time), so use while(c != 'A' && c != 'P') instead
  • No need for two scanf if you use do..while loop
  • After entering a char with scanf it is recommended to clean all characters from buffer, e.g. with while(getchar()!='\n'); (this will clean all input including incorrect and redundant characters)
  • use toupper to avoid making 4 comparison (actually single c=toupper(c) inside loop can minimize your while as while(c != 'A' && c != 'P') )

UPDATE:

To add message "Invalid input" and adding some other useful improvement subjected befor... new code is as:

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

void CleanBuffer(){
    int n;
    while((n = getchar()) != EOF && n != '\n' );
}

char GetStuff(void)
{
    char c;
    do {
          printf("Please enter A for AM or P for PM: ");
          scanf (" %c", &c);
          c = toupper(c); // here letter become uppercase
          CleanBuffer();
    } while( (c != 'A' && c != 'P')?printf("Invalid input! "):0 );
    return c;
}

int main(void)
{
    printf("You have entered: %c\n", GetStuff());
    return 0;
}

Note: function will return 'A' or 'P' in uppercase, so if this is not needed change the code as in example before update (use two toupper and do not change c after scanf). Also you can use tolower as an option (of course with comparing to 'a' and 'p').

答案 3 :(得分:0)

Another possible solution. As others mentioned the condition was to be done with &&. Anyway the big problem is how to remove what's left on the console input line. Since the console works by lines, we remove everything up to the next using System.Diagnostics; public static class StorageEmulatorHelper { /* Usage: * ====== AzureStorageEmulator.exe init : Initialize the emulator database and configuration. AzureStorageEmulator.exe start : Start the emulator. AzureStorageEmulator.exe stop : Stop the emulator. AzureStorageEmulator.exe status : Get current emulator status. AzureStorageEmulator.exe clear : Delete all data in the emulator. AzureStorageEmulator.exe help [command] : Show general or command-specific help. */ public enum StorageEmulatorCommand { Init, Start, Stop, Status, Clear } public static int StartStorageEmulator() { return ExecuteStorageEmulatorCommand(StorageEmulatorCommand.Start); } public static int StopStorageEmulator() { return ExecuteStorageEmulatorCommand(StorageEmulatorCommand.Stop); } public static int ExecuteStorageEmulatorCommand(StorageEmulatorCommand command) { var start = new ProcessStartInfo { Arguments = command.ToString(), FileName = @"C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\AzureStorageEmulator.exe" }; var exitCode = executeProcess(start); return exitCode; } private static int executeProcess(ProcessStartInfo startInfo) { int exitCode = -1; try { using (var proc = new Process {StartInfo = startInfo}) { proc.Start(); proc.WaitForExit(); exitCode = proc.ExitCode; } } catch { // } return exitCode; } } . If the user already left something on the input line before calling '\n', it would be useful to add a call to GetStuff() before the while loop.

In general I suggest to start with a SkipRestOfTheLine() loop, before making it nicer (such as in the while(1) you posted).

cleanBuffer()

答案 4 :(得分:-1)

try this,

   char GetStuff(void)
    {
        char c;
        scanf("%c", &c);
        while (((c != 'A') || (c != 'a')) && ((c != 'P') || (c != 'p'))==1)
        {
              printf("invalid input, enter again (A for AM or P for PM): ");
              scanf ("%c", &dtChar);
        }
        return c;
    }

I hope this works, some time because of not given proper bracket it is stuck in the loop.