考慮下面幾行:C中的字符串格式%80 [^,]是什麼意思?
char szInline[80];
char szDescription[80] = { NULL };
float fCost = 0;
sscanf (szInline, "%80[^,], %f", szDescription, &fCost);
什麼是%80 [^,]嗎?
考慮下面幾行:C中的字符串格式%80 [^,]是什麼意思?
char szInline[80];
char szDescription[80] = { NULL };
float fCost = 0;
sscanf (szInline, "%80[^,], %f", szDescription, &fCost);
什麼是%80 [^,]嗎?
閱讀至多80個字符,直到下一個,
逗號。
順便說一句,該szDescription
緩衝器是由1
很好的捕獲「太小1」的錯誤! – dasblinkenlight
@dasblinkenlight:好的bug候選者,但在這種特殊情況下沒有任何後果,因爲輸入字符串的最大長度爲79. – chqrlie
@AnT:定義:'char szInline [80];'如果'szInline'不是一個合適的字符串(不包含空字節),代碼會調用未定義的行爲。我們都假設這個片段省略了'sInline'的初始化,但省略號'...'會使它更加明顯。 – chqrlie
這裏太小是步驟sscanf(szInline, "%80[^,], %f", szDescription, &fCost)
:
sscanf
將從,
不同1
和80
字符之間解析成陣列szDescription
,,
字符;'\n'
);float
類型的變量fCost
。EOF
是早期失敗的情況。有在那裏潛在的問題:
szDescription
太短80個字符加上一個'\0'
終止子,但幸運的是,輸入數組szInline
還具有80的長度。如果包含一個正確的字符串,最多79
字符將與sscanf
匹配,因此不會發生溢出。尺寸說明符在這種情況下實際上不需要。,
之後的空格是多餘的。 %f
總是忽略主要的空白。謹防sscanf()
將在此輸入返回EOF
:,1
因爲有從,
不同沒有字符從輸入字符串的開頭進行解析。即使是高級C程序員也常常忽略這種特殊情況。
如果你想接受,
之前可能爲空字符串,則不能直接使用sscanf()
,但你可以使用這個:
/* compute the length of the initial sequence upto `,` if any */
size_t len = strcspn(szInline, ",");
/* len < 80 because sizeof(szInline) == 80 */
/* copying the initial string */
memcpy(szDescription, szInline, len);
szDescription[len] = '\0';
if (sscanf(szInline + len, ",%f", &fCost) != 1) {
/* conversion error: no `,` or no number past it */
...
}
sscanf()
有很多怪癖,它是極難的事情正確使用但最重要的解析任務。很少使用的標準功能strspn()
和strcspn()
是有用的選擇。
有沒有辦法讓scanf匹配80個非逗號字符,以便1也會成功? –
不是直接爲'sscanf()':看到我更新的答案。 – chqrlie
btw'{NULL}'應該是'{0}'或'{'\ 0'}'。 'NULL'是一個值爲0的指針。將它分配給一個字符應該給你一個*「不兼容的整數轉換指針」*警告。 – user3386109
@ user3386109:不幸的是,它很可能不會產生警告。 NULL被擴展爲一個實現定義的空指針常量,通常爲'0'。(是的,事實上,一個* null指針常量*不一定是指針類型的表達式就像您認爲的那樣直截了當。) –
@ user3386109:即使將'NULL'定義爲'(void *)0'是C標準庫實現中非常流行的一種實踐,'NULL'不保證/不需要成爲指針。它可能是一個整數'0',這將使這個代碼有效。但是,你的觀點依然存在。 'NULL'在那裏沒有生意。 NULL應該只保留給指針上下文。 – AnT