實驗報告:統計字符串中子字符串出現的次數


實驗報告

源程序:

 

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int cntstring(char *source,char *substr);
 5 void main()
 6 {
 7     char str1[50],str2[20];       //str1 為主字符串,str2 為子字符串
 8     cout<<"input source string:";
 9     cin.getline(str1,50);
10     cout<<"input sub string:";
11     cin.getline(str2,20);
12     cout<<"Occurs:"<<cntstring(str1,str2)<<endl;
13 }
14 int cntstring(char *source,char *substr)
15 {
16     int sum=0;                   //統計子字符串數量初值為0
17     char *p1=source,*p2=substr;
18     while(*p1 !='\0')               //主字符串沒有結束
19     {
20         if(*p1 == *p2)               //第一個字符相同
21         {
22             while(*p1 == *p2 && *p2 !='\0')   //循環比較后續字符
23             {
24                 p1++;p2++;            //子字符串沒有結束,兩字符串同事后移一個字符
25             }
26             
27         }
28         else
29         {
30             p1++;                 //主字符串后移,重新比較
31         }
32             
33         if(*p2 == '\0')
34             sum++;
35         p2=substr;                //字字符串出現一次,指針重新指向子字符串
36     }
37     
38     return sum;                  //返回統計結果
39 }

 

提示:主函數使用cin.getline讀入主字符串和子字符串。函數cntstring對於主字符串和子字符串從第一個字符開始逐一向后比較。第二個while循環表示當主字符串的當前字符與子字符串的第一個字符相同時,循環比較后續的字符是否相同,若循環完畢且指向子字符串的指針移到子字符串的末尾,則認為完成一次成功匹配,否則主字符串后移一個字符,再重新比較。

————————————————————————————

輸入: input source string:This is a C++ program.↙

      input sub string:is↙

輸出結果:Occurs:2

————————————————————————————

二、實驗要求

對該題目進行下述修改,並對修改后的程序運行結果進行分析

錯誤分析:

重新運行程序,輸入如下數據:

input source string:aaabc↙

input sub string:aabc↙

則輸出結果為:Occurs:0

(1)對於錯誤分析中提出的問題,采用單步調試技術分析出錯的原因。修改程序使其正確。

(2)修改程序,使其能夠同時輸出子字符串在主字符串中出現的每一個位置(該位置默認為子字符串中第一個字符在主字符串中出現的位置)。

 

三、實驗結果以及分析(紅色並下划線的是增加的代碼

(1)將上述源程序代碼更改為如下所示代碼:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int cntstring(char *source, char *substr);
 5 void main()
 6 {
 7     char str1[50], str2[20];
 8     cout << "input source string:";
 9     cin.getline(str1, 50);
10     cout << "input sub string:";
11     cin.getline(str2, 20);
12     cout << "Occurs:" << cntstring(str1, str2) << endl;
13 }
14 int cntstring(char *source, char *substr)
15 {
16     int sum = 0;
17     char *p1 = source, *p2 = substr;
18     while (*p1 != '\0')
19     {
20         if (*p1 == *p2)
21         {
22             while (*p1 == *p2 && *p2 != '\0')
23             {
24                 p1++; p2++;
25             }
26 
27         }
28         else
29         {
30             p1++;
31         }
32 
33         if (*p2 == '\0') 
34         {
35             sum++;
36         37         }
38             
39         p2 = substr;
40         p1 = ++source;//←為添加的代碼; 41     }
42 
43     return sum;
44 }

分析

采用單步調試技術進行分析,拿錯誤分析中輸入的數據 aaabc 和 aabc 來舉例子

首先看實驗流程,main函數將輸入的兩個字符串str1,str2作為實參,傳遞給*source,*substr的指針變量。

在用戶函數cntstring中,聲明字符型指針變量p1,p2,並將source(即str1的首地址)賦給p1,將substr(即str2的首地址)賦給p2。

看函數執行部分,當*p1(str1的首地址)不等於結束符'\0'時,進入while循環,如果*p1與*p2(str2的首地址)相等,則進入if語句,當指針p2還未指向結束符'\0'時,指針p1與p2同時向后移動一個字符,指向下一個字符。如str1為"aaabc",str2為"aabc",開始時,p1指向str1中的a,p2指向str2中的a,字符相同,兩個指針同時向后移動。當指向的字符不相同時,指針p1指向下一個字符,當p2還未指向結束符'\0'時,將p2指針初始化,指向str2的第一個字符,同時也將p1指針初始化,指向str1的第二個字符(注意++source為指針運算,指針可以自增)。若p2指向了結束符,意味着已經找到了子字符串,故sum++(若沒有找到子字符串p2是不可能指向結束符的)。當p1還未指向str1的結束符時,再次循環,從頭上判斷 字符是否相等開始(注意此時p1已經指向str1的第二個字符)。相同步驟以此類推

對於aaabc和aabc,前兩個字符是相同的,當同時指向各自的第三個字符時,字符不相同,執行else語句中的p1++,p1指向了字符b,但后面有p1指針的初始化(p1=++source),故該輪循環結束后,p1指向str1的第二個字符a,p2也初始化,指向str2的第一個字符a,又開始一輪循環,則后面字符都相同,直到p2指向結束符,p1也指向結束符,執行了sum++語句,即sum=0+1,sum=1;返回值給主函數輸出 Occurs:1;

(建議自己拿一只筆,用箭頭模仿指針走向,按照程序運行的步驟來分析)

(2)將第一題中的代碼改為如下代碼:

 

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int cntstring(char *source, char *substr);
 5 void main()
 6 {
 7     char str1[50], str2[20];
 8     cout << "input source string:";
 9     cin.getline(str1, 50);
10     cout << "input sub string:";
11     cin.getline(str2, 20);
12     cout << "Occurs:" << cntstring(str1, str2) << endl;
13 }
14 int cntstring(char *source, char *substr)
15 {
16     int sum = 0;
17     char *p1 = source, *p2 = substr,*p0 = source; 18     while (*p1 != '\0')
19     {
20         if (*p1 == *p2)
21         {
22             while (*p1 == *p2 && *p2 != '\0')
23             {
24                 p1++; p2++;
25             }
26 
27         }
28         else
29         {
30             p1++;
31         }
32 
33         if (*p2 == '\0') 
34         {
35             sum++;
36             cout << "postion=" << source-p0+1<< endl; 37         }
38             
39         p2 = substr;
40         p1 = ++source;
41     }
42 
43     return sum;
44 }

 

分析

將str1的首地址賦給一個不變化的指針*p0(因為在后面運行中source會自增,設一個指針變量將其首地址保存下來)。

對於位置:由指針的運算可知,指針相減得出來的是整數且整數的值為兩個指針指向的地址之間的數據單元的數量,舉個栗子:

當p1指向aaabc中的b的時候,則p1-source(首地址,為第一個a)=3;(3個數據單元)

由於當str1,str2中的字符開始相等時,會進入while循環,就不會每指向下一個字符的時候進行初始化(p2 = substr;p1 = ++source;

此時source保存着子字符串第一個字符在主字符串中的位置,比如主字符串為aaabc,子字符串aabc;source的值為主字符串中第二個a的地址

故source-p0等於1,再加1就是第二個a的位置,即子字符串在主字符串的中的位置。(仔細理解一下,我寫的可能不夠形象)

 

算法思想:指針的運算以及指針的移動指向。(具體看題(1)中的解釋)

 

以上就是一道例題以及擴展題目的展示。若有更好的方法希望指出,謝謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM