思考
在C語言這種靜態(tài)語言處理可變長的字符串往往是個(gè)令人頭大的事。是不是就沒辦法處理這種令人頭的字符串呢?答案應(yīng)該是否定的!這種令人頭痛的東西,那些研發(fā)人員早就注意到,應(yīng)該不會(huì)這么長時(shí)間沒有一個(gè)解決方案。
查找
俗話說的好,“世上無難事,只怕有心人”。在查閱《21st Century C》時(shí)候,找到了處理這種令人頭痛的字符串的方法。
書中在例 9-3 中運(yùn)用了C語言的可變參數(shù)宏的特性和asprintf函數(shù)實(shí)現(xiàn)了一個(gè)可輸入變長字符串的字符串拓展宏。
代碼
#include<stdio.h>
#include<stdlib.h> //free
//Safer asprintf macro
typedef char* string;
#define str_extend( wt , ... ) { \
string tmp = ( wt ); \ // 記錄字符串原地址
if(asprintf(&(wt), __VA_ARGS__) < 0) abort(); \ // 更新變量 wt 地址
if(tmp) { free(tmp);tmp=NULL; } \ // 釋放原地址數(shù)據(jù)
}
int main(){
int i = 3;
string q =NULL; // 指針初始化置NULL值
str_extend(q,"select * from tab\n");
str_extend(q, "%swhere col %d is not null\n", q ,i);
printf("%s", q);
free(q);
q=NULL;
}
結(jié)果
解釋
首先這個(gè)宏有兩個(gè)比較特別的地方:
- 使用了可變參數(shù)宏。
- 使用了asprintf函數(shù)。
可變參數(shù)宏
這個(gè)相關(guān)解釋可以看另一篇博客
關(guān)于C語言如何實(shí)現(xiàn)默認(rèn)參數(shù)的解決方法
asprintf()函數(shù)
asprintf 函數(shù)分配必要的字符串空間并填充字符串,如果內(nèi)存已滿返回-1,屬于動(dòng)態(tài)內(nèi)存,需要手動(dòng)釋放。
注意:傳給 asprintf 函數(shù)的字符串 應(yīng)該 預(yù)先進(jìn)行基本的字符串安全性檢查。
提示
我們在使用C語言字符串時(shí)候,大部分情況字符串長度都不是固定,這個(gè)可變參數(shù)宏方法可以很好的解決變長字符串問題。
有時(shí)候我們需要接受一個(gè)字符串的情況,一般如下:
char dtm[100];
strcpy( dtm, "Saturday March 25 1989" );
這樣做不僅直接限制了dtm長度,還容易使得字符串操作越界。如果直接定義一個(gè) char * 的變量,那么strcpy就無法使用,運(yùn)行直接奔潰。
常量字符串又不是我們需要處理的,而且我們大部分時(shí)候也不是想要一個(gè)常量,也不想去管這個(gè)字符串具體的長度(但是 我們心里要對操作的字符串長度有點(diǎn)數(shù),別太過于大,當(dāng)然這種情況一般比較少見)。
這個(gè)時(shí)候 asprintf 函數(shù)的優(yōu)勢就體現(xiàn)出來了,它一不需要傳入字符串長度參數(shù),二只需要一個(gè)普普通通的 char * 變量作為接收者即可。
這時(shí)上面的情況我們就可以如直接調(diào)用示例代碼中的str_extend() 宏來完成這個(gè)任務(wù),如下:
char *dtm =NULL;
str_extend(dtm,"Saturday March 25 1989");
非常簡潔明了且舒服~!
當(dāng)然,我們也可以使用這種方法實(shí)現(xiàn)類似 strcpy 函數(shù)的功能。
如果只是初始化并賦值一個(gè)字符串,又不想其被編譯器解釋為一個(gè)常量(定die了的那種),那么可以使用以下這利用asprintf函數(shù)制作出如下strdup函數(shù)來避免這種情況:
代碼
#include<stdio.h>
#include<stdlib.h>
typedef char* string;
string strdup(const string in){
if(!in) return NULL;
string out;
if(asprintf(&out,"%s", in) < 0) {
printf("Memory is full!\n return NULL!");
return NULL;
}
return out;
}
int main(){
string q=strdup("愛你呀!\n"); // 初始化賦值一步走,得到字符串變量
printf("%s",q);
free(q); // 因?yàn)閟trdup函數(shù)創(chuàng)建動(dòng)態(tài)分配內(nèi)存
q=NULL;
}
結(jié)果
通過 strdup 函數(shù)創(chuàng)建出來的字符串就是遵循正常字符串變量使用邏輯,而非常量。
總結(jié)
在字符串處理任務(wù)中,變量字符串的處理往往是一件令人頭的事情。現(xiàn)在,我們有了 asprintf 函數(shù),就可以輕松愉快的處理這些麻煩的問題。因?yàn)檫@種方法會(huì)涉及指針的使用,所以不要忘記給自己“擦屁股”。
注意:
文章為本人在簡書平臺原創(chuàng),盜用必究!