1.字元指標可以指向乙個字串。
我們可以用字串常量對字元指標進行初始化。例如,有說明語句:
char *str = "this is a string.";
是對字元指標進行初始化。此時,字元指標指向的是乙個字串常量的首位址,即指向字串的首位址。
這裡要注意字元指標與字元陣列之間的區別。例如,有說明語句:
char string[ ]="this is a string.";
此時,string是字元陣列,它存放了乙個字串。
字元指標str與字元陣列string的區別是:str是乙個變數,可以改變str使它指向不同的字串,但不能改變str所指的字串常量。string是乙個陣列,可以改變陣列中儲存的內容。
2.例項:
char *str, *str1="this is another string.";
char string[100]="this is a string.";
則在程式中,可以使用如下語句:
str++; /* 指標str加1 */
str = "this is a new string."; /* 使指標指向新的字串常量 */
str = str1; /* 改變指標str的指向 */
strcpy( string, "this is a new string.") /* 改變字串的的內容 */
strcat( string, str) /* 進行串連線操作 */
在程式中,不能進行如下操作:
string++; /* 不能對陣列名進行++運算 */
string = "this is a new string."; /* 錯誤的串操作 */
string = str1; /* 對陣列名不能進行賦值 */
strcat(str, "this is a new string.") /* 不能在str的後面進行串連線 */
strcpy(str, string) /* 不能向str進行串複製 */
3.其它說明:
1) 以字串形式出現的,編譯器都會為該字串自動新增乙個0作為結束符,如在**中寫:"abc",那麼編譯器幫你儲存的是"abc/0"
2) "abc"是常量嗎?答案是有時是,有時不是。
不是常量的情況:"abc"作為字元陣列初始值的時候就不是,如
char str = "abc";
因為定義的是乙個字元陣列,所以就相當於定義了一些空間來存放"abc",而又因為字元陣列就是把字元乙個乙個地存放的,所以編譯器把這個語句解析為 char str[3] = ;又根據上面的總結1,所以char str = "abc";的最終結果是 char str[4] = ;
做一下擴充套件,如果char str = "abc";是在函式內部寫的話,那麼這裡的"abc\0"因為不是常量,所以
應該被放在棧上。
是常量的情況:把"abc"賦給乙個字元指標變數時,如
char* ptr = "abc";
因為定義的是乙個普通指標,並沒有定義空間來存放"abc",所以編譯器得幫我們找地方來放"abc",顯然,這裡的"abc"當成常量並
把它放到程式的常量區是編譯器最合適的選擇
。所以儘管ptr的型別不是const char*,並且ptr[0] = 'x';也能編譯通過,但是執行ptr[0] = 'x';就會發生執行時異常,因為這個語句試圖去修改程式常量區中的東西。
記得哪本書中曾經說過char* ptr = "abc";這種寫法原來在c++標準中是不允許的,但是因為這種寫法在c中實在是太多了,為了相容c,不允許也得允許。雖然允許,
但是建議的寫法應該是const char* ptr = "abc";這樣如果後面寫ptr[0] = 'x'的話編譯器就不會讓它編譯通過,也就避免了上面說的執行時異常。
又擴充套件一下,如果char* ptr = "abc";寫在函式體內,那麼雖然這裡的"abc/0"被
放在常量區中,但是ptr本身只是乙個普通的指標變數,所以ptr是被放在棧上的, 只不過是它所指向的東西被放在常量區罷了。
3) 陣列的型別是由該陣列所存放的東西的型別以及陣列本身的大小決定的。如char s1[3]和char s2[4],
s1的型別就是char[3],s2的型別就是char[4],
也就是說儘管s1和s2都是字元陣列,但兩者的型別卻是不同的。
4) 字串常量的型別可以理解為相應字元常量陣列的型別,
如"abcdef"的型別就可以看成是const char[7]
5) sizeof是用來求型別的位元組數的。如int a;那麼無論sizeof(int)或者是sizeof(a)都是等於4,因為sizeof(a)其實就是sizeof(type of a)
6) 對於函式引數列表中的以陣列型別書寫的形式引數,編譯器把其解釋為普通的指標型別,如對於void func(char sa[100],int ia[20],char *p)
則sa的型別為char*,ia的型別為int*,p的型別為char*
7) 根據上面的總結,來實戰一下:
對於char str = "abcdef";就有sizeof(str) == 7,因為str的型別是char[7],
也有sizeof("abcdef") == 7,因為"abcdef"的型別是const char[7]。
對於char *ptr = "abcdef";就有sizeof(ptr) == 4,因為ptr的型別是char*。
對於char str2[10] = "abcdef";就有sizeof(str2) == 10,因為str2的型別是char[10]。
對於void func(char sa[100],int ia[20],char *p);
就有sizeof(sa) == sizeof(ia) == sizeof(p) == 4,
因為sa的型別是char*,ia的型別是int*,p的型別是char*。
4.區別:
(1)字元陣列由若干個元素組成,每個元素中存放字串的乙個字元,而字元指標變數中存放的是字串的首位址。
(2)初始化方式不同。對字元陣列初始化要用static儲存類別,在編譯時進行。而對字元指標變數初始化不必加static,在實際執行時進行。
(3)賦值方式不同。對字元陣列不能整體賦值,只能轉化成份量,對單個元素進行。而字元指標變數賦值可整體進行。
例如:
char s[10];
s= /"c++/";/*錯,s是常量,怎能被賦值*/
(4)在定義乙個字元陣列時,編譯時即已分配記憶體單元,
有確定的位址。而定義乙個字元指標變數時,給指標變數分配記憶體單元,但該指標變數具體指向哪個字串,並不知道,即
指標變數存放的位址不確定
。例如:
char a[10];
char *p;/*野指標*/
scanf(/"%s/",s);/*正確*/
scanf(/"%s/",p);/*非常危險,p的值動態*/
乙個錯誤的例子,
如下:char *name;
scanf("%s",name);
printf("%s",name);
有的編譯器雖然也能通過,但這是錯誤的。
解決這個問題有兩種方法:
用陣列的方法或給字元針針分配記憶體空間的方法:
陣列的方法:
char name[20];
scanf("%s",name);
printf("%s",name);
給字元針針分配記憶體空間的辦法:
char *name;
name=(char*)malloc(50);
//此時name已經指向乙個剛剛分配的位址空間
scanf("%s",name);
printf("%s",name);
但是對指標變數直接賦值是可以的。
(5)字元指標變數的值可以改變,字元陣列名是乙個常量,不能改變。例如,有簡單程式:
main()
執行結果:man
字元陣列與字元指標
10.4 指標與字串 10.4.1 字元陣列與字元指標 在第八章中我們已經詳細討論了字元陣列與字串,字元指標也可以指向乙個字串。我們可以用字串常量對字元指標進行初始化。例如,有說明語句 char str this is a string.是對字元指標進行初始化。此時,字元指標指向的是乙個字串常量的首...
字元指標與字元陣列
1.字元指標可以指向乙個字串。我們可以用字串常量對字元指標進行初始化。例如,有說明語句 char str this is a string.是對字元指標進行初始化。此時,字元指標指向的是乙個字串常量的首位址,即指向字串的首位址。這裡要注意字元指標與字元陣列之間的區別。例如,有說明語句 char st...
字元陣列與字元指標
節選了一些有價值和易錯的部分。char str this is a string.char string this is a string.字元指標str與字元陣列string的區別是 str是乙個變數,可以改變str使它指向不同的字串 但不能改變str所指的字串常量 string是乙個陣列,可以改...