看板 C_and_CPP 關於我們 聯絡資訊
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
EdisonX: #1IOXeMHX (C_and_CPP) 要修的話,這篇可以當後半段 ? 05/14 22:12
請問一下,若是我不斷修改字串函數,像這樣: 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