2016-07-27 105 views
3

考慮下面幾行:C中的字符串格式%80 [^,]是什麼意思?

char szInline[80]; 
char szDescription[80] = { NULL }; 
float fCost = 0; 
sscanf (szInline, "%80[^,], %f", szDescription, &fCost); 

什麼是%80 [^,]嗎?

+1

btw'{NULL}'應該是'{0}'或'{'\ 0'}'。 'NULL'是一個值爲0的指針。將它分配給一個字符應該給你一個*「不兼容的整數轉換指針」*警告。 – user3386109

+0

@ user3386109:不幸的是,它很可能不會產生警告。 NULL被擴展爲一個實現定義的空指針常量,通常爲'0'。(是的,事實上,一個* null指針常量*不一定是指針類型的表達式就像您認爲的那樣直截了當。) –

+1

@ user3386109:即使將'NULL'定義爲'(void *)0'是C標準庫實現中非常流行的一種實踐,'NULL'不保證/不需要成爲指針。它可能是一個整數'0',這將使這個代碼有效。但是,你的觀點依然存在。 'NULL'在那裏沒有生意。 NULL應該只保留給指針上下文。 – AnT

回答

4

閱讀至多80個字符,直到下一個,逗號。

順便說一句,該szDescription緩衝器是由1

+1

很好的捕獲「太小1」的錯誤! – dasblinkenlight

+1

@dasblinkenlight:好的bug候選者,但在這種特殊情況下沒有任何後果,因爲輸入字符串的最大長度爲79. – chqrlie

+0

@AnT:定義:'char szInline [80];'如果'szInline'不是一個合適的字符串(不包含空字節),代碼會調用未定義的行爲。我們都假設這個片段省略了'sInline'的初始化,但省略號'...'會使它更加明顯。 – chqrlie

1

這裏太小是步驟sscanf(szInline, "%80[^,], %f", szDescription, &fCost)

  • sscanf將從,不同180字符之間解析成陣列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()是有用的選擇。

+0

有沒有辦法讓scanf匹配80個非逗號字符,以便1也會成功? –

+0

不是直接爲'sscanf()':看到我更新的答案。 – chqrlie

相關問題