1. 程式人生 > >字串常量初始化指標

字串常量初始化指標

今天寫個小文說一說字串地址和字串常量。

在C/C++中,一個字串常量表示的是該字串第一個元素的地址,就跟char指標名,char陣列名錶示的是字串第一個元素的地址一樣。

想要列印一個地址,用一個簡單的 cout << 地址; 語句就可以搞定;

但是下面這兩條語句將列印整個字串

char a[20] = "1234";
cout << a << endl;

char *p = a;
cout << p << endl;

這也是字元陣列 與其他陣列不同的一個地方,那麼該如何得到該字串的地址呢?

下面有兩種方法可供參考

cout << (int*)a << endl;
cout << &a << endl;

這兩種方法都可以正確打印出“字串的地址”,但是有細微區別之處

在字元陣列a中,a表示第一個字元的地址,a+1表示第二個字元的地址;

在第一條列印地址的語句中,(int*)a只是起到了一個強制型別轉換的作用,換句話說,a表示第一個字元的地址,但是cout <<a;輸出的是整個字串,這是因為這個地址是char*型別的,cout識別到char*型別的地址將會自動列印從該地址指向的空間開始直到遇到'\0'的字串內容,所以這裡我們只需要進行一個強制型別轉換(這裡舉例強制轉換為int*,可以轉換為其他型別的指標,只要不是char*,哪怕是double*也可以正確列印地址)。所以如果想要第二個字元的地址呢,cout << (int*)(a+1);就可以啦

第二條列印地址的語句中,直接使用了&a;這裡需要強調的是,不論任何陣列,陣列名錶示的都是第一個元素的地址,&陣列名錶示的才是該陣列的地址,雖然二者打印出來是同一地址,但是如果進行指標運算則天差地別,看一下下面這段程式碼和效果

int a[10];
cout << "a  is: " << a << " a+1  is: " << a+1 << endl;
cout << "&a is: " << &a << " &a+1  is: " << &a+1 << endl; 

有圖有真相,a+1只是向後移動了4個位元組,而&a+1直接向後移動了40個位元組,所以&陣列名錶示的才是整個陣列的地址。所以同理用&字元陣列名也可以打印出字串地址。

 下面說一說字串常量,首先字串儲存在靜態儲存區,其次,不可修改。

於是就產生了下面幾條語句

char a[20] = "1234";
char * p = "1234";
const char * p = "1234";

第一條語句不用說,很常用了,正確,那麼二三條語句哪個對哪個錯呢。

剛開始我還覺得加不加const無所謂,反正都是錯的,後來細思極恐,果然還是知識貧窮限制了想象力;

一開始我認為後面兩句錯的原因是因為 沒見過,看著像是給*p賦了個"1234",可又不是,這是個什麼東西,總之就是看著怪怪的;

所以這裡就牽扯到開頭提到的一個知識點了;在C/C++中,一個字串常量表示的是該字串第一個元素的地址,就跟char指標名,char陣列名錶示的是字串第一個元素的地址一樣

所以這回就明白了,看著是"1234",其實本質上是"1234"第一個字元的地址,那麼將 char*型的指標p指向“1234”就沒有問題啦,地址對地址嘛,但是編譯後出錯了,理由是"1234"是一個常量,所以加上了const限定。

關於這裡為什麼要加const限定才正確,如果不加的話型別也是匹配的,為什麼會報錯呢,所以這裡需要再強調一下,"1234"是字串常量,常量不允許被修改,如果char * p = "1234";編譯成功,那就意味著"1234"有可能被修改,而這是不被允許的,所以必須乖乖聽話加上const限定符讓系統安心才是嘛。

咦?常量不允許被修改,要加const限定符才可以,那為什麼我們一直用的第一條語句是正確的而且從來沒有報錯過呢?

這就要說說第一條語句和第三條語句的區別啦,"1234"是字串常量,常量儲存在靜態儲存區,有地址

第三條語句是讓一個常量指標直接指向靜態儲存區的"1234"的地址,因為是直接指向本尊地址,所以要加上const限定符

而第一條語句則是將靜態儲存區的"1234"的副本拿出來複製到字元陣列a中,所以這樣初始化可以在後面隨意更改副本"1234",這樣並不會影響到真正的"1234";

是真地址假地址cout一下就知道了

1 char a[20] = "1234";
2 const char * p = "1234";
3 cout << &a << endl; // 獲取字元陣列a的地址
4 cout << &"1234" << endl; // 獲取 "1234"在靜態儲存區的地址
5 
6 //再來驗證一下字串常量為該字串第一個元素的地址
7 cout << *"1234" << endl;
8 cout << *("1234"+1) << endl;

 

 

OK,明顯副本”1234“與本尊”1234“的地址不同,而且差了很多很多地址位,肯定是跨記憶體區了的,最後面兩行想要的結論也得到了驗證,實踐出真知,真是不枉我熬夜到12點。

&n