C語言學習筆記(三)——字符串

目錄

1 字符串的表示

1) 字符串字面量(字符串常量)        2)字符串數組和初始化

3)數組和指針                                     4)字符串數組

2 字符串的輸入輸出

2.1 輸入                      2.2 輸出                               2.3 自定義輸入輸出

3 字符串函數

4 補充

4.1 命令行參數           4.2 轉換爲數字


1 字符串的表示

字符串是以空字符(\0)結尾的char類型數組。表示字符串的幾種方式如下:

1) 字符串字面量(字符串常量)

用雙引號括起來的內容稱爲字符串字面量(string literal),也叫作字符串常量(string  constant)。雙引號中的字符和編譯器自動加入末尾的\0字符,都作爲字符串儲存在內存中,"I love money."

從ANSI  C標準起,如果字符串字面量之間沒有間隔,或者用空白字符分隔,C會將其視爲串聯起來的字符串字面量。

char greeting[50] = "Hello, and"" how are"" you"" today!";
與下面的代碼等價:
char greeting[50] = "Hello, and how are you today!";

**注意**

如果要在字符串內部使用雙引號,必須在雙引號前面加上一個反斜槓(\) : "my friend \" Book\" !"

字符串常量屬於靜態存儲類別(static storage class),如果在函數中使用字符串常量,該字符串只會被儲存一次。用雙引號括起來的內容被視爲指向該字符串儲存位置的指針。

2)字符串數組和初始化

定義字符串數組時,必須讓編譯器知道需要多少空間。

  • 方法一:用足夠空間的數組儲存字符串

const char m1[40] = "Limit yourself to one line's worth."; #const表明不會更改這個字符串。

注意:const char m[10] = {‘L’,'i','m','i','t','\0'}; 這種定義方式最後沒有這個空字符,這就不是一個字符串,而是一個
字符數組。

在指定數組大小時,要確保數組的元素個數至少比字符串長度多1(爲了容納空字符)。所有未被使用的元素都被自動初始化爲0。

  •  方法二:讓編譯器確定數組的大小

const char m2[] = "If you can't think of anything, fake it.";

讓編譯器計算數組的大小隻能用在初始化數組時。如果創建一個稍後再填充的數組,就必須在聲明時指定大小。

注意:

字符數組名和其他數組名一樣,是該數組首元素的地址。

char car[10] = "Tata"; ——>car == &car[0]、*car == 'T'、*(car+1) == car[1] == 'a'。

  • 方法三:使用指針表示法創建字符串

const char * pt1 = "Something is pointing at me.";

該聲明和下面的聲明幾乎相同:
const char ar1[] = "Something is pointing at me.";

3)數組和指針

數組形式和指針形式的不同?

數組形式(ar1[])在計算機的內存中分配爲一個內含29個元素的數組(每個元素對應一個字符,還加上一個末尾的空字符'\0')。字符串都作爲可執行文件的一部分儲存在數據段中。程序在開始運行時纔會爲該數組分配內存。此時,纔將字符串拷貝到數組中。注意,此時字符串有兩個副本。一個是在靜態內存中的字符串字面量,另一個是儲存在ar1數組中的字符串。此後,編譯器便把數組名ar1識別爲該數組首元素地址(&ar1[0])的別名。

注意:ar1是地址常量。可以進行類似ar1+1這樣的操作,標識數組的下一個元素。但是不允許進行++ar1(只能用於變量名前)這樣的操作。

指針形式(*pt1)也使得編譯器爲字符串在靜態存儲區預留29個元素的空間。一旦開始執行程序,它會爲指針變量pt1留出一個儲存位置,並把字符串的地址儲存在指針變量中。該變量最初指向該字符串的首字符,但是它的值可以改變。

總結:

char heart[] = "I love Tillie!";
const char *head = "I love Millie!";

1)數組名heart是常量,而指針名head是變量。
2)兩者都可以使用數組表示法
3)兩者都能進行指針加法操作
4)只有指針表示法可以進行遞增操作
5)讓head和heart統一
head = heart;  /* head現在指向數組heart */
heart = head;  /* 非法構造,不能這樣寫 */

4)字符串數組

const char *mytalents[3] = {"Adding numbers swiftly","Multiplying accurately", "Stashing data"};

