問題來源:
在寫二叉樹序列化與反序列化時發現序列化函式為char* Serialize1(TreeNode *root) 其函式回傳型別為char*,但是我在實作的程序中為了更方便的操作添加字串使用的是C++中string型別的變數,這就導致我最后得到的結果res是string型別,若是要回傳需要轉化為char *型別,而等我將string型別轉為char*后回傳在主函式中就成了亂碼,
先直接說最后的解決辦法:
第一種:定義一個char陣列,陣列長度為stringlength+1,將string的內容依次賦值給char陣列,最后加上'\0' ,然后回傳char陣列名就行了,
第二種:將string定義為類的成員變數
就貼第一種方法的代碼
char *result = new char[res.length() + 1]; //定義需要回傳的result物件 for (int i = 0; i < res.length(); ++i) { result[i] = res[i]; //將string型別的res內容都放到result內 } result[res.length()] = '\0'; //加上結束符\0
再說說我嘗試的方法
嘗試1:
一開始我是直接定義char *result=&res[0];想要通過這個陳述句直接回傳這個string型別變數的首地址,但是失敗了,在主函式中的結果變數是亂碼 "葺葺葺葺葺葺葺葺葺葺"
嘗試2:
于是我開始思考可能的原因
1.考慮到區域變數可能隨著函式釋放,因此導致我回傳的指標指向的內容隨著函式一起釋放導致了亂碼,但一想到平時寫的函式都是正常回傳的,所以這個我很快否決了,但最后發現這個思路是對的,至于平常寫的函式都是正常回傳則是因為沒有涉及到型別轉換,
2.通過VS的除錯發現我使用的char *result=&res[0]陳述句回傳的是res的首個元素地址,并不是res的首地址,因為string作為std封裝的資料結構除了char*這種從C吸收過來的結構還有記憶體分配allocate這些東西所以導致其記憶體地址并不像char陣列那樣是首個元素地址
所以我想干脆把整個string型別的res都賦值給char *型別的result
所以我嘗試了char *result=(char*)res.data();陳述句,將res(res是string型別的結果)賦給result,轉換是成功的,但回傳值依舊失效(且這種轉換需要自己加上\0結束符)
然后嘗試char *result=(char*)res.c_str(); 結果也是成功的,但回傳值依舊失效,
最后嘗試,用new新建一個char陣列,將res的內容全部拷貝到char陣列內,然后將陣列名回傳,終于成功,
問題根源
通過VS除錯我最終發現了問題根源所在:res所占記憶體隨著函式結束而被釋放
這是函式未執行完的除錯界面

這是執行完除錯界面

很明顯:res沒有了,在函式執行完畢后res記憶體也跟著被釋放了而char陣列result卻仍然存在,他們的不同點在哪:result是回傳值
我們知道函式的函式堆疊知識點,堆疊記憶體放著函式入口地址,區域變數,回傳地址等,我猜測result作為要被回傳的物件其記憶體空間應該是不隨著函式一起被釋放的,也就是主函式內的回傳值應該還是用那塊記憶體,經過測驗這個結論是對的,主函式中的變數的確是使用回傳值那塊記憶體,
到這里就發現了,雖然執行char* result=(char*)res.c_str()陳述句能讓result內是完整的結果內容(也就是轉換完成),但result會隨著string型別的res的釋放而導致char*型別的result所指向的記憶體空間內容全部清空,最后雖然回傳了result所指的空間但里面的內容早就被清空了,就好比把記憶體比作一塊地,res先在其上面蓋了一座房子,而使用上面轉換陳述句后result也是房子的主人,這下房子有了兩個主人,他們都能對房子進行操作,正因為他們都能進行操作,當他們所屬函式結束也就是res大限到來之時,res將自己建立的房子銷毀了,那么result也就沒有房子可住了,也就是他們公用的那片記憶體被初始化,這時主函式雖然收到了回傳地址但那片地址已經沒有內容了,也就導致亂碼了,
到這里,問題的根源就知道了,那么解決方法也就很明顯了:1.記憶體分離,將res和result的所屬記憶體地址分開,2.或者想辦法讓res所在記憶體不隨著函式結束而釋放.
具體實作:
第1種.上面那段new新建char*變數的代碼,為result重新開辟一段空間,
第2種.i:若在類里:將res設為類的成員變數或者static成員變數(最好不要,能成功但會有新問題出現),他們都不會隨著成員函式的結束而釋放,區別就是普通成員變數會隨著物件的釋放而釋放,static不會,它是存放在靜態存盤區
ii:若是像C這類面向程序代碼就是將res設為全域變數即可
================================7.19更新===================================
對于函式的引數,如果傳入的是char* 能否將其轉為string型別,呼叫string庫函式達到更改char*內的元素目的?
void replaceSpace(char *str, int length) { //改變不了str的指向,想改其指向,得傳入char **str //所以嘗試改變指標內容,為了呼叫string庫函式,先轉成string string(str) = string(str).replace(string(str).find(" "), 1, "%20"); //代碼error:形參str重定義 string str2=str; //也不行,str2是獨立空間
}
失敗了,,,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/3612.html
標籤:C++
上一篇:Windows高DPI系列控制元件(二) - 柱狀圖
下一篇:C++11多執行緒入門
