如何安全動態格式化字串

2021-03-31 08:56:29 字數 2440 閱讀 3289

在c語言中,我們如果希望進行格式化進行輸出,一般我們用 sprintf 來字串。

例如:char temp[100];

sprintf(temp, "%s", "helloworld"  );

通常上面的操作應該沒有任何問題。但是,在某些情況下,是有意想不到的結果產生。

比如:在進行出錯資訊進行輸出時,我們採取如下寫法:

char temp[64];

sprintf( temp, "error at file %s , line %d , column %d , message: %s", strfile, linenumber, columnnumber, strmessage);

一般情況下,如果出錯資訊較少,上面程式沒有任何問題,如果出錯資訊很長,上面的資料會越界,從而導致改寫其他記憶體中的內容,引發一些你想象不到的錯誤。

這時,估計你的解決方案就是增大temp的空間,比如:temp[1000]。

沒錯,這樣改正之後,造成上面出錯的概率會較少很多,但是還沒有完全解決此問題。

在使用者如果提供比較多的出錯資訊時,還是有問題產生。

那麼我們有沒有辦法來完全解決此問題呢????

在c++中,有個string類,可以用來動態儲存字串,它會根據當前字串的長度來調整它的長度。

且string.begin() 相當於char*指標。

說到這,你是不是有一種衝動改寫上面的程式?( i so ).

string strtemp;

strtemp.reserve(64); //優化string的記憶體分配策略

sprintf( strtemp.begin(), "error at file %s , line %d , column %d , message: %s", strfile, linenumber, columnnumber, strmessage);

編譯通過,^_^(竊喜) ! 

測試一下,在較短的出錯訊息(沒有超過64)時,沒有任何問題,但是在超過64之後,會進行出錯!!!(是不是比上面的比較『安全』? )

為什麼上面會出錯???string 不是動態進行擴充套件儲存空間嗎?

沒錯,如果超過64之後,string會進行動態分配空間,由於string一般確保它的儲存空間連續性,所以它是重新分配一塊足夠大的空間,然後將資料copy過去,這個過程類似於realloc 來分配空間。這必然導致我們現在的string.begin()和以前的begin()所指向的位址不一樣。

而我們sprintf指向的位址是以前的string.begin(),不是重新分配之後的空間,一般以前分配的空間會被釋放,所以會導致程式出錯。

哪我們還有沒有別的辦法來改善上面的問題???

mfc中的cstring類有個成員函式format就可以用來格式化字串,並且可以動態擴充套件此字串。

是不是很酷???

但是,對於我來說,凡是不在ui地方(即介面顯示部分),盡量避免使用mfc中的內容,使得以後的移植比較方便(可能有點杞人憂天的感覺),嘿嘿!!

難道就沒有別的解決方案???

畢竟格式化字串是非常常見的事情,連c中都有乙個特定的函式來完成(sprintf)。難道c++裡面就沒有解決方案嗎?

記得在c++的io輸出流中,標準的cout,就可以用來格式化輸出到螢幕。

如果是fstream就可以用於格式化輸出到檔案中。(說到這裡,好像記得有個字串流?)

趕快進行msdn搜尋,呵呵,找到了這個傢伙。

不再多說了,直接進行示例.

std::ostringstream strout( ios_base::out);

strout << "error at file " << file

<< " line " << linenumber << " column " << columnnumber << endl;

strout << " message:" << cerrormsg(errorcode).geterrormsg() << endl;

strout << " usermessage: " << errstr << endl;

然後我們可以把上面的字串提取出來.

string strvalue =  strout.str();

到了這一步,你應該知道如何來使用string型別的值了吧。

呵呵,終於將它進行解決了,並且解決的如此徹底( 噓,不要告訴別人,告訴你乙個秘密,以前碰到此問題,沒有很好的進行解決過,只是適當的將temp的陣列增大,即將出錯的概率進行了降低!)。

什麼??? 你無法編譯???? 加入相關標頭檔案不就可以了嗎???不知道哪個標頭檔案,那去msdn中查詢啊。

什麼你沒有查到?耐心一點會有的(不過在比較隱蔽的地方)。

use to work with objects of type basic_string.

use work with char *, which are c strings

即:在上面中,我們只要加入下面一句就可以了:

#include

字串格式化

sprintf snprintf snprintf std stringstream std strstream boost lexical cast boost format cstring format 1 sprintf 使用 sprintf 不安全,輕則破壞資料的準確性,重則程式崩潰。請看下...

格式化字串

通常在使用字串的時候,會對字串進行格式化,然後輸出或呼叫 一般我們使用替換標記對字串進行格式化 string str1 string.format add is 1,2,3 而且在c 中的替換標記可以以任意順序和次數出現在格式化字串中,但替換值是按順序排的,而且替換標記不能超出索引範圍 string...

字串格式化

例如 string s hello map.put target world string res format s,map 有什麼用呢?比如在some.properties中配置模板字串,但是如果用 這種方式,在配置了spring讀取properties注入變數的時候,這個變數就找不到會報錯。這個...