char yourtalents[3[40] = {"Walking in a straight line","Sleeping", "Watching television"};

mytalents數組是一個內含3個指針的數組,yourtalents是一個內含3個數組的數組,每個數組內含40個char類型的值。

mytalents中的指針指向初始化時所用的字符串字面量的位置,這些字符串字面量被儲存在靜態內存中;而 yourtalents 中的數組則儲存着字符串字面量的副本,所以每個字符串都被儲存了兩次。此外,爲字符串數組分配內存的使用率較低。yourtalents 中的每個元素的大小必須相同,而且必須是能儲存最長字符串的大小。

如果要用數組表示一系列待顯示的字符串,請使用指針數組,因爲它比二維字符數組的效率高。如果要改變字符串或爲字符串輸入預留空間,不要使用指向字符串字面量的指針

2 字符串的輸入輸出

2.1 輸入

C 庫提供了許多讀取字符串的函數:scanf()、gets()和fgets()。

1)gets()函數

在讀取字符串時,scanf()和轉換說明%s只能讀取一個單詞。gets()函數可以讀取整行輸入,直至遇到換行符,然後丟棄換行符,儲存其餘字符,並在這些字符的末尾添加一個空字符使其成爲一個 C 字符串。

 gets()唯一的參數是 words,它無法檢查數組是否裝得下輸入行。gets()函數只知道數組的開始處,並不知道數組中有多少個元
素。如果輸入的字符串過長,會導致緩衝區溢出

2)fgets()函數

用fgets()來代替gets(),gets_s()函數也可代替gets()。

fgets()函數通過第2個參數限制讀入的字符數來解決溢出的問題。第2個參數指明瞭讀入字符的最大數量。讀到一個換行符,會把它儲存在字符串中。第3 個參數指明要讀入的文件。如果讀入從鍵盤輸入的數據,則以stdin(標準輸入)作爲參數。

fputs()函數返回指向 char的指針。如果函數讀到文件結尾,它將返回一個特殊的指針:空指針(null pointer)。

注意:系統使用緩衝的I/O。這意味着用戶在按下Return鍵之前,輸入都被儲存在臨時存儲區(即,緩衝區)中。按下Return鍵就在輸入中增加了一個換行符,並把整行輸入發送給fgets()。對於輸出,fputs()把字符發送給另一個緩衝區,當發送換行符時,緩衝區中的內容被髮送至屏幕上。

注意:空字符是整數類型,而空指針是指針類型。它們都可以用數值0來表示。空字符是一個字符,佔1字節;而空指針是一個地址,通常佔4字節。

3)gets_s()函數

用一個參數限制讀入的字符數。gets_s()只從標準輸入中讀取數據,所以不需要第3個參數。如果gets_s()讀到換行符,會丟棄它而不是儲存它。

如果gets_s()讀到最大字符數都沒有讀到換行符,會執行以下幾步。首先把目標數組中的首字符設置爲空字符,讀取並丟棄隨後的輸入直至讀到換行符或文件結尾,然後返回空指針。接着,調用依賴實現的“處理函數”(或你選擇的其他函數),可能會中止或退出程序。

4)scanf()函數

scanf()函數有兩種方法確定輸入結束。無論哪種方法,都從第1個非空白字符作爲字符串的開始。如果使用%s轉換說明,以下一個空白字符(空行、空格、製表符或換行符)作爲字符串的結束(字符串不包括空白字符)。如果指定了字段寬度,如%10s,那麼scanf()將讀取10 個字符或讀到第1個空白字符停止(先滿足的條件即是結束輸入的條件)。

2.2 輸出

1)puts()函數

只需把字符串的地址作爲參數傳遞給它即可。puts()在顯示字符串時會自動在其末尾添加一個換行符。在遇到空字符時就停止輸出,所以必須確保有空字符。

2)fputs()函數

fputs()函數是puts()針對文件定製的版本。2 個參數指明要寫入數據的文件。如果要打印在顯示器上,可以用定義在stdio.h中的stdout(標準輸出)作爲該參數。fputs()不會在輸出的末尾添加換行符。

3)printf()函數

和puts()一樣,printf()也把字符串的地址作爲參數。它可以格式化不同的數據類型。

2.3 自定義輸入輸出

完全可以在getchar()和putchar()的基礎上自定義所需的函數。

