2014-02-21 24 views
0

我發現了一些奇怪的事情。下面是代碼示例:sscanf的奇怪行爲

... 
char *start = strchr(value, '('); 
if(start) 
{ 
    char buf[LEN]; 
    memset(buf, 0, LEN); 
    int num = sscanf(start, "(%s)", buf); 
    if(num) 
    { 
     buf[strlen(buf) - 1] = '\0'; 
     sprintf(value, "%s", buf); 
    } 
... 

如果值爲「(xxx)」,例如,那麼在此操作後值將爲「xxx」。
但是如果值是「([34] xx {4,7} | 1234567890)」,那麼值將是「[34] xx {4,7}」。
任何人都可以解釋它嗎?

P.S.它是ARM平臺。

+0

你得到的實際輸出是多少? – Dipto

+1

如果字符串在末尾沒有\ 0,則不應使用strlen(buf)。 –

+2

''sscanf()'遇到空白時會停止讀取'%s'。 '|'字符後面有一個空格。代碼然後覆蓋'|'字符。 – hmjd

回答

2
int num = sscanf(start, "(%s)", buf); 

在此,當它遇到一個空白在緩衝器sscanf返回通過start指向。你在你輸入的字符串有一個空格:

"([34]xx{4,7}| 1234567890)" 
      ^space here 

scanf返回成功匹配和分配的輸入項目的數量。在這裏,它將返回1,並且值num1。接下來,用if塊中的該語句覆蓋buf中的最後一個字符。

buf[strlen(buf) - 1] = '\0'; 

這解釋了你的程序的輸出。現在,關於您的代碼的幾件事:

您不需要做memset(buf, 0, LEN);。只需執行char buf[LEN] = {0};這將填充空字節的數組。

sscanf不檢查緩衝區buf的數組綁定,其中您正在寫入的字符串是sscanf正在從start中讀取。如果buf的大小不夠,sscanf會嘗試在超出緩衝區buf的內存中寫入。這會導致未定義的行爲,甚至因非法內存訪問而導致程序崩潰。您應該在格式字符串sscanf中給出字段寬度以防止緩衝區溢出。

#define STRINGIFY(s) #s // preprocessor command # stringifies the token s 
#define XSTRINGIFY(s) STRINGIFY(s) 
#define LEN 10 // max buffer length without the null byte 

// inside a function 

char buf[LEN + 1]; // +1 for the null byte 
const char *format = "(" XSTRINGIFY(LEN) "%s)"; // "(%10s)" 
int num = sscanf(start, format, buf); 

在格式字符串"(%10s)"10意味着至多10字符被存儲在緩衝器指向buf然後一個空字節\0在端自動添加。因此,你不需要在if塊以下幾點:

buf[strlen(buf) - 1] = '\0'; // overwrites the last char before null byte in buf. 

這樣做,事實上,將覆蓋buf,因爲strlen不計空字節的最後一個字符。

1

sscanf與%s一起使用,遇到空白時會終止。這就是您將輸出變爲「[34] xx {4,7}」而不是預期行爲的原因

+0

不應該在這種情況下num是零? – someuser

+0

sscanf返回它處理的字符數。因此它不會爲零 – arunb2w

+0

@ arunb2w'scanf'返回成功匹配和分配的輸入項*數,而不是處理的字符數。 – ajay

1

格式字符串由一系列指令組成,它們描述如何處理輸入字符序列。如果指令處理失敗,則不會讀取其他輸入,並返回scanf()。 「失敗」可以是以下兩種情況之一:輸入失敗,意味着輸入字符不可用或匹配失敗,這意味着輸入不合適(見下文)。

在你的情況,sscanf比賽開始(,然後解析下一個標記,%s消耗數據到第一個空格字符。 sscanf然後無法匹配),這意味着解析停止。一個令牌已成功讀取並分配,因此返回值爲1

請注意,使用scanf時,無法檢測到分配的最後一個令牌之後發生的匹配故障。