字串變數
一些程式設計語言為聲明字串提供了特殊的 string 類型。C語言採取了不同的方式:只要保證字串是以Null 字元串結尾的,任何一維的字元數組都可以用來儲存字串。如果編寫自己的字串處理函數,請千萬注意要正確地處理Null 字元。
假設需要變數用來儲存最多80個字元的字串。既然字串會在末尾處需要Null 字元,那麼要聲明的變數是含有81個字元的數組。#define STR_LEN 80
/* 慣用法 */
char str[STR_LEN + 1];
對宏加一的這種方法是C程式員常用的方式。
初始化字串變數
char date1[8] = "June 14";
date1: | J | u | n | e | | 1 | 4 | /0 |
char date2[9] = "June 14";
date2: | J | u | n | e | | 1 | 4 | /0 | /0 |
大體上來說,這種行為與C語言處理數組初始化的方法一致。
字串變數的聲明可以忽略它的長度。這種情況下,編譯器會自動計算長度:
char date3[] = "June 14";
編譯器為date3分配8個字元的空間。
字元數組與字元指標
一起來比較一下下面兩個聲明:
char date[] = "June 14";
它聲明date是個字元數組。和這個聲明相似的是下面這個聲明:
char *date = "June 14";
它聲明date是個指向字串字面量的指標。
[注意],不能錯誤地認為上面兩種date可以互換。兩者之間有著顯著的差異:
(1) 在聲明為數組時,就像任意數組元素一樣,可以修改儲存在date中的字元。在聲明為指標時,date指向字串字面量。
(2) 在聲明為數組時,date是數組名。在聲明為指標時,date是變數,這個變數可以在程式執行期間指向其他字串。
如果需要可以修改的字串,那麼就要建立字元數組來儲存字串。這時聲明指標變數是不夠的。下面的聲明使編譯器為指標變數分配了足夠的記憶體空間:
char *p;
可惜的是,它不為字串分配空間。在使用p作為字串之前,必須把p指向字串數組。一種可能是把p指向已經存在的字串變數:
char str[STR_LEN + 1], *p;
p = str;
現在p指向了str的第一個字元,所以可以把p作為字串使用了。
字串的讀寫
3.1 用 printf 函數和 puts 函數寫字串
%s 允許 printf 函數寫字串。如:
char str[] = "Are we having fun yet?";
printf("Value of str: %s/n", str);
如果只顯示字串的一部分,可以用 %.ps。這裡的 p 是要顯示的字元數量。語句
printf("%.6s/n", str);會顯示出
Are we
C函數庫還提供puts函數。
puts(str);
3.2 用 scanf 函數和 gets 函數讀字串
在 scanf 函數調用中,不需要在 str 前添加運算子 &。因為 str 是數組名,編譯器會自動把它當作指標來處理。調用時,scanf 函數會跳過空白字元,然後讀入字元,並且把讀入的字元儲存到 str 中,知道遇到空白字元為止。scanf 函數始終會在字串末尾儲存一個Null 字元。用 scanf 函數讀入字串永遠不會包含空白字元。因此,scanf 函數通常不會讀入一整行輸入。分行符號會使 scanf 函數停止讀入,空格符或定位字元也會產生同樣的效果。可以參考下面的例子:
#include <stdio.h>
#define STR_LEN 80
int main()
{
char str[STR_LEN + 1];
printf("input a string:");
scanf("%s", str);
printf("String inputed is:%s/n", str);
return 0;
}
運行結果如下:
Input a string:this is a string
String is:this
為了每次讀入一整行輸入,可以使用 gets 函數。類似於 scanf 函數,gets 函數把讀入的字元放到數組中,然後儲存一個Null 字元。然而,在其他方面 gets 函數有些不同於 scanf 函數:
(1) gets 函數不會在開始讀字串之前跳過空白字元( scanf 函數會跳過)。
(2) gets 函數會持續讀入直到找到分行符號才停止(scanf 函數會在任意空白字元處停止)。
此外,gets 函數會忽略掉分行符號,而不會把它儲存到數組中,用Null 字元代替分行符號。
3.3 逐個字元讀字串
因為 scanf 函數和 gets 函數都有風險且不夠靈活,C 程式員經常會編寫自己的輸入函數。通過每次一個字元的方式來讀入字串。下面是自己編寫的讀取字串的函數 read_line():
int read_line(char str[], int n)
{
char ch;
int i = 0;
while((ch = getchar()) != '/n')
if(i < n)
str[i++] = ch;
str[i] = '/0'; /* terminates string */
return i; /* number of characters stored */
}
返回之前,read_line 函數在字串的末尾放置了一個Null 字元。就像 scanf 函數和 gets 函數一樣,標準函數會自動在輸入字串的末尾放置一個Null 字元串。然而,如果自己寫輸入函數,必須要考慮到這一點。