簡體   English   中英

使用scanf - > ANSI C的最大字符串長度

[英]Max string length using scanf -> ANSI C

我有:

#define MAX_STR_LEN 100

我想放入scanf模式,所以我可以控制字符串長度:

scanf("%100[^\n]s",sometext)

我試過了:

scanf("%MAX_STR_LEN[^\n]s",sometext)
scanf("%"MAX_STR_LEN"[^\n]s",sometext)
scanf("%",MAX_STR_LEN,"[^\n]s",sometext)

它沒有用。 我只想避免緩沖區溢出,因為“sometext”分配了malloc(MAX_STR_LEN) ...

有任何想法嗎?

我對這些解決方案都不滿意,所以我進一步研究,發現了GNU GCC宏字符串化

可以用作:

#define XSTR(A) STR(A)
#define STR(A) #A
#define MAX_STR_LEN 100
scanf("%"XSTR(MAX_STR_LEN)"[^\n]s", sometext)

也許VS2010提供類似的東西?

我只是想避免緩沖區溢出

然后不要使用scanf() 完全沒有。

如果要掃描文本行,請不要#define MAX_STR 您可以在<limits.h>隱藏LINE_MAX (如果您的目標是POSIX兼容系統):

char buf[LINE_MAX];
fgets(buf, sizeof(buf), stdin);

應該做的伎倆。

幾乎每個人都說,最好使用fgets(..., stdin)來處理這個問題。

在下面的鏈接中,我提出了一種安全且正確的技術,可以通過一個更安全的方法,通過實體替換scanf()

一個安全替換scanf()的

我提出的宏(使用兼容的C99編譯器)是safe_scanf() ,如以下程序所示:

#include <stdio.h>
#define safe_scanf(fmt, maxb, ...) { \
    char buffer[maxb+1] = { [maxb - 1] = '\0' }; \
    fgets(buffer, maxb+1, stdin); \
    if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \
        while(getchar() != '\n') \
           ; \
    sscanf(buffer, fmt, __VA_ARGS__); \
  }

#define MAXBUFF 20     

int main(void) {
   int x; float f;      
   safe_scanf("%d %g", MAXBUFF+1, &x, &f);
   printf("Your input was: x == %d\t\t f == %g",  x, f);
   return 0;
}  

您必須根據需要調整 MAXBUFF的值...
雖然宏safe_scanf()非常可靠,
使用宏方法有一些弱點:
缺少對參數的類型檢查,缺少“返回”值(幾乎與“true” scanf()函數不同,它返回一個int ,帶有用於錯誤檢查的有價值信息),等等。
所有這些問題都有解決方案,但它是另一個主題的一部分......

也許,最精確的解決方案是通過調用stdarg.h庫來定義具有可變數量參數的函數my_scanf() ,聯合fgets()vsscanf() 在這里你有代碼:

#include <stdio.h>
#include <stdarg.h>

int my_scanf(const char* fmt, const unsigned int maxbuff, ...) {
    va_list ptr;
    int ret;

    if (maxbuff <= 0)
       return EOF; /* Bad size for buffer[] */

    char buffer[maxbuff+1];
    buffer[maxbuff-1] = '\0';  /* Quick buffer cleaning... */

    if (fgets(buffer, maxbuff+1, stdin) == NULL)
       return EOF; /* Error detected */
    else {
        if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0'))
            /* Condition logically equivalent to:
                   fgets() has not reached an '\n'
            */
            while (getchar() != '\n')
               ; /* "Flushing" stdin... */

        va_start(ptr, maxbuff);
        ret = vsscanf(buffer, fmt, ptr);
        va_end(ptr);
        return ret;
    }    
}

#define MAXBUFF 20
int main(void) {
   int x; 
   float z;
   int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z);
   printf("\nTest:\n x == %d\n z == %g\n scanfret == %d", x, z, scanf_ret);
   getchar();   
   return 0;   
}

函數my_scanf()具有原型

int my_scanf(const char* fmt, const int maxbuff, ...);

它接受格式字符串fmt ,其行為方式與其他scanf()類似。
第二個參數是從標准輸入(鍵盤)有效接受的最大字符數。
返回值是一個int ,如果maxbuff沒有意義,那么它是EOF ,或者發生了一些輸入錯誤。 如果返回非負值,則與標准函數sscanf()vsscanf()返回的值相同。

在函數內部, maxbuff在1中遞增,因為fgets()為一個額外的'\\ 0'字符騰出了空間。
立即丟棄maxbuff非正值。
fgets()將讀取從stdin (鍵盤)讀取的字符串,其中包含最多maxbuff字符的空間,包括'\\ n'。
如果用戶輸入了一個非常長的字符串,那么它將被截斷,並且需要某種“刷新”機制以便將所有字符丟棄到下一個'\\ n'( ENTER )。 如果沒有,下一個鍵盤讀取可能有舊字符,根本不需要。
“刷新”的條件是在讀取stdinfgets()沒有達到'\\ n'。
如果且僅當buffer[maxbuff - 1]不等於'\\ 0'或'\\ n'時才會出現這種情況。
檢查一下!
最后,使用stdarg.h 和函數vsscanf()的適當組合來處理變量參數列表。

推薦fgets(buffer, sizeof(buffer), stdin)方法。

如果您想使用scanf(),可以在運行時創建其格式。

#define MAX_STR_LEN 100
char format[2 + sizeof(size_t)*3 + 4 + 1];  // Ugly magic #
sprintf(format, " %%%zu[^\n]", (size_t) MAX_STR_LEN);
scanf(format, sometext);

或者將MAX_STR_LEN重新定義為字符串

#define MAX_STR_LEN "100"
scanf(" %" MAX_STR_LEN "[^\n]", sometext);

仍然推薦fgets()
注意fgets()會將前導空格和尾部\\n放在緩沖區中,而" %[^\\n]"則不會。
順便說一句:格式中的尾隨s不太可能按照你的想法行事。

怎么樣

scanf("%.*[^\n]s", MAX_STR_LEN, sometext)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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