欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解C語(yǔ)言fscanf函數(shù)讀取文件教程及源碼

 更新時(shí)間:2022年02月15日 10:29:21   作者:hxj7  
這篇文章主要為大家介紹了詳解C語(yǔ)言算法fscanf讀取文件示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步

fscanf 函數(shù)用于格式化讀入文件中數(shù)據(jù),可以大大提高讀取文件的效率。這次筆者將最近使用該函數(shù)的一些經(jīng)驗(yàn)記錄下來(lái)。

第一部分:?jiǎn)栴}和結(jié)論

fscanf 函數(shù)的原型是:

int fscanf(FILE* stream, const char* format, [argument...]);

fscanf 函數(shù)與 scanf 函數(shù)用法類似,只不過(guò)前者用于讀取文件流的數(shù)據(jù)而已。至于 fscanf 的基礎(chǔ)用法我就不贅述了,網(wǎng)上的文章很多。簡(jiǎn)單提及一下要點(diǎn):

  • 1. format str:如%d, %f, %c, %s等,分別表示讀入一個(gè)整數(shù),浮點(diǎn)數(shù),字符,字符串。還可以加上控制,如%ld,表示讀入一個(gè)長(zhǎng)整型數(shù),%20s表示最多讀入20個(gè)字符。
  • 2. 返回值:在沒(méi)有出錯(cuò)的情況下,fscanf 返回正確匹配和賦值的域的個(gè)數(shù);如果出錯(cuò),則返回EOF。

fscanf 的難點(diǎn)在于以下幾點(diǎn):

  • 1. 對(duì)空白符的處理(空格、制表符、換行符);
  • 2. *的用法;
  • 3. [] 以及 [^] 的用法;
  • 4. EOF 的處理;

對(duì)于上述問(wèn)題,網(wǎng)上的文章都語(yǔ)焉不詳,所以筆者自己寫(xiě)了點(diǎn)實(shí)驗(yàn)代碼進(jìn)行驗(yàn)證,應(yīng)該是比較詳細(xì)的小結(jié)了。
先把結(jié)論羅列在下面,具體的實(shí)驗(yàn)代碼放在文章最后:

  • 1. 在空白符這個(gè)意義上來(lái)講,fscanf 對(duì)空格、制表符、換行符是一視同仁的,不加區(qū)分的;%s會(huì)跳過(guò)前面的空白符,但是不會(huì)跳過(guò)后面的空白符;%c不會(huì)跳過(guò)空白符。
  • 2. *表示讀取一個(gè)域,但是不賦值給變量。
  • 3. []表示只讀取中括號(hào)內(nèi)的字符,[]表示不讀取中括號(hào)內(nèi)的字符,值得注意的是%[]s將不會(huì)跳過(guò)前面的空白符。
  • 4. 如果還沒(méi)有任何一個(gè)域匹配成功或者任何一個(gè)匹配失敗發(fā)生之前,就達(dá)到了文件流末尾,就算出錯(cuò);或者讀取文件流出錯(cuò)。這兩種情況下,fscanf 返回EOF。

第二部分:實(shí)驗(yàn)代碼

為了驗(yàn)證上面提出的一些問(wèn)題,筆者動(dòng)手寫(xiě)了下面的實(shí)驗(yàn)代碼進(jìn)行驗(yàn)證分析,代碼共分為六個(gè)部分,注意每個(gè)部分所使用的文件內(nèi)容是不一樣的:

  • 1. fscanf 對(duì)空格的處理;
  • 2. fscanf 對(duì)制表符的處理;
  • 3. fscanf 對(duì)換行符的處理;
  • 4. 當(dāng)空格、制表符以及換行符混雜時(shí)fscanf的處理;
  • 5. []符號(hào)在format str中的應(yīng)用;
  • 6. 出錯(cuò)的情況。

實(shí)驗(yàn)代碼:

