代码之家  ›  专栏  ›  技术社区  ›  griotspeak

关于验证Objective-C中用户输入的问题,数字与字符串

  •  3
  • griotspeak  · 技术社区  · 16 年前

    如果您输入一个非数字字符,为什么该代码会“精确地”无休止地循环?

    第一个问题是因为我想学习好的防御性编码。有人知道检查用户输入的好方法吗?我的google fu让我失望了。有些人似乎认为如果我具体说明 %f scanf 我“要求”一个 float ; 在某种程度上,我通过打印 userInput . 事实上,如果我把 do while 循环,代码的执行“没有问题”。它分配了一个 0 然后开始做生意。

    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        float userInput;
        float result;
    
        NSLog(@"3X^3 -5x^2 + 6");
    
        do {
            NSLog(@"What is x?");
            scanf("%f", &userInput);
            NSLog(@"userInput = %f", userInput);
        } while(userInput == 0);
    
        result = 3 * (userInput * userInput * userInput) - 5 * (userInput * userInput) + 6;
        NSLog(@"the result is: %f", result);
    
        [pool drain];
        return 0;
    }
    
    2 回复  |  直到 15 年前
        1
  •  3
  •   gavinb    16 年前

    这实际上与Objective-C或Cocoa无关。问题只是与标准C库函数的使用有关 scanf ,以及处理错误条件。从 手册页,描述返回代码:

    零表示虽然有可用的输入,但未分配任何转换;通常这是由于输入字符无效,例如用于“%d”转换的字母字符。

    有效的数字输入可以由 斯坎夫 %f 说明符,这样显然可以按预期工作。但如果输入非数字字符, 斯坎夫 无法将其转换为浮点,并且 将文本保留在的缓冲区中 stdin . 因为代码没有检查来自的返回代码 斯坎夫 ,并且仅在以下情况下进行测试: userInput 如果为非零,则循环将永远不会退出,如 用户输入 0.0 ,并且将永远不会更新为 不会将非数字字符从 标准 缓冲器这就是为什么你的代码运行在一个无限循环中。

    如果您已初始化 用户输入 对于非零值,这将以一种方式解决问题,因为非数字输入将导致 失败与失败 while 条件将被触发。但更好的解决方法是检查 . 如果为零,则打印一条错误消息,然后执行以下操作: fpurge(stdin) 要在再次循环之前清除无效输入,请执行以下操作:

    int rc = scanf("%f", &userInput);
    if (rc == 0)
    {
        NSLog(@"Invalid input, try again.");
        fpurge(stdin);
    }
    

    这就是输入和解析的纯C方法。防御性编码的底线是,您应该始终检查返回代码!

    正如Chris提到的,对于一个实际的Cocoa应用程序,您需要查看 NSNumberFormatter 诸如此类,但是您可能会从小部件而不是文件流获取输入,因此代码与上面的代码有很大不同。

        2
  •  1
  •   Chris Hanson    16 年前