#include <iostream>
#include<string.h>
using namespace std;
int main()
{
char *str="AAA";
str[0]='B';
cout << str << endl;
return 0;
}
這段代碼的問題在哪兒呢?乍一看我沒看出問題,通過學習帖子的回覆,還是小有感觸的。
其實,這就是char *a = "hello" 與 char a[] = "hello"區別。正如一個回覆中所說,第一個把一個常量字符串存入靜態存儲區,並用p指針指向其首位。後續程序可以通過該指針讀取字符串內容,但不能改寫;第二個把字符串複製到棧空間裏,並將此位置命名爲 char p[]。後續程序可以通過字符數組p讀取、更改該字符串,但不能改寫p自身。
因此,當把程序改爲:
#include <iostream>
#include<string.h>
using namespace std;
int main()
{
char str[]="AAA";
str[0]='B';
cout << str << endl;
return 0;
}
就可以得到想要的輸出了。
看到這裏,我突然想起了以前學過的常量指針與指向常量的指針的概念,遂找出來重新理了一遍,總結如下:
1. 指向常量的指針這樣定義:
const char *pc;
或者
char const *pc;
char *a = "hello"
就屬於這種情況,因爲"hello"屬於靜態存儲區中的常量字符串。其實,在C++中更標準的寫法是const char *a = "hello",前述寫法是屬於兼容C的寫法。在這裏,通過指針a可以讀取字符串,但是不能改寫。對於指針a本身,可以對它重新進行賦值,也就是可以改變它的指向。
2. 常量指針。顧名思義,就是指針本身是常量,不可更改。如下定義:
char * const pc;
可以讀取和改寫pc指向的內容,但是不能改變pc的指向。其實,char a[] = "hello"屬於這一範疇。因爲常量指針除了用"
* const "定義外,還有變量的地址、數組名、結構數組名、對象數組名、函數名等。在這裏a就屬於數組名,因此它也是常量指針。所以,對指針a進行重定向的操作是非法的,編譯器會提示“表達式必須是可以修改的左值”。3. 指向常量的常量指針。如下定義:
const char* const pc;
這時候,pc指向的內容和pc本身都不能更改。比如
char *const pc = "hello";
中pc其實就屬於指向常量的常量指針。因爲除了顯式的const常量指針說明以外,靜態存儲區的"hello"隱式的告訴了pc指向常量。所以,pc[3] = 'a' 和 pc = 'world' 的操作都是非法的。最後,我們再來比較一下char pc[] = "hello" 與 char* const pc = "hello"的區別。請看以下兩段代碼:
#include <iostream>
#include<string.h>
using namespace std;
int main()
{
char pc[] = "hello";
pc[0]='B';
cout << pc << endl;
return 0;
}
和
#include <iostream>
#include<string.h>
using namespace std;
int main()
{
char* const pc = "hello";
pc[0]='B';
cout << pc << endl;
return 0;
}
第一段代碼可以正常打印出”Bello“,而第二段代碼編譯會有內存訪問衝突。這說明,char pc[] = "hello" 僅僅是常量指針,它將字符串複製到棧空間中,因此pc指向的內容是可更改的;而char* const pc = "hello" 是指向常量的常量指針,"hello"保存在靜態存儲區中,因此pc指向的內容是不能更改的。第二段代碼更改如下,將pc指向棧區,即可正常打印:
#include <iostream>
#include<string.h>
using namespace std;
int main()
{
char str[] = "hello";
char* const pc = str;
pc[0]='B';
cout << pc << endl;
return 0;
}