簡體   English   中英

C整數安全輸入

[英]C Integer Safe Input

如何使用scanfgets獲得安全的整數輸入(尤其是正數)? 我嘗試了幾種解決方案,每種解決方案都有一些問題。

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) ),就會引發運行時錯誤。


那么使用scanfgets從控制台窗口檢索整數值的正確方法是什么?

答案取決於您所說的安全到底是什么意思。 如果要捕獲任何可能的輸入錯誤,則唯一的選擇是使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM