[英]Questions about validating user input in Objective-C, number vs string
如果您输入非数字字符,为什么“确切”这个代码会无休止地循环?
第一个问题是因为我想学好防守编码。 有谁知道检查用户输入的好方法? 我的google-fu让我失望了。 有些人似乎认为,如果我在scanf
中指定%f
,我“要求” float
; 我在某种程度上通过打印userInput
的值来验证这userInput
。 事实上,如果我注释掉do while
循环,那么执行代码就没有问题了。 它为userInput
分配一个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;
}
这与Objective-C或Cocoa无关。 问题只是使用标准C库函数scanf
,并处理错误情况。 从scanf
联机帮助页,描述返回码:
零表示虽然有可用输入,但没有分配转换; 通常这是由于输入字符无效,例如'%d'转换的字母字符。
scanf
可以使用%f
说明符解析有效的数字输入,因此显然可以按预期工作。 但是如果输入非数字字符,则scanf
无法将其转换为float,并将文本stdin
在stdin
的缓冲区中 。 由于代码没有检查scanf
的返回代码,只测试userInput
是否为非零,因此循环永远不会退出,因为userInput
恰好从0.0
开始,并且永远不会更新,因为scanf
不会提取非数字stdin
缓冲区中的字符。 这就是为什么你的代码在无限循环中运行的原因。
如果已将userInput
初始化为非零值,则会以一种方式解决问题,因为非数字输入会导致scanf
失败并触发while
条件。 但更好的解决方法是检查scanf
的返回码。 如果它为零,则打印错误消息,并在再次循环之前执行fpurge(stdin)
清除无效输入,如下所示:
int rc = scanf("%f", &userInput);
if (rc == 0)
{
NSLog(@"Invalid input, try again.");
fpurge(stdin);
}
所以这是输入和解析的简单C方法。 防御性编码的底线是你应该经常检查返回码!
正如Chris所提到的,对于一个实际的Cocoa应用程序,你会想要查看NSNumberFormatter
之类的东西,但是你可能会从小部件而不是文件流中获取输入,因此代码与上面的代码完全不同。
在Cocoa中验证用户输入的正确方法是使用NSFormatter的适当子类的实例,在这种情况下类似于NSNumberFormatter。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.