天天看點

字元數組與字元指針的差别與聯系

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] = {'a','b','c'};又依據上面的總結1,是以char

str[] = "abc";的終于結果是 char str[4] = {'a','b','c','\0'};

 做一下擴充。假設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的值動态*/

(5)字元指針變量的值能夠改變,字元數組名是一個常量,不能改變。

比如。有簡單程式:

#include <stdio.h>

int main()

{

      char *s = "china man";

      s+= 6;

      printf("%s\n",s);

      getchar();

      return 0;

}

執行結果:man