乙個C語言初學者寫乙個查詢替換程式的歷程

2021-06-22 02:18:37 字數 3206 閱讀 2241

本人大一,正式接觸c語言剛剛三個月,基礎不牢,在寫一道作業時走了許多彎路,也有許多收穫,分享給大家。

作業題目如下「編寫乙個程式repl,它用命令列指定的字串替換命令列指定檔案中的單詞。例如,命令列:repl file.txt you they  將用you替換file.txt檔案中所有單詞they。」

此時我們剛剛學到「檔案的輸入與輸出」一章,老師說這章內容許多要自學,主要是stdio.h中的一些函式,我草草看了看,就開始胡亂的敲起了我的**。

我首先想到的方法如下(哈哈,不要笑話我啊,原來真的沒怎麼學過c語言):我感覺建立臨時檔案的方法比較麻煩(其實並不麻煩),就想著在原文字檔案中直接進行查詢替換(自然不大可能),先用乙個find函式查詢要被替換的字串所在位置,然後返回乙個檔案指標,再用乙個repl函式完成後續的替換操作。這種方法的最終成品如下:

#include #include #include //#define debug

file *find(file *fp,char *s,int m); /*m為被替換字串字元數*/

file *repl(file *fp,char *s,int m,int n); /*m為被替換字串字元數,n為替換字串字元數*/

int main(int argc,char *argv)

file *fp,*tmpfp;

if((fp=fopen(argv[1],"rb+"))==null)

exit(-1);

for(;;)

fclose(fp);

return 0;

}file *find(file *fp,char *s,int m)

return null;

}file *repl(file *fp,char *s,int m,int n)

fsetpos(fp,ptr);

fputs(s,fp);

fseek(fp,n-1,seek_cur);

return fp;

}

雖然這**什麼也幹不了,但我為完成這個作業所用的四分之三的時間都用在了這個上面。彎路都走完了,就找著正路了。由於codeblocks貌似無法除錯帶引數的main函式(我自己嘗試,set program's arguments中的語句貌似只在程式執行中有效,和網上說的不太一樣),我就用#ifdef與#endif之間的語句來大致了解程式執行的流程。

我走過以下幾處彎路:

1、第15行我對文字檔案的開啟方式一開始是「r+」,是以文字模式開啟的,這在使用fseek函式時就遇到了問題:檔案讀寫指標無法偏移(一會你會知道,這是乙個歪打正著的結論),《c primer plus》中有如下解釋:在文字模式中,只要求保證如下這些呼叫有效:

fseek (file, 0l, seek_set)

到檔案開始

fseek (file, 0l, seek_cur)

在當前位置不動

fseek (file, 0l, seek_end)

到檔案結尾

fseek (file, ftell-pos, seek_set) 

到距檔案開始處ftell-pos位元組的位置,ftell-pos是ftell( )的返回值

2、為什麼說我上面那個結論是歪打正著呢,原因是這樣的,我看到我的程式跑不好,我就增加了第35行的語句來進行跟蹤,令人驚奇的是每次輸出的的fp指向的位址都是相同的(當然這是正常的)。其實是我把檔案指標和檔案讀寫指標搞混了,fseek函式實際上是使檔案讀寫指標發生了移動,並沒有使檔案指標發生移動。我輸出fp指向的位址,自然不會有變化了。

3、認為用空字元覆蓋字元相當於刪除字元操作,事實上在用記事本開啟檔案時,空字元為一種不可顯示字元,顯示效果和空格一樣(使用winhex開啟可以看出來,notepad++也能看出,會將空字元顯示為「null」)。

4、認為在「rb+」開啟方式下,fputs函式輸出的內容不會覆蓋後面的內容,只會插入,fwrite才會覆蓋(真不知道當時怎麼想的)。

在動過無數次小手術沒有成功後,我決定必須得動大手術了,就用建立臨時檔案的方法,把**完全重寫了(我一開始想建個大字元陣列把字元全部讀進去來著,後來覺著行不通,萬一有個上gib的文字檔案呢),成品**(其實這不是最終結果,最終結果我是用「wb」方式開啟臨時檔案的,**也有所變化,主要是不用理會'\r'的問題了)如下:

#include #include #include file *copy(file *fp,file *tmpfp,char *s,int m);          /*m為被替換字串字元數*/

file *insert(file *fp,file *tmpfp,char *s,int n); /*m為被替換字串字元數,n為替換字串字元數*/

//#define debug

int main(int argc,char *argv)

file *fp,*tmpfp;

if((fp=fopen(argv[1],"rb"))==null)

exit(-1);

if((tmpfp=fopen("tmp.txt","w"))==null)

exit(-1);

for(;;)

fclose(fp);

fclose(tmpfp);

remove(argv[1]);

rename("tmp.txt",argv[1]);

return 0;

}file *copy(file *fp,file *tmpfp,char *s,int m)

}}file *insert(file *fp,file *tmpfp,char *s,int m)

最大的收穫體現在第60、61行,我是這樣發現的,在用程式處理完乙個文字檔案後,我想在每行的末尾新增一些字元繼續測試,神奇的發現,用記事本開啟新增後儲存時行與行之間還不是一行,再次開啟後吊詭的事情出現了:文字連成了一行!

百思不得其解,我就用winhex開啟程式處理過的檔案,很奇怪的,我用程式連續處理同一文字檔案每處理一次,換行處 0a 前就多出乙個 0d 不可顯示字元,也就是字元『\r', 0a 即為』\n',一旦換行處 0d 超過兩個,在換行處用記事本開啟再次新增字元就會使 0d 0a統統消失,導致的結果是文字連成了一行。於是我在程式中加入了60、61兩行,作業完成啦!後來查閱其他書籍,得到了61行注釋中的結論。

這些收穫雖然都是書本上有的,但當自己真正的體驗到時,才能真正的感覺到書上所說的那些應該注意的地方究竟是什麼意思。

(第一次在這裡寫博文,錯誤的地方希望得到大家指正!)

如何從乙個初學者成乙個DBA

oracle的體系太龐大了,對於初學者來說,難免會有些無從下手的感覺,什麼都想學,結果什麼都學不好,所以把學習經驗共享一下,希望讓剛剛入門的人對oracle有乙個總體的認識,少走一些彎路。一 定位 oracle分兩大塊,一塊是開發,一塊是管理。開發主要是寫寫儲存過程 觸發器什麼的,還有就是用orac...

乙個初學者的RHCE之路

乙個初學者的rhce之路 1 認清你的考試目的,rhce對於初學者來說是很難的,所以我不建議沒有準備好就報考rhce,雖然我也是如此。因為此考試通過率底,靈活性大,我見過的從事linux工作的 十分牛x的人物,考兩次都沒有通過的。所以一定要明確你自己的目的,是要從事linux工作,尤其是linux網...

乙個初學者該如何學習核心

乙個初學者該如何學習核心?第一步 先會使用它。連linux 是什麼 基本操作都不會就去研究核心,純屬扯淡,門 都沒有。第二步 看懂核心原始碼需要一些作業系統 c 語言等的基礎。第三步 找本合適的核心參考書,讓它幫助你對核心有個整體的理解和認識,第四步 要能夠動手配置編譯核心,還要基本看得懂核心中的k...