[英]C Integer Safe Input
如何使用scanf
或gets
獲得安全的整數輸入(尤其是正數)? 我嘗試了幾種解決方案,每種解決方案都有一些問題。
1.使用getchar()
刪除字符串輸入
int safeInput() {
int input;
scanf("%d", &input);
while(getchar() != '\n');
return input;
}
此方法有效地處理輸入字符串,但是,如果字符串如3a
被輸入時,的值input
變為3
,這是不是真正的異常處理。
2.以字符串形式檢索輸入,然后轉換為整數值。
int safeInput() {
char[200] input, safe_input;
gets(input);
// I know about the security issue about gets - but it's not the point.
int i = 0;
while (1) {
if (input[i] >= 48 && input[i] <= 57) safe_input[i] = input[i];
else break;
i++;
}
return atoi(safe_input);
}
該方法存在以下問題:如果輸入的字符串長度大於分配給input
字符串,則無法處理。
3.如果使用指針定義字符串怎么辦?
我關心通過指針定義input
,例如char *input;
。 但是,一旦我執行gets(input)
(或scanf("%s", input)
),就會引發運行時錯誤。
那么使用scanf
或gets
從控制台窗口檢索整數值的正確方法是什么?
答案取決於您所說的安全到底是什么意思。 如果要捕獲任何可能的輸入錯誤,則唯一的選擇是使用strtol()
系列的函數,該strtol()
甚至可以進行范圍檢查。 在遠離scanf()
新手指南中 ,我描述了它的用法。
這是適合您在此處嘗試的代碼,並帶有注釋:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
// return success as boolean (0, 1), on success write result through *number:
int safeInput(int *number)
{
long a;
char buf[1024]; // use 1KiB just to be sure
if (!fgets(buf, 1024, stdin))
{
// reading input failed:
return 0;
}
// have some input, convert it to integer:
char *endptr;
errno = 0; // reset error number
a = strtol(buf, &endptr, 10);
if (errno == ERANGE)
{
// out of range for a long
return 0;
}
if (endptr == buf)
{
// no character was read
return 0;
}
if (*endptr && *endptr != '\n')
{
// *endptr is neither end of string nor newline,
// so we didn't convert the *whole* input
return 0;
}
if (a > INT_MAX || a < INT_MIN)
{
// result will not fit in an int
return 0;
}
// write result through the pointer passed
*number = (int) a;
return 1;
}
首先,如果您想要安全的輸入, 請不要使用gets
。 當您可以使用fgets
時, fgets
您對這些問題的了解並不是真正的借口。 接下來,訣竅是嘗試在int之后讀取一個非空白字符:如果找不到任何人,則int后面沒有任何內容。
int safeInput(int *input) { // the return value is the indicator of failed read
int c;
char dummy[2]; // never forget the terminating null!
if (scanf("%d%1s", input, dummy) == 1) return 1;
// in case of error, skip anything up to end of line or end of file
while (((c = fgetc(stdin)) != '\n') && (c != EOF));
return 0;
}
這里的scanf
是,當scanf
返回1時, %1s
一直吃到行尾的所有內容, 包括終止符' n'
。 但這有一個主要缺點: scanf
將僅在流的結尾或讀取一個附加的(非空白)字符后結束。 因此,Felix Palmen的答案使用起來更容易,更安全。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.