7.4 字串及應用
7。4 字串及應用
上一節介紹了二維陣列的定義、初賦值、記憶體映象及陣列元素的使用。本節主要講字串、字串的的儲存和使用。
文字處理是計算機應用的重要工作。近年來,計算機更多地被用來文字處理而非數值處理,如文字的輸入、編輯、排版、查詢、替換和輸出等。為了能進行簡單文字處理,C語言可以透過定義字元型資料來完成一些的工作。如:
char ch;ch=getchar( );putchar(ch);
以上程式碼定義了一個字型變數,並且可以透過getchar函式輸入一個字元存放到字元變數ch中,再透過putchar(ch)把字元輸出來。字元常量用單引號定界,可以是普通字元,如‘A’、‘#’、‘9’等,也可以是跳脫字元,如‘\n’、‘\t’、‘\x41’、‘\101等。如果兩個單引號之間什麼也沒有,如’‘,則稱為空字元,這與空白’ ‘字元不同,空白字元中有一個稱為空格的符號。
很多時候,我們要處理更多的字元,因此我們可以把這些字元按順序排列,並用一對雙引號(“”)定界,稱為
字串常量
。回顧一下,我們在學習scanf與printf函式時,函式的第一個引數——
格式控制字串
就是字串。如:
“Hello,world!\n”“a=%d,b=%d\n”
如果要讓螢幕上顯示的Hello,world兩端帶有雙引號(“),則字串要寫成這樣的形式:
”\“Hello,world!\”\n“
此時字串用轉義符號
'\"'
表示雙引號,目的是要與用來定界的雙引號區別開。
字串常量可以用printf輸出,此時要用%s格式符表示。如;
printf(”Hello,%s“,”world!\n“);
printf函式執行時,會把字串”world!\n“去代替格式控制字串中的%s,因此螢幕上顯示:
Hello,world!
字串常量被儲存在連續的儲存空間中,最後用一個特殊的字元
'\0'
表示字串的結束,如“Hello,world!”在記憶體中是這樣儲存的:
地址
內空空間
編號
xxx0D
12
xxx0C
'\0'
11
xxx0B
’d‘
10
xxx0A
’l‘
9
xxx09
’r‘
8
xxx08
’o‘
7
xxx07
’w‘
6
xxx06
’,‘
5
xxx05
’o‘
4
xxx04
’l‘
3
xxx03
’l‘
2
xxx02
’e‘
1
xxx01
’H‘
0
字串常量”Hello,world!“佔用的儲存空間中的內容是不可被改變的。我們看到的是一串符號,但在計算機中
字串常量是其第一個字元的首地址
,如上圖,”Hello,world!“的值是一個地址數值xxx01,即字元’H‘的首地址。我們可以透過以下輸出來驗證字串是一個地址的事實:
printf(”%d“,”Hello,world!\n“);
注意這裡用的格式符是
%d
,而不是
%s
。因此語句執行後顯示的結果是一個整數,而不是字串本身。
很遺憾C語言沒有提供字串變數,這使操作字串時稍稍麻煩些。由於字串佔用連續儲存空間,所以可以透過定義
字元陣列
來儲存字串。如:
char str[80];
字元陣列str可以存放79個字元的字串,因為要留一個字元來儲存字串結束標誌’\0‘。字串在定義的同時是可以被賦初值的,有以下幾種賦初值的辦法:
char str[80]={’H‘,’e‘,’l‘,’l‘,’o‘,’!‘,’\0‘};char str[80]=”Hello!“;char str[80]={”Hello!“};
三種賦初值的結果都一樣,但是第一種很顯然要麻煩得多,因為一個字元一個字元賦值,並且在最後不能忘記字串結束標
'\0'
。而後兩種賦初值,會依次把每個字元複製到字元陣列str的每個元素中,含最後的字串結束符號
'\0'
。
字串的輸出可以用printf或puts函式實現。用printf函式時,要在格式控制字串中用格式符%s指定,用puts不需要指它格式符,如:
printf(”%s“,str);puts(str);
我們前面講過,陣列名字是地址常量,因此str是一個地址。那麼怎麼輸出字串呢?執行以上語句時,printf函式從str地址對應的字元開始逐個字元輸出,直到碰到字串結束標誌’\0‘為止。我們可以用前面學習的陣列元素的輸出方法(逐個元素)來輸出字串,即:
for(i=0;str[i]!=’\0‘;i++) putchar(str[i]);
與一維陣列輸出不同是
迴圈控制條件
。前面用i小於陣列長度來表示。字串的長度可以用strlen函式來確定,但如果先求字串長度再輸出顯示多消耗了一些時間。因為知道字串以’\0‘結束。因此,迴圈條件可設為為str[i]!=’\0‘,即當第i個字元為’\0‘時,表示字串結束,退出迴圈。
知道了字串的輸出方法後,我們來看一如何輸入字串儲存到陣列中。我們可以用getchar函式一個字元一個字元地輸入,輸入一個就儲存到陣列對應的元素中,此時需要一個計數器記錄當前輸入的字元個數,只要不碰到回車我們繼續輸入。給字元陣列輸入字串的程式碼段為:
cnt=0; //計數器為零,表示初始沒有字元while( (ch=getchar( ))!=’\0‘){ str[cnt]=ch; cnt++;}str[cnt]=’\0‘;
以上程式碼能完成了字串的輸入並儲存到字元陣列str中,但是這裡假定了str陣列是無限長的,在實際應用時,還要限定輸入字串的長度,如cnt cnt=0;while( (ch=getchar( ))!=’\n‘ && cnt 當然我們可以用scanf函式來實現字串的輸入,此時格式控制字串中要使用%s格式符,如: scanf(”%d“,str); 由於陣列名str本身是一個地址常量,所以不能在str的前面用取地址運算子&。但是scanf只能實現沒有空格的字串輸入,如果輸入的字串含有空格,只取空格前的字串放到陣列中。 也可以用使用gets函式來實現字串的輸入,與scanf相比,可以輸入帶有空格的字串,輸入方式為: gets(str); 上面,我們已經學習字串的概念、儲存與字串的輸入與輸出,以下通過幾個例項深入掌握字串的應用。 例1 :輸入一個以回車符為結束標誌的字串(少於80個字元),判斷該字串是否為迴文。迴文指的是字串中心對稱或正向讀與反向讀都是一樣的,如“abcba” “abccba”是迴文,“abcdba”不是迴文。 字串的輸入與輸出,我們可以直接使用前面的方法實現,所以本例的關鍵是判斷字串str是否迴文。為此,可設兩個變數i、j,i儲存字串前面的字元的下標,j儲存字串後面字元的下標,初始時i為0,j為字串最後一個字元下標(字串長度-1)。比較str[i]與str[j],如果兩個字元相等,則分別讓i加1、j減1。如果不等或者i比j大,則程式結束。 初始狀態 比較完第一次後i,j下標的位置 完整的程式如下: #include 程式使用i>=j判斷是否迴文,原因是如果不是迴文,一定是因為條件str[i]!=str[j]退出的,此時i小於j。只有從條件i>=j退出,此時說明是迴文。 例2: 輸入一個以回車符為結束標誌的字串(少於80個字元),統計其中數字字元’0‘……’9‘的個數。 本例我們用gets輸入字串str,然後依次檢驗每個字元str[i]是否是數字,如果是則讓記數器cnt加1。檢驗字元str[i]的程式碼為: if(str[i]>=’0‘ && str[i]<=’9‘) cnt++; 由於’\0‘之前的每個字元都要被檢驗到,因此可以使用for迴圈或while迴圈實現,用for迴圈如下: for(i=0;str[i]!=’\0‘;i++) //str[i]!=’\0‘可簡寫為str[i] if(str[i]>=’0‘ && str[i]<=’9‘) cnt++; 完整的程式如下: #include 例3: 輸入一個以回車符為結束標誌的字串(少於20個字元),提取其中所有的數字字元( ’0‘……’9‘ ),將其轉換為一個十進位制整數輸出。 分析: 如有字串“abc1xyz2uvw3#yuv”,提取的數字字元應該是’1‘、’2‘、’3‘,因此構成的十進位制整數是123。如何才能把’1‘、’2‘、’3‘變成十進位制整數呢? 假設該十進位制數為x,則x的初值為0。然後碰到’1‘後,要把1放在x的之後(0 1 ),可讓x乘以10再加上’1‘對應的數1,即:x=x*10+’1‘-’0‘=1;當碰到’2‘時,要把2放在x之後(1 2 ),可讓x乘以10再加上’2‘對應的數2,即:x=x*10+’2‘-’0‘=10+2=12。最後,要把’3‘放在x之後(12 3 ),即讓x=x*10+’3‘-’0‘=12*10+3=123。因此當str[i]是數字時要作如下處理: if(str[i]>=’0‘ && str[i]<=’9‘) x=x*10+str[i]-’0‘; //讓str[i]作為x的個位 用for迴圈對字串每個字元進行處理,程式碼如下: for(i=0;str[i];i++) if(str[i]>=’0‘ && str[i]<=’9‘) x=x*10+str[i]-’0‘; 完整的程式如下: #include 最後講一下 字串的長度 ,字串的長度指的是字串中包含字元的個數。空字串”“指的是不包括任何字元的串,只有一個字元結束符’\0‘,因此字串長度為0。字串”Hello world!“的字元個數為12。但是如果字串中含有轉義符,則多個符號表示的轉義符只算作一個字元,如:字串”\\\x41\\“長度為3而不是8,因為’\\‘是一個字元,’\x41‘是一個字元’A‘,如果用printf輸出,顯示為:\A\。 本節主要介紹了字串常量及用字串陣列儲存、輸入與輸出字串的方法。字串的應用很頻繁,初學者只有不斷加強字串程式設計訓練才能更好掌握字串應用。本節就講到這裡,下次再見!