getchar
與 putchar
緩沖區
getchar
putchar
有下面的語句段:
while ((s = getchar()) != '\n'){
putchar(s);
putchar("\n");
}
這個while循環是怎麼工作的呢?
首先
getchar
在資料緩沖區裡讀資料進來,這個讀取資料是一個個讀的,循環依次判斷讀進來的字元是不是為換行符,是的話就跳出循環,不是就列印出該字元。其實在
getchar
讀取字元之前,通過鍵盤輸入的字元已經通過
stdin
流全部存入了緩沖區中,
getchar
隻在使用者輸入了換行符時才會去讀取緩沖區裡的資料。
C字元串數組與指針
在C中字元串實質上是最後一個元素為空字元的
char
數組,而我們知道數組與指針是有關聯的。聲明一個字元串有以下兩種方式:
char *string1 = "foo";
//通過指針聲明,string1其實是指向"foo"這個字元串第一個char字元'f'的位址
char string2[4] = "foo";
//通過char數組生明字元串,string2是一個數組
這兩種聲明方式有一點不同,就是數組名
string2
是個常量,而指針名
string1
是一個變量。數組形式的
string[4]
是計算機記憶體中配置設定的用于存儲四個字元
'f','o','o','o','\0'
,
string2
既是數組名,也是首個字元
string[0]
的位址,
string2
的值不能更改,可以通過
string2+1
來通路第二個字元
'o'
,但不能這樣用:
++string2
,C中規定
++
自增符号隻能用于變量,
string2
這裡顯然是個常量,它的值是該數組首個元素的位址。對于
string1
形式,C Primer Plus中這樣說:
指針形式(也就是我們這裡的)會在靜态存儲區為字元串預留4個元素的空間(最後一個存儲空間用來放
string1
)。一旦程式開始執行,還要為指針變量
'\0'
另外預留一個存儲位置,以在該指針變量中存儲字元串位址。這個變量初始時指向字元串的第一個字元,但是它的值是可以改變的。是以,可以對它使用增量運算符(例
string1
将指向第二個字元
++string1
)。總之數組形式的字元串初始化是從靜态存儲區把一個字元串指派給數組,而指針初始化隻是複制字元串的位址。
'o'
這裡我們就很清楚了兩種形式的不同。一般推薦用數組來定義字元串,因為用指針形式定義字元串時,若是修改了指針指向的字元串某個字元可能會導緻所有使用該位址字元的值發生變化,這和編譯器的實作方式有關。
在通路字元串,例如
puts
時,不管是數組形式還是指針形式,會一直列印字元知道碰到空字元才結束。
字元串數組
考慮到一下形式定義:
char (*list)[2] ={"a","b"};//1
const char *multiple_strings[3] = {//2
"I love you",
"You are beautiful",
"You makes me happy"};
你會發現1處會報警告:
Incompatible pointer types initializing 'char (*)[2]' with an expression of type 'char [2]'; take the address with &
因為此處聲明的list是一個指向由兩個字元構成的元素的元素的位址,而
"a"
是一個字元串,并不是個字元,是以我們得把
"a"
改成
'a'
。其實這樣也是錯誤的,我們聲明list是個指針,指向一個二維數組的第一個元素,那麼就不要用一整個二維數組類型去初始化它,最好這樣:
char (*list)[2] = {'a','b'};
char test[2][2] = {{'a','b'},{'b','c'}};
list = test;
這樣不會有任何警告。
再看注釋2處什麼意思呢?這其實定義了一個字元串數組,但是這是一個一位數組,而不是二維數組(我們知道二維數組指針形式聲明并不是這樣的),數組裡面的每個元素都是一個char類型元素的位址,每個元素都是對應字元串第一個字元的位址,也就有下列關系成立:
*multiple_strings[0] == 'I'; *multiple_strings == 'Y'
。對指針進行數組式操作在這裡也是成立的:
multiple_strings[1][2]
就對應的就是第二個字元串
You
中的
'u'
。
關于這部分的詳細知識可以參見C Primer Plus的第十一章關于字元串數組的部分。
總結: