[英]Specifying the maximum string length to scanf dynamically in C (like "%*s" in printf)
我可以使用此技術指定scanf
讀取到buffer
的最大字符數:
char buffer[64];
/* Read one line of text to buffer. */
scanf("%63[^\n]", buffer);
但是如果我們在編寫代碼時不知道緩沖區長度怎么辦? 如果它是函數的參數呢?
void function(FILE *file, size_t n, char buffer[n])
{
/* ... */
fscanf(file, "%[^\n]", buffer); /* WHAT NOW? */
}
此代碼容易受到緩沖區溢出的影響,因為fscanf
不知道緩沖區有多大。
記得之前看到過這個,開始認為是解決問題的方法:
fscanf(file, "%*[^\n]", n, buffer);
我首先想到的是, *
在"%*[*^\\n]"
指的是最大字符串大小傳遞參數(在這種情況下n
)。 這就是printf
*
的含義。
當我檢查scanf
的文檔時,我發現這意味着scanf
應該丟棄[^\\n]
。
這讓我有些失望,因為我認為能夠為scanf
動態傳遞緩沖區大小將是一個非常有用的功能。
有什么方法可以將緩沖區大小動態傳遞給scanf
嗎?
在scanf()
沒有printf()
格式說明符*
的模擬。
在The Practice of Programming 中,Kernighan 和 Pike 推薦使用snprintf()
創建格式字符串:
size_t sz = 64;
char format[32];
snprintf(format, sizeof(format), "%%%zus", sz);
if (scanf(format, buffer) != 1) { …oops… }
將示例升級為完整功能:
int read_name(FILE *fp, char *buffer, size_t bufsiz)
{
char format[16];
snprintf(format, sizeof(format), "%%%zus", bufsiz - 1);
return fscanf(fp, format, buffer);
}
這強調了格式規范中的大小比緩沖區的大小小一(它是可以存儲的非空字符數,不計算終止空字符)。 請注意,這與fgets()
形成對比,其中大小(一個int
,順便說一句;不是size_t
)是緩沖區的大小,而不是少一個。 有多種改進功能的方法,但它表明了這一點。 (如果這是你想要的,你可以用[^\\n]
替換格式中的s
。)
此外,正如Tim Čas在評論中指出的那樣,如果您想要(其余的)一行輸入,通常最好使用fgets()
來讀取該行,但請記住,它在其輸出中包含換行符(而%63[^\\n]
將換行符留給下一個 I/O 操作讀取)。 對於更一般的掃描(例如,2 或 3 個字符串),這種技術可能更好——特別是如果與fgets()
或getline()
,然后使用sscanf()
來解析輸入。
此外,由 Microsoft(或多或少)實施並在 ISO/IEC 9899-2011(C11 標准)的附件 K 中標准化的 TR 24731-1“安全”功能明確要求長度:
if (scanf_s("%[^\n]", buffer, sizeof(buffer)) != 1)
...oops...
這避免了緩沖區溢出,但如果輸入太長可能會產生錯誤。 可以/應該像以前一樣在格式字符串中指定大小:
if (scanf_s("%63[^\n]", buffer, sizeof(buffer)) != 1)
...oops...
if (scanf_s(format, buffer, sizeof(buffer)) != 1)
...oops...
請注意,對於使用生成的格式字符串的代碼,必須忽略或抑制有關“非常量格式字符串”的警告(來自某些編譯器的某些標志集)。
在scanf
系列函數中確實沒有可變寬度說明符。 替代方法包括動態創建格式字符串(盡管如果寬度是編譯時常量,這似乎有點愚蠢)或簡單地接受幻數。 一種可能性是使用預處理器宏來指定緩沖區和格式字符串寬度:
#define STR_VALUE(x) STR(x)
#define STR(x) #x
#define MAX_LEN 63
char buffer[MAX_LEN + 1];
fscanf(file, "%" STR_VALUE(MAX_LEN) "[^\n]", buffer);
另一種選擇是#define
字符串的長度:
#define STRING_MAX_LENGTH "%10s"
或者
#define DOUBLE_LENGTH "%5f"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.