[英]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.