C語言:輸入任意字符串替換字符串中任意的子字符串,無限制中英文

一、實(shí)現(xiàn)的功能
1.提示用戶輸入一段句子,用戶可以輸入任意長度的句子,不限制中英文。
2.提示用戶輸入需要被替換的文字。
3.提示用戶輸入替換的內(nèi)容,不限制長度和中英文。
4.然后輸出替換后的句子。
二、算法實(shí)現(xiàn)
1.實(shí)現(xiàn)功能1、2、3
(1)首先需要聲明一個(gè)動(dòng)態(tài)輸入函數(shù):
char* strdc(char *s)
該函數(shù)的返回值為一個(gè)字符型指針,指向輸入字符串的內(nèi)存地址,該函數(shù)接收一個(gè)字符型指針,該指針的指向與返回值指向相同。
(2)在函數(shù)內(nèi)定義整型變量:count,ch并初始化為0,來分別記錄循環(huán)的次數(shù)以便增加多少內(nèi)存和用于接收用戶輸入的字符
(3)然后初始化指針s指向的內(nèi)存大小,這里采用malloc()函數(shù),該函數(shù)包含在頭文件stdlib.h中,初始空間只需要申請一個(gè)字符大小即可,用來保存用戶輸入的第一個(gè)字符,其余字符的保存靠循環(huán)增加其內(nèi)存。
(4)進(jìn)入循環(huán),每當(dāng)用戶輸入一個(gè)字符,將該值對應(yīng)的ASCII碼賦值給變量ch,然后判斷該值是否為換行符,這是循環(huán)退出的條件,然后將ch賦值給s[count],完成一個(gè)字符的存儲(chǔ),然后使count自增1,然后為指針s指向的內(nèi)存擴(kuò)大1個(gè)字符的內(nèi)存大小,這里采用realloc()函數(shù),并將新內(nèi)存的地址返回給s(這里不能確定relloc函數(shù)返回的指針指向和之前指針s的指向一樣,所以需要重新將其賦值給s),然后循環(huán)往復(fù),直到用戶按下回車換行鍵位’\n’,退出循環(huán),然后將結(jié)尾字符’\0’地址賦值給指針s[count],完成動(dòng)態(tài)輸入字符串,然后返回指針s,然后手動(dòng)釋放指針s的內(nèi)存,避免產(chǎn)生內(nèi)存泄露并使s指向空,防止s變成野指針。
2.實(shí)現(xiàn)字符串替換:
(1)需要聲明一個(gè)字符串替換的函數(shù):
char* strsub(char *str1,char *str2,char *str3)
該函數(shù)的返回值為一個(gè)字符指針,該函數(shù)接受三個(gè)字符型指針參數(shù),str1,str2,str3分別為指向句子的字符指針,指向被替換字符串的指針,替換的字符串。
(2)不難想到一共有三種情況:
第一種:str2指向的字符串長度大于str3
第二種:str2指向的字符串長度小于str3
第三種:是str2指向的字符串長度等于str3
顯然需要采用選擇結(jié)構(gòu),switch和if均可,筆者采用的是if.
(3)在對上述情況分別編程前,還需要先定義選擇結(jié)構(gòu)中需要用到的變量:
字符型指針變量k: 存儲(chǔ)指針str2指向的字符串在str1指向的字符串中第一次出現(xiàn)的地址。
整型變量str1_l,str2_l,str3_l: 分別是存儲(chǔ)str1,str2,str3指向的字符串的長度。
整型變量n: 存儲(chǔ)str3指向的字符串的長度與str2指向的字符串的長度的差值,用于判斷是否增加內(nèi)存。n>0擴(kuò)容,n<=0不擴(kuò)容。
整型變量y_l: 余長,y_l為str2指向的字符串在str1指向的字符串中,其str2指向字符串后面的字符的總數(shù)包括結(jié)尾’\0’。
(4)接下來開始進(jìn)入選擇結(jié)構(gòu):
1)當(dāng)str3的長度大于str2的時(shí)候(n>0):首先要獲取余長y_l,這些字符需要往后面移動(dòng),包括最后的’\0’
獲取指針str1指向的字符串的長度str1_l,每一次替換字符串前都需要重新獲取,因?yàn)榭傋址拈L度str1_l會(huì)改變。
用變量y_l創(chuàng)建一個(gè)字符數(shù)組rep[y_l]用來保存需要移動(dòng)的字符,包括最后的’\0’,每輪替換,數(shù)組的長度會(huì)改變,用變量y_l去定義數(shù)組。
使用realloc()函數(shù)為指針str1指向的內(nèi)存擴(kuò)容,新的大小為str1_l+n+1,這包括了最后的’\0’(字符串結(jié)束字符),并將返回的的指針轉(zhuǎn)換為char*型賦值給str1,因?yàn)閞ealloc()返回的指針指向并非一定就是原來str1的指向,所以得重新賦值。
同理的,指針k的指向也要重新獲取,用strstr()函數(shù),該函數(shù)包含在頭文件string.h中。
然后進(jìn)入第一個(gè)循環(huán),將被替換的字符串后面的所有字符存入字符數(shù)組rep中,這些字符是需要移動(dòng)的。
進(jìn)入第二個(gè)循環(huán),將替換的字符串存入k指向的字符串中,k指向的字符串就是str1指向的字符串的子字符串(str2指向的字符串)。
進(jìn)入第三個(gè)循環(huán),將rep數(shù)組的字符全部存回在替換的字符串后面,完成一輪替換
獲取k的指向,這里檢查的時(shí)候應(yīng)該跳過已經(jīng)替換的字符串,即替換的時(shí)候要將指針k往后移動(dòng)str3_l的長度,避免如下例子的死循環(huán):
如str1=“fish”,str2=“sh”,str3=“fish”
如果k的指向空,就退出循環(huán),完成替換。
2)當(dāng)str3的長度小于str2的時(shí)候(n<0):這時(shí)候就無需擴(kuò)容了。
首先要獲取余長y_l,這些字符需要往前面移動(dòng),包括最后的’\0’。
進(jìn)入第一個(gè)循環(huán),將替換字符串先存入指針str1指向的字符串中,注意這里不能包括結(jié)尾的’\0’,所以這里的循環(huán)條件的最大值不加1。否則會(huì)導(dǎo)致格式化%s輸出的時(shí)候,輸出到’\0’這里就停止了。
進(jìn)入第二個(gè)循環(huán),將子字符串后面的所有字符存回字符串str1中,包括最后的’\0’,注意這里的下標(biāo),n為負(fù)數(shù),要加負(fù)號。
子字符串后面的所有字符存回字符串str1中,包括最后的’\0’
獲取k的指向,這里檢查的時(shí)候也同樣要跳過已經(jīng)替換的字符串,不在贅述。
3)當(dāng)str3的長度等于str2的時(shí)候(n==0):這里還要分成兩種情況,即當(dāng)指針str2指向的字符串與str2指向的字符串內(nèi)容相等的時(shí)候,指針str2指向的字符串與str2指向的字符串內(nèi)容不相等的時(shí)候
所以這里還要使用選擇語句if,判斷表達(dá)式采用了strcmp()函數(shù),該函數(shù)包含在頭文件string.h中,如果兩字符串相等就會(huì)返回一個(gè)非零值,相等就返回0。
顯然當(dāng)指針str2指向的字符串與str2指向的字符串內(nèi)容相等的時(shí)候,不會(huì)進(jìn)入循環(huán),直接就到后面返回指針str1.
指針str2指向的字符串與str2指向的字符串內(nèi)容不相等的時(shí)候進(jìn)入循環(huán),這里直接將替換字符串先存入str1指向的字符串中就可以,不用移位。
最后出選擇結(jié)構(gòu)后,返回指針str1,然后手動(dòng)釋放str1指向的堆區(qū)內(nèi)存,避免內(nèi)存泄漏,并給str1賦值NULL,使其變?yōu)榭罩羔?,防止str1變成野指針。
至此實(shí)現(xiàn)字符串替換的函數(shù)已經(jīng)完成。
3.主函數(shù)
(1)首先要定義三個(gè)字符型指針用來保存輸入的字符串的地址。
(2)調(diào)用printf()函數(shù)提示用戶輸入相應(yīng)的字符串,注意換行,然后調(diào)用動(dòng)態(tài)輸入函數(shù)strdc()保存用戶輸入的字符串。
(3)重復(fù)步驟(2)直到所有字符串輸入完畢。
(4)調(diào)用printf()函數(shù),在其里面調(diào)用字符串函數(shù)strsub(),輸出替換后的字符串,注意換行。
(5)return 0;至此整個(gè)程序結(jié)束。
三、代碼實(shí)現(xiàn)
四、實(shí)例展示
五、其他
str1指向的字符串的長度是動(dòng)態(tài)變化的,如果采用傳統(tǒng)的定義數(shù)組的方式也可以,只要把字符數(shù)組的長度定得足夠大,只不過這樣無疑浪費(fèi)內(nèi)存,不值得推薦。
所以每當(dāng)發(fā)生字符串替換前,需要使用到relloc()函數(shù)為指針str1指向的內(nèi)存擴(kuò)容,以便容下多出的字符,但是要注意返回的指針的指向可能與之前str1的指向不一樣,所以要將返回的指針賦值給指針str1。
如有不正確之處或不足之處,歡迎各位程序員一起探討^ _ ^。
