作者wtchen (沒有存在感的人)
看板C_and_CPP
標題十三誡增修--04:你不可以試圖用 char* 去更改一個"字串常數"
時間Sat May 14 16:45:03 2016
04.
你不可以試圖用 char* 去更改一個"字串常數"
試圖去更改字串常數(string literal)的結果會是undefined behavior。
錯誤例子:
char* pc = "john"; /* pc 現在指著一個字串常數 */
*pc = 'J'; /* undefined behaviour,結果無法預測*/
pc = "jane"; /* 合法,pc指到在別的位址的另一個字串常數*/
/* 但是"john"這個字串還是存在原來的地方不會消失*/
因為char* pc = "john"這個動作會新增一個內含元素為"john\0"的static char[5],
然後pc會指向這個static char的位址(通常是唯讀)。
若是試圖存取這個static char[],Standard並沒有定義結果為何。
pc = "jane" 這個動作會把 pc 指到另一個沒在用的位址然後新增一個
內含元素為"jane\0"的static char[5]。
可是之前那個字串 "john\n" 還是留在原地沒有消失。
通常編譯器的作法是把字串常數放在一塊read only(.rdata)的區域內,
此區域大小是有限的,所以如果你重複把pc指給不同的字串常數,
是有可能會出問題的。
正確例子:
char pc[] = "john"; /* pc 現在是個合法的陣列,裡面住著字串 john */
/* 也就是 pc[0]='j', pc[1]='o', pc[2]='h',
pc[3]='n', pc[4]='\0' */
*pc = 'J';
pc[2] = 'H';
說明:字串常數的內容應該要是"唯讀"的。您有使用權,但是沒有更改的權利。
若您希望使用可以更改的字串,那您應該將其放在合法空間
錯誤例子:
char *s1 = "Hello, ";
char *s2 = "world!";
/* strcat() 不會另行配置空間,只會將資料附加到 s1 所指唯讀字串的後面,
造成寫入到程式無權碰觸的記憶體空間 */
strcat(s1, s2);
正確例子(2):
/* s1 宣告成陣列,並保留足夠空間存放後續要附加的內容 */
char s1[20] = "Hello, ";
char *s2 = "world!";
/* 因為 strcat() 的返回值等於第一個參數值,所以 s3 就不需要了 */
strcat(s1, s2);
C++對於字串常數的嚴格定義為const char* 或 const char[]。
但是由於要相容C,char* 也是允許的寫法(不建議就是)。
不過,在C++試圖更改字串常數(要先const_cast)一樣是undefined behavior。
const char* pc = "Hello";
char* p = const_cast<char*>(pc);
p[0] = 'M'; // undefined behaviour
備註:
由於不加const容易造成混淆,
建議不管是C還是C++一律用 const char* 定義字串常數。
補充資料:
http://en.cppreference.com/w/c/language/string_literal
http://en.cppreference.com/w/cpp/language/string_literal
字串函數相關:
#1IOXeMHX
undefined behavior : 精華區 z -> 3 -> 3 -> 23
--
個人網頁:
http://gnitnaw.github.io/
以後在C_and_CPP或LinuxDev發表的文章都會放一份在這邊。
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 86.209.153.222
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1463215507.A.037.html
※ 編輯: wtchen (86.209.153.222), 05/14/2016 18:00:45
請問一下,若是我不斷修改字串函數,像這樣:
char *a = "aaaa";
a = "bbbb";
a = "cccc";
....
連續這樣很多次的話會不會使得read only區被唯讀字串弄爆?
推 Rollnmeow: 有錯字 第一個undefined behavior打成了behavoir 05/14 22:34
已修正,謝謝
→ Caesar08: 需要補充undefined behavior是甚麼意思嗎? 05/14 22:46
這個FAQ有,我可以加進補充資料。
※ 編輯: wtchen (86.209.153.222), 05/14/2016 23:28:15
※ 編輯: wtchen (86.209.153.222), 05/14/2016 23:32:40
推 EdisonX: 那就得看 .rdata 有多大了, 不過避開弄爆的方法很多 , 但 05/14 23:35
→ EdisonX: 用這特性也可以做一些奇淫怪技。 05/14 23:35
→ wtchen: 可以教一下這邪惡的技巧嗎? 05/14 23:40
→ wtchen: 居然還有這招.... 05/14 23:48
根據EdisonX提供的資料改了一下...
※ 編輯: wtchen (86.209.153.222), 05/14/2016 23:58:04