(注意為了清晰無(wú)誤地表示出不同的空白符,用 <\b>代表空格,<\t>表示制表符,<\n>表示換行符。)

      #include <stdio.h>
      #include <errno.h>
      void fscanfTest(FILE* fp) {
        char c1, c2, s1[100], s2[100];
        int d;
        // 第一部分:fscanf對(duì)空格的處理
        printf("the content of file is:\n");
        printf("hello<\\b>world<\\b><\\b>666lucky<\\n>");
        printf("\n\n");
        // %s不會(huì)跳過(guò)后面的空格
        fscanf(fp, "%s", s1);
        printf("%s!\n", s1);  // hello!
        // %s會(huì)跳過(guò)前面的一個(gè)空格
        rewind(fp);   // 將光標(biāo)移回文件開(kāi)頭
        fscanf(fp, "%s%s", s2, s1);
        printf("%s! %s!\n", s2, s1);  // hello! world!
        // %*s會(huì)從文件流中讀入,但是不會(huì)將值賦予變量(*的作用)
        rewind(fp);
        fscanf(fp, "%*s%s", s1);
        printf("%s!\n", s1);  // world!
        // %s會(huì)跳過(guò)前面的多個(gè)空格
        rewind(fp);
        fscanf(fp, "%*s%s%s", s2, s1);
        printf("%s! %s!\n", s2, s1);  // world! 666lucky!
        // %c不會(huì)跳過(guò)空格
        rewind(fp);
        fscanf(fp, "%*s%c", &c1);
        printf("%c!\n", c1); // " !"
        // format str中的一個(gè)空格表示如果文件流接下來(lái)有連續(xù)空格,都跳過(guò)
        rewind(fp);
        fscanf(fp, "%*s%*s %c", &c1);
        printf("%c!\n", c1);          // "6!"
        rewind(fp);
        fscanf(fp, "%*s%*s%*d%c", &c1);
        printf("%c!\n", c1);          // "l!" 
        rewind(fp);
        fscanf(fp, "%*s%*s%*d %c", &c2);   // 注意這里format str中的空格沒(méi)起作用,是因?yàn)?66和lucky之間沒(méi)有空白符
        printf("%c!\n", c2);          // "l!"
        rewind(fp);
        fscanf(fp, "%*s%*s%*d%s", s1);
        printf("%s!\n", s1);          // "lucky!" 
        rewind(fp);
        fscanf(fp, "%*s%*s%*d %s", s2);
        printf("%s!\n", s2);          // "lucky!"
        // format str中的多個(gè)連續(xù)空格和一個(gè)空格的效果是一樣的
        rewind(fp);
        fscanf(fp, "%*s %c", &c1);
        printf("%c!\n", c1); // "w!"
        rewind(fp);
        fscanf(fp, "%*s  %c", &c2);
        printf("%c!\n", c2); // "w!"
        // 第二部分:fscanf對(duì)制表符的處理
        printf("the content of file is:\n");
        printf("hello<\\t>world<\\t><\\t>666lucky<\\n>");
        printf("\n\n");
        // %s不會(huì)跳過(guò)后面的制表符
        fscanf(fp, "%s", s1);
        printf("%s!\n", s1);  // hello!
        // %s會(huì)跳過(guò)前面的一個(gè)制表符
        rewind(fp);
        fscanf(fp, "%s%s", s2, s1);
        printf("%s! %s!\n", s2, s1);  // hello! world!
        // %s會(huì)跳過(guò)前面的多個(gè)制表符
        rewind(fp);
        fscanf(fp, "%*s%s%s", s2, s1);
        printf("%s! %s!\n", s2, s1);  // world! 666lucky!
        // %c不會(huì)跳過(guò)制表符
        rewind(fp);
        fscanf(fp, "%*s%c", &c1);
        printf("%c!\n", c1); // "<\\t>!"
        // format str中的一個(gè)制表符表示如果文件流接下來(lái)有連續(xù)制表符,都跳過(guò)
        rewind(fp);
        fscanf(fp, "%*s%*s\t%c", &c1);
        printf("%c!\n", c1);          // "6!"
        rewind(fp);
        fscanf(fp, "%*s%*s%*d%c", &c1);
        printf("%c!\n", c1);          // "l!" 
        rewind(fp);
        fscanf(fp, "%*s%*s%*d\t%c", &c2);
        printf("%c!\n", c2);          // "l!"
        rewind(fp);
        fscanf(fp, "%*s%*s%*d%s", s1);
        printf("%s!\n", s1);          // "lucky!" 
        rewind(fp);
        fscanf(fp, "%*s%*s%*d\t%s", s2);
        printf("%s!\n", s2);          // "lucky!"
        // format str中的多個(gè)連續(xù)制表符和一個(gè)制表符的效果是一樣的
        rewind(fp);
        fscanf(fp, "%*s\t%c", &c1);
        printf("%c!\n", c1); // "w!"
        rewind(fp);
        fscanf(fp, "%*s\t\t%c", &c2);
        printf("%c!\n", c2); // "w!"
        // 第三部分:fscanf對(duì)換行符的處理
        printf("the content of file is:\n");
        printf("hello<\\n>world<\\n><\\n>666lucky<\\n>");
        printf("\n\n");
        // %s不會(huì)跳過(guò)后面的換行符
        fscanf(fp, "%s", s1);
        printf("%s!\n", s1);  // hello!
        // %s會(huì)跳過(guò)前面的一個(gè)換行符
        rewind(fp);
        fscanf(fp, "%s%s", s2, s1);
        printf("%s! %s!\n", s2, s1);  // hello! world!
        // %s會(huì)跳過(guò)前面的多個(gè)換行符
        rewind(fp);
        fscanf(fp, "%*s%s%s", s2, s1);
        printf("%s! %s!\n", s2, s1);  // world! 666lucky!
        // %c不會(huì)跳過(guò)換行符
        rewind(fp);
        fscanf(fp, "%*s%c", &c1);
        printf("%c!\n", c1); // "<\\n>!"
        // format str中的一個(gè)換行符表示如果文件流接下來(lái)有連續(xù)換行符,都跳過(guò)
        rewind(fp);
        fscanf(fp, "%*s%*s\n%c", &c1);
        printf("%c!\n", c1);          // "6!"
        rewind(fp);
        fscanf(fp, "%*s%*s%*d%c", &c1);
        printf("%c!\n", c1);          // "l!" 
        rewind(fp);
        fscanf(fp, "%*s%*s%*d\n%c", &c2);
        printf("%c!\n", c2);          // "l!"
        rewind(fp);
        fscanf(fp, "%*s%*s%*d%s", s1);
        printf("%s!\n", s1);          // "lucky!" 
        rewind(fp);
        fscanf(fp, "%*s%*s%*d\n%s", s2);
        printf("%s!\n", s2);          // "lucky!"
        // format str中的多個(gè)連續(xù)換行符和一個(gè)換行符的效果是一樣的
        rewind(fp);
        fscanf(fp, "%*s\n%c", &c1);
        printf("%c!\n", c1); // "w!"
        rewind(fp);
        fscanf(fp, "%*s\n\n%c", &c2);
        printf("%c!\n", c2); // "w!"
        // 第四部分:當(dāng)空格、制表符以及換行符混雜時(shí)fscanf的處理
        printf("the content of file is:\n");
        printf("hello<\\b><\\t><\\n>world<\\t><\\b><\\n>666lucky<\\n>");
        printf("\n\n");
        // %s會(huì)跳過(guò)連在一起的空格、制表符和換行符
        fscanf(fp, "%s%s", s2, s1);
        printf("%s! %s!\n", s2, s1);  // hello! world!
        // 當(dāng)作為空白符時(shí),format str中的空格、制表符以及換行符是一樣的,可以相互替代!
        rewind(fp);
        fscanf(fp, "%*s %c", &c1);
        printf("%c!\n", c1);  // "w!"
        rewind(fp);
        fscanf(fp, "%*s\t%c", &c2);
        printf("%c!\n", c2);  // "w!"
        rewind(fp);
        fscanf(fp, "%*s\n%c", &c1);
        printf("%c!\n", c1);  // "w!"
        // 第五部分:[]符號(hào)在format str中的應(yīng)用
        printf("the content of file is:\n");
        printf("hello<\\b><\\t><\\n>world<\\b><\\t>666lucky<\\n>");
        printf("\n\n");
        // [el]表示只讀取'e'或者'l'這個(gè)字符,[0-9]表示只讀取0-9這10個(gè)數(shù)字字符
        // %[]之后的域都不起作用了,不會(huì)讀取文件流。
        // test#1: %c%[]s可以正常工作
        // output#1: h! ell!
        errno = 0;
        d = fscanf(fp, "%c%[el]s", &c1, s1);
        if (d == 2) printf("%c! %s!\n", c1, s1);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // test#2: %[]s后面的%c沒(méi)有正常讀取
        // output#2: d = 2
        errno = 0;
        rewind(fp);
        d = fscanf(fp, "%c%[el]s%c", &c2, s2, &c1);
        if (d == 3) printf("%c! %s! %c!\n", c2, s2, c1);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // test#3: %[]s后面的%s沒(méi)有正常讀取
        // output#3: d = 2
        errno = 0;
        rewind(fp);
        d = fscanf(fp, "%c%[el]s%s", &c1, s1, s2);
        if (d == 3) printf("%c! %s! %s!\n", c1, s1, s2);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // test#4: 再次運(yùn)行fscanf函數(shù)就可以繼續(xù)讀取文件流
        // output#4: o! world!
        errno = 0;
        d = fscanf(fp, "%c%s", &c2, s2);
        if (d == 2) printf("%c! %s!\n", c2, s2);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // [^el]表示不讀取'e'也不讀取'l'這個(gè)字符,[^0-9]表示不讀取0-9的數(shù)字字符
        // %[^]之后的域都不起作用了,不會(huì)讀取文件流。
        // test#5: %c%[^]s可以正常工作,注意下面的%[^w]s這個(gè)域讀取了空格、制表符以及換行符。
        // output#5: h! ello<\\b><\\t><\\n>!
        errno = 0;
        rewind(fp);
        d = fscanf(fp, "%c%[^w]s", &c1, s1);
        if (d == 2) printf("%c! %s!\n", c1, s1);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // test#6: %[^]s后面的%s沒(méi)有正常讀取
        // output#6: d = 2
        errno = 0;
        rewind(fp);
        d = fscanf(fp, "%c%[^w]s%s", &c2, s2, s1);
        if (d == 3) printf("%c! %s! %s!\n", c2, s2, s1);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // test#7: 再次運(yùn)行fscanf函數(shù)就可以繼續(xù)讀取文件流
        // output#7: w! orld!
        errno = 0;
        d = fscanf(fp, "%c%s", &c1, s1);
        if (d == 2) printf("%c! %s!\n", c1, s1);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // test#8: %[^\n]s可以一直讀取到行末尾,哪怕遇到空格或者制表符。
        // output#8: h! ello<\\b><\\t>!
        errno = 0;
        rewind(fp);
        d = fscanf(fp, "%c%[^\n]s", &c2, s2);
        if (d == 2) printf("%c! %s!\n", c2, s2);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // test#9: %[^ ]s不會(huì)讀取空格,但是會(huì)讀取制表符和換行符
        // output#9: <\\t><\\n>world!
        errno = 0;
        rewind(fp);
        d = fscanf(fp, "%*s%*c%[^ ]s", s1);
        if (d == 1) printf("%s!\n", s1);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }  
        // test#10: %[^\t]s不會(huì)讀取制表符,但是會(huì)讀取空格和換行符
        // output#10: <\\n>world<\\b>!
        errno = 0;
        rewind(fp);
        d = fscanf(fp, "%*s%*c%*c%[^\t]s", s2);
        if (d == 1) printf("%s!\n", s2);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        } 
        // test#11: %[^]s不會(huì)跳過(guò)前面的空白符
        // output#11: <\\b><\\t><\\n>wo!
        errno = 0;
        rewind(fp);
        d = fscanf(fp, "%*s%[^r]s", s1);
        if (d == 1) printf("%s!\n", s1);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
        // 第六部分:出錯(cuò)的情況
        // 從第五部分 test#2 以及 test#3 的例子中可以看出,fscanf的返回值表示能夠正確賦值的域的個(gè)數(shù)。如果出錯(cuò),fscanf返回EOF。
        // 怎樣才算出錯(cuò)?如果還沒(méi)有任何一個(gè)域匹配成功或者任何一個(gè)匹配失敗發(fā)生之前,就達(dá)到了文件流末尾,就算出錯(cuò);或者讀取文件流出錯(cuò)。就這兩種情況。
        // 即使所有域都不匹配,但只要沒(méi)到達(dá)文件流末尾并且讀取文件流過(guò)程中沒(méi)有發(fā)生錯(cuò)誤,就不算出錯(cuò),errno就是0。此時(shí),fscanf返回0。
        printf("the content of file is:\n");
        printf("hello");
        printf("\n\n");
        // test#1: 此時(shí)的%c發(fā)生匹配失敗,所以返回值為0。
        // output#1: d = 0
        errno = 0;
        d = fscanf(fp, "%*s%c", &c1);
        if (d == 1) printf("%c!\n", c1);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }   
        // test#2: 繼續(xù)讀取,已經(jīng)到達(dá)文件流末尾,返回EOF。
        // output#2: d = -1
        errno = 0;
        d = fscanf(fp, "%c", &c2);
        if (d == 1) printf("%c!\n", c2);
        else {
          printf("d = %d\n", d);
          if (errno != 0) perror("fscanf");
          else printf("Error: no matching characters!\n");
        }
      }
      int main(int argc, char* argv[]) {
        FILE *fp;
        if (argc < 2) {
          printf("Usage: %s <filename>\n", argv[0]);
          return 1;
        }
        if ((fp = fopen(argv[1], "r")) == NULL) {
          printf("Error: cannot open file\n");
          return 1;
        }
        fscanfTest(fp);
        fclose(fp);
        return 0;
      }

以上就是詳解C語(yǔ)言fscanf函數(shù)讀取文件示例教程的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言fscanf讀取文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論