void put1(const char * string)/* 不會改變字符串 */
{
while (*string != '\0')
putchar(*string++);
}

3 字符串函數

C庫提供了多個處理字符串的函數,ANSI  C把這些函數的原型放在string.h頭文件中。其中最常用的函數有  strlen()、strcat()、strcmp()、strncmp()、strcpy()和 strncpy()。

size_t strlen(const char * s); 該函數返回s字符串中的字符數,不包括末尾的空字符。
char *strcat(char * restrict s1, const char * restrict s2); 該函數把s2指向的字符串拷貝至s1指向的字符串末尾。s2字符串的第1
個字符將覆蓋s1字符串末尾的空字符。該函數返回s1。
char *strncat(char * restrict s1, const char * restrict s2, size_t n); 該函數把s2字符串中的n個字符拷貝至s1字符串末尾。s2字符串的第1個
字符將覆蓋s1字符串末尾的空字符。不會拷貝s2字符串中空字符和其後的字
符,並在拷貝字符的末尾添加一個空字符。該函數返回s1。
int strcmp(const char * s1, const char * s2); 如果s1字符串在機器排序序列中位於s2字符串的後面,該函數返回一個
正數;如果兩個字符串相等,則返回0;如果s1字符串在機器排序序列中位
於s2字符串的前面,則返回一個負數。
int strncmp(const char * s1, const char * s2, size_t n); 該函數的作用和strcmp()類似,不同的是,該函數在比較n個字符後或遇
到第1個空字符時停止比較。
char *strcpy(char * restrict s1, const char * restrict s2); 該函數把s2指向的字符串(包括空字符)拷貝至s1指向的位置,返回值s1
char *strncpy(char * restrict s1, const char * restrict s2, size_t n); 該函數把s2指向的字符串拷貝至s1指向的位置,拷貝的字符數不超過n,其返回值是s1。該函數不會拷貝空字符後面的字符,如果源字符串的字符少於n個,目標字符串就以拷貝的空字符結尾;如果源字符串有n個或超過n個字符,就不拷貝空字符。
sprintf() 把數據寫入字符串,而不是打印在顯示器上。
char *strchr(const char * s, int c); 如果s字符串中包含c字符,該函數返回指向s字符串首位置的指針(末尾的空字符也是字符串的一部分,所以在查找範圍內);如果在字符串s中未找到c字符,該函數則返回空指針。

ctype.h系列與字符相關的函數。雖然這些函數不能處理整個字符串,但是可以處理字符串中的字符。

4 補充

4.1 命令行參數

命令行(command line)是在命令行環境中,用戶爲運行程序輸入命令的行。

在UNIX環境中運行該程序的命令行是:
$ fuss
或者在Windows命令提示模式下是:
C> fuss

命令行參數(command-line argument)是同一行的附加項。$ fuss -r Ginger,一個C程序可以讀取並使用這些附加項。

C編譯器允許main()沒有參數或者有兩個參數。main()有兩個參數時,第1個參數是命令行中的字符串數量。過去,這個int類型的參數被稱爲argc。系統用空格表示一個字符串的結束和下一個字符串的開始。把命令行字符串儲存在內存中,並把每個字符串的地址儲存在指針數組中。而該數組的地址則被儲存在 main()的第 2 個參數中。

4.2 轉換爲數字

數字既能以字符串形式儲存,也能以數值形式儲存。把數字儲存爲字符串就是儲存數字字符。

C要求用數值形式進行數值運算。但是在屏幕上顯示數字則要求字符串形式,因爲屏幕顯示的是字符。printf()和  sprintf()函數,通過%d  和其他轉換說明,把數字從數值形式轉換爲字符串形式,scanf()可以把輸入字符串轉換爲數值形式。C 還有一些函數專門用於把字符串形式轉換成數值形式。

需要整數,可以使用atoi()函數,atof()函數把字符串轉換成 double 類型的值, atol()函數把字符串轉換成long類型的值。

更智能的函數:strtol()把字符串轉換成long類型的值,strtoul()把字符串轉換成unsigned long類型的值,strtod()把字符串轉換成
double類型的值。這些函數的智能之處在於識別和報告字符串中的首字符是否是數字。而且,strtol()和strtoul()還可以指定數字的進制。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章