1. 程式人生 > >scanf中特殊的格式控制符

scanf中特殊的格式控制符

scanf fscanf,均從第一個非空格的可顯示字元開始讀起!

scanf以空白字元為定界符,但如果輸入的字串是以其它字元為定界符的,那怎麼辦?

比如要讀取一串字串,以回車結尾,就可以採用scanf("%[^\n]", ...);

根據TCPL中的描述,

[...]  match the longest non-empty string of input characters from the set between brackets; A '\0' is added. []...]includes ]in the set.

 [符號可以作為掃描列表中的一個成員,但]字元除緊貼最左邊的[字元或抑揚符兩種情況外,其餘情況下都不會被看作掃描列表的成員。例如“%[]abcd]”或者“%[^]abcd]”,上述兩種情況下]字元屬於掃描列表的成員,但如果是“%[ab]cd]”,中間的]字元不會被看作掃描列表的成員,而且輸入輸出的結果會是亂七八糟的。


[^...]  match the longest non-empty string of input characters not from the set between brackets; A '\0' is added. []...]includes ]in the set.

標準輸入輸出函式scanf具有相對較多的轉換說明符,它常常作為入門級函數出現在各種教材中。但奇怪的是,[]和n這兩種都為c89/c99所規定的標準說明符卻鮮少在大多數教材中出現。

    在使用[]說明符之前,得先明白兩個概念:一是掃描列表。掃描列表(scanlist)指的是包含在[和]兩個字元之間除緊靠左邊[字元的抑揚符之外的字元,例如:

scanf("%[abcd]", ptr);

abcd組成掃描列表。二是掃描字符集(scanset)。掃描字符集指的是結果字符集,例如上面的例子,結果字符集就是abcd。如果輸入一個字串“cbadkjf”,那麼ptr得到的字串是cbad,kjf三個字元都屬於定界符,輸入到k字元時輸入字串被截斷,kjf三個字元被留在stdin裡面。如果帶有抑揚符,例如:

scanf("%[^abcd]", ptr);

掃描列表仍然是abcd,但掃描字符集是除abcd外的可輸入字元。如果輸入字串“jksferakjjdf”,ptr得到的字串是“jksfer”。如果想限制輸入字串的字元數量,可以象s說明符那樣,在[]前面使用位域,例如:

scanf("%10[^abcd]", ptr);

這樣結果字串最多隻能包含10個字元(除'/0'字元外)。


對於減號-,只有在緊貼[字元或抑揚字元以及作為掃描列表最後一個成員時,-字元才會被視為掃描列表的成員。c標準把其餘情況規定為編譯器相關的。大多數編譯器把這種情況的減號定義為連字元,例如:

scanf("%[a-zA-Z]", ptr);

那麼掃描列表由大小寫各26個字母組成。少數編譯器仍舊把這種情況下的減號視為掃描列表成員。

fscanf(fd,"%*[^/n]/n");//%*是虛讀,沒有存,只是讓指標跳過了這個變數!

%n說明符輸出有效字元數量,%n在scanf和printf中都可使用。與%n相對應的形參是一個int型別的指標,%n不影響scanf和printf的返回值。例如:

scanf("%d %d%n", &i, &j, &k);

如果輸入434 6434,則k等於8,而scanf的返回值仍然為2。又如:

scanf("%c%n", &ch, &k);

輸入“sbcdefdg”後,k等於1,而不是8,因為%c只取一個字元,%n輸出的是有效字元數量

        %n用在printf函式裡,表示輸出的字元數量,例如:

printf("i=%d, j=%d/n%n", i, j, &k);

在i=343、j=123的情況下,k=12,同時%n不影響printf的返回值,其返回值仍然為12,而不是14。

這個用法是在參H264 jm82考程式碼上看到的,用來從解碼器引數配置檔案中讀取配置引數,程式碼如下:

// read the decoder configuration file
if((fd=fopen(config_filename,"r")) == NULL)
{
snprintf(errortext, ET_SIZE, "Error: Control file %s not found/n",config_filename);
error(errortext, 300);
}

fscanf(fd,"%s",inp->infile);                // H.26L compressed input bitsream
fscanf(fd,"%*[^/n]");

fscanf(fd,"%s",inp->outfile);               // YUV 4:2:2 input format
fscanf(fd,"%*[^/n]");

fscanf(fd,"%s",inp->reffile);               // reference file
fscanf(fd,"%*[^/n]");

對應的配置檔案內容如下:

test.264                 ........H.26L coded bitstream
test_dec.yuv             ........Output file, YUV 4:2:0 format
test_rec.yuv             ........Ref sequence (for SNR)

通過這種方式

inp->infile = "test.264"

inp->outfile = "test_dec.yuv"

inp->reffile = "test_rec.yuv"

而相應的配置檔案中的一些註釋則不會被讀入,這是相當簡便的用法,比起通過嚴格約定註釋符並進行一個字元一個字元來解析,這種方式簡單了許多!值得借鑑!