字串常量初始化指標
今天寫個小文說一說字串地址和字串常量。
在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