1. 程式人生 > >#牆裂推薦Boost regex# C,C++11,Boost三種regex庫效能比較

#牆裂推薦Boost regex# C,C++11,Boost三種regex庫效能比較

在最近的一個專案中,發現之前的正則匹配模組對於長字串匹配效能損失比較厲害,因此對長字串下的各種正則匹配進行了略微研究並附有例項。本文參考了部落格http://www.cnblogs.com/pmars/archive/2012/10/24/2736831.html(下文稱文1),這篇文章也是對三種regex庫進行了比較,但有些地方我還有一些自己的見解,特此羅列如下,感謝這篇文章的作者。

1.C regex庫

由於專案中一直用的都是C regex庫,所以首先對C regex進行了研究。對於C regex的各種介面及引數可以參照文1,如果要看起來更專業的話,可以參考這一篇,http://pubs.opengroup.org/onlinepubs/000095399/functions/regcomp.html(下文稱文2)。

對於C regex的效能測試是這樣的,首先按照慣例我們將C regex提供的各個呼叫封裝成一個呼叫,其傳入引數為模式字串和待匹配字串,如果二者匹配,則返回1,否則返回0.

這個呼叫中的流程像文1中所述,首先呼叫regcomp對模式字串進行編譯,編譯時可以指定各種引數,如擴充套件/基礎正則語法,是否忽略大小寫,是否儲存結果以及對換行符的設定(此引數請參照文2)。之後,呼叫regexec將待匹配的目標字串與編譯好的正則表示式進行匹配,後邊的引數可以設定匹配到的字串儲存位置,以及將模式字串中的行首符(^)和行尾符($)是否當作一般字元處理,詳情可以參考文1,文2。最後,呼叫regfree釋放記憶體。

int match(const char* pattern, const char* target)
{
	regex_t oRegex;
	int nErrCode = 0;
	char szErrMsg[1024] = {0};
	size_t unErrMsgLen = 0;

	if ((nErrCode = regcomp(&oRegex, pattern, 0)) == 0)
	{
		if ((nErrCode = regexec(&oRegex, target, 0, NULL, 0)) == 0)
		{
			regfree(&oRegex);
			return 1;
		}
	}

	unErrMsgLen = regerror(nErrCode, &oRegex, szErrMsg, sizeof(szErrMsg));
	unErrMsgLen = unErrMsgLen < sizeof(szErrMsg) ? unErrMsgLen : sizeof(szErrMsg) - 1;
	szErrMsg[unErrMsgLen] = '\0';

	regfree(&oRegex);
	return 0;
}
測試程式設定好模式字串以及待匹配的目標字串後,對此函式進行10000次呼叫,取開始和結束的時間之差作為效能評測依據,下文的C++11和Boost也是使用這種方法,簡單有效嘛。

考慮到是重複呼叫10000次,我們自然會想,那我豈不是在這個match裡面把同一個模式字串不停的進行編譯,匹配,釋放記憶體,我們要測試的只是匹配效能啊,編譯一次不就好了嗎,好,我們可以改進一下,封裝成下面這個呼叫,看到了吧,我們傳進來編譯好的正則表示式regex_t指標不就好了嗎,然後迴圈10000次之後,再將其記憶體釋放掉不是很完美?

int match_pre_comp(regex_t * pattern, const char* target)
{
	int nErrCode = 0;
	char szErrMsg[1024] = {0};
	size_t unErrMsgLen = 0;

	if ((nErrCode = regexec(pattern, target, 0, NULL, 0)) == 0)
	{
		return 1;
	}

	unErrMsgLen = regerror(nErrCode, pattern, szErrMsg, sizeof(szErrMsg));
	unErrMsgLen = unErrMsgLen < sizeof(szErrMsg) ? unErrMsgLen : sizeof(szErrMsg) - 1;
	szErrMsg[unErrMsgLen] = '\0';

	return 0;
}
為了同時測試上述兩種方法的效能,我們使用巨集定義來編譯出不同版本的可執行程式,設計的主體如下,在其中,我們故意使用長目標字串(1000)來進行測試,以達到目的,當指定 #define NOT_PRE_COMP時,使用第一種方法,當指定#define PRE_COMP時使用第二種方法,二者不能同時存在,也不能同時不存在。使用#define LOOP_COUNT (XXX)可以指定迴圈次數。當然這些變了之後,得重新編譯。
/*
 * Program: 
 *   This program for test c regex performance
 * Platform
 *   Ubuntu14.04     gcc-4.8.2
 * History:
 *   weizheng     2014.11.05    1.0
 */

#include <sys/time.h>
#include <stdio.h>
#include "regex.h"
#define LOOP_COUNT ( 10000 )
#define PRE_COMP

/*
 * you must choice PRE_COMP or NOT_PRE_COMP to decide pre_complie the regex expression or not
 */
#if defined(PRE_COMP) && defined(NOT_PRE_COMP)
	#error can not define PRE_COMP and NOT_PRE_COMP at the same time
#elif !defined(NOT_PRE_COMP) && !defined(PRE_COMP)
	#error please define PRE_COMP or NOT_PRE_COMP
#endif

/************************************ main ************************************/

int main(void)
{
	char pattern[] = "ywfuncFlag.*rzgw/rzdk_rzzl.jsp";
	char target[] = "<xml><param0>{\"bod\":{\"autoLoad\":false,\"keys\":[\"YWFUNC\"],\"state\":4,\"supportDynamic\":true},\"compId\":\"\",\"flag\":0,\"realUrl\":\"\",\"remoteIp\":\"\",\"ywType\":\"2\",\"ywfunc\":\"39\",\"ywfuncFlag\":\"/FMISWeb/faces/financing/dhkmanage/rzgw/rzdk_rzzl.jsp?^IRZDKServiceBC/RZFS%3d00000007%26amp;^IRZDKServiceBC/BEGINDATE%3d2014-10-01%26amp;^IRZDKServiceBC/ENDDATE%3d2014-10-31%26amp;^IRZDKServiceBC/ISTJTH%3d8\",\"ywfuncName\":\"\",\"ywfuncPageId\":\"DYHKRZZL\",\"RZWAIT_ZLLIST\":{\"bod\":{\"autoLoad\":false,\"keys\":[\"GID\"],\"state\":4,\"supportDynamic\":true},\"listItemClass\":\"com.soft.grm.investfinancing.service.masterdata.model.bo.RzptZltsOldModel\",\"listType\":0,\"masterProperty\":[],\"notUpdateField\":[],\"tableName\":\"\",\"useColumnNameToXml\":true,\"metaList\":{\"GID\":{\"columnCaption\":\"GID\",\"columnIndex\":0,\"columnName\":\"GID\",\"length\":0,\"mapName\":\"GID\",\"nullAble\":true,\"scale\":-127,\"sqlType\":2},\"ZLTS\":{\"columnCaption\":\"ZLTS\",\"columnIndex\":2,\"columnName\":\"ZLTS\",\"length\":4,\"mapName\":\"ZLTS\",\"nullAble\":true,\"scale\":0,\"sqlType\":";

#ifdef PRE_COMP
	regex_t oRegex;
	if (regcomp(&oRegex, pattern, 0))
		printf("regex complie error\n");
#endif

	/*
	 * record the start time
	 */
	struct timeval tv_start, tv_end;
	gettimeofday(&tv_start, NULL);

	/*
	 * matching
	 */
	int count = 0;
	for(int i = 0; i < LOOP_COUNT; i++)
	{
#ifdef PRE_COMP
		if(match_pre_comp(&oRegex, target))
#endif

#ifdef NOT_PRE_COMP
		if(match(pattern, target))
#endif
		{
			count++;
		}
	}

	/*
	 * record the end time
	 */
	gettimeofday(&tv_end, NULL);
	unsigned long time_used = (tv_end.tv_sec * 1000000 + tv_end.tv_usec - (tv_start.tv_sec * 1000000 + tv_start.tv_usec))/1000;

#ifdef PRE_COMP
	regfree(&oRegex);
#endif
	printf("used:   %lu ms\n", time_used);
	printf("matched %d times\n", count);

	return 0;
}

編譯執行兩種版本,結果如下:

不對模式字串進行預編譯,即就是每次都在迴圈內進行重新編譯:

[email protected]:~/test$ ./c_regex_main 
used:   418 ms
matched 10000 times

在迴圈之前對模式字串進行預先編譯,之後傳入編譯好的正則表示式用來迴圈,不進行重新編譯:

[email protected]:~/test$ ./c_regex_main 
used:   404 ms
matched 10000 times

從結果中看出C regex的匹配耗時,這個時候也不好說到底是快還是慢,看跟誰比了,如果你想知道,請繼續往下看。不過就C regex來說,不預編譯和預編譯兩種方法差異並不大,應該對於這種長字串,編譯所佔時間遠遠小於匹配時間,所以編譯一次和多次影響不會很大。

2. C++11 regex

我想說,我寫這篇文章一個主要目的就是來吐槽C++ 11 regex,準確的說,應該是吐槽g++ 4.8的!C++對於正則匹配提供了兩個呼叫:regex_match,regex_search,如果整個輸入序列與表示式匹配,則regex_match函式返回true;如果輸入序列中有一個子串與表示式匹配,則regex_search函式返回true(參考C++ primer(第五版,中文版,P646))。對於regex_match還好說,對於regex_search,說起來,我真是一萬隻草泥馬呼嘯了......

這個regex_search麼,你給模式字串設定且僅設定好一個單詞,比如上文待匹配字串中的任意一個子串,"xml"吧,這很簡單了吧,一看都應該匹配上啊,但這尼瑪就是返回false,你有啥話說,你就是把待匹配目標字串設定成“xml”,它也是返回false。臥槽,我是不是開啟的方式不對,到底問題在哪裡!

於是,我把cplusplus上的官方示例拉下來執行,我想這應該沒問題吧,但我去....regex error(模式字串編譯錯誤),我去....啥情況麼,官方都不對?好吧,我只好把聖經C++ primer拿出來,我相信聖經不會錯的,臥槽,結果真的不出所料,仍舊的regex error。我去...我三觀都毀了,草泥馬到底長的是個什麼樣子......

不過,沒事麼,咱還可以google麼,雖然被封,但咱還是能翻牆的麼,呵呵,搜尋regex_search always return false,說到底還是google管用啊,我搜到了stackoverflow上類似的問題:

http://stackoverflow.com/questions/20027305/strange-results-when-using-c11-regexp-with-gcc-4-8-2-but-works-with-boost-reg
http://stackoverflow.com/questions/12279869/using-regex-search-from-the-c-regex-library
http://stackoverflow.com/questions/11628047/difference-between-regex-match-and-regex-search?lq=1
終於找到了答案,對,你猜對了,C++11 too new,g++ 4.8還沒有完全支援。有人說VS2010,VS2012已經支援了,好吧,換上我強大的雙系統,咱windows下解決問題麼,呵呵。

來,把上面的C regex程式碼修改修改換成使用C++11 regex的,如下,注意一點,在windows下獲取時間就不能用gettimeofday了,得換成相應windows呼叫。同樣,我們通過常量LOOP_COUNT來設定迴圈次數,C++使用模式字串構造regex_t物件就相當於C regex中的編譯正則表示式字串,所以這個就不用擔心多次重複編譯了。

/*
 * Program: 
 *   This program for test c++11 regex performance
 * Platform
 *   windows8.1     VS2012
 * History:
 *   weizheng     2014.11.06    1.0
 */

#include <regex>
#include <windows.h>
#include <stdio.h>

const int LOOP_COUNT = 10000;

/************************************ main ************************************/

int main()
{
	std::regex pattern("ywfuncFlag.*rzgw/rzdk_rzzl.jsp");
	std::string target = "<xml><param0>{\"bod\":{\"autoLoad\":false,\"keys\":[\"YWFUNC\"],\"state\":4,\"supportDynamic\":true},\"compId\":\"\",\"flag\":0,\"realUrl\":\"\",\"remoteIp\":\"\",\"ywType\":\"2\",\"ywfunc\":\"39\",\"ywfuncFlag\":\"/FMISWeb/faces/financing/dhkmanage/rzgw/rzdk_rzzl.jsp?^IRZDKServiceBC/RZFS%3d00000007%26amp;^IRZDKServiceBC/BEGINDATE%3d2014-10-01%26amp;^IRZDKServiceBC/ENDDATE%3d2014-10-31%26amp;^IRZDKServiceBC/ISTJTH%3d8\",\"ywfuncName\":\"\",\"ywfuncPageId\":\"DYHKRZZL\",\"RZWAIT_ZLLIST\":{\"bod\":{\"autoLoad\":false,\"keys\":[\"GID\"],\"state\":4,\"supportDynamic\":true},\"listItemClass\":\"com.soft.grm.investfinancing.service.masterdata.model.bo.RzptZltsOldModel\",\"listType\":0,\"masterProperty\":[],\"notUpdateField\":[],\"tableName\":\"\",\"useColumnNameToXml\":true,\"metaList\":{\"GID\":{\"columnCaption\":\"GID\",\"columnIndex\":0,\"columnName\":\"GID\",\"length\":0,\"mapName\":\"GID\",\"nullAble\":true,\"scale\":-127,\"sqlType\":2},\"ZLTS\":{\"columnCaption\":\"ZLTS\",\"columnIndex\":2,\"columnName\":\"ZLTS\",\"length\":4,\"mapName\":\"ZLTS\",\"nullAble\":true,\"scale\":0,\"sqlType\":";

	/*
	 * record the start time
	 */
	LARGE_INTEGER lFreq,lSatrt,lEnd;
	QueryPerformanceFrequency(&lFreq);
	QueryPerformanceCounter(&lSatrt);

	int count = 0;
	for(int i = 0; i < LOOP_COUNT; i++)
	{
		if(std::regex_search(target, pattern))
		{
			count++;
		}
	}

	/*
	 * record the end time
	 */
	QueryPerformanceCounter(&lEnd);
	float time_used = (float)(lEnd.QuadPart - lSatrt.QuadPart)*1000/lFreq.QuadPart;

	printf("used:   %.2f ms\n", time_used);
	printf("matched %d times\n", count);

	return 0;
}

結果如下,這尼瑪簡直找不到更慢的了,不知道烏龜看到會不會後悔沒跟它比賽。你可能覺得C真特麼快,如果是這樣,你還需要繼續往下看:

used:   13754.17 ms
matched 10000 times
請按任意鍵繼續. . .
3. Boost regex

好的,下面就是我牆裂推薦的Boost regex了。Boost是C++標準庫的後備庫,有”準標準庫“之稱,頗負盛名。我當年大二寫了個自認為還不錯的系統,後來一個學長告訴我他用boost 10行程式碼就能完成...我當時就震精了。參考了Boost regex的基本介紹和一些樣例之後,發現這個設計完全跟C++11一樣啊,只要把regex呼叫的名稱空間從std換成boost似乎就好了,當然前提是你已經安裝好了boost庫,編譯時加上鍊接選項-lboost_regex。

ok,當然,測試程式碼也是簡單有效,不過看到結果時,我又一次被震精了。

/*
 * Program: 
 *   This program for test boost regex performance
 * Platform
 *   Ubuntu14.04     g++-4.8.2
 * History:
 *   weizheng     2014.11.06    1.0
 */

#include <boost/regex.hpp>
#include <sys/time.h>
#include <cstdio>

const int LOOP_COUNT = 10000;

/************************************ main ************************************/

int main()
{
	boost::regex pattern("ywfuncFlag.*rzgw/rzdk_rzzl.jsp");
	std::string target = "<xml><param0>{\"bod\":{\"autoLoad\":false,\"keys\":[\"YWFUNC\"],\"state\":4,\"supportDynamic\":true},\"compId\":\"\",\"flag\":0,\"realUrl\":\"\",\"remoteIp\":\"\",\"ywType\":\"2\",\"ywfunc\":\"39\",\"ywfuncFlag\":\"/FMISWeb/faces/financing/dhkmanage/rzgw/rzdk_rzzl.jsp?^IRZDKServiceBC/RZFS%3d00000007%26amp;^IRZDKServiceBC/BEGINDATE%3d2014-10-01%26amp;^IRZDKServiceBC/ENDDATE%3d2014-10-31%26amp;^IRZDKServiceBC/ISTJTH%3d8\",\"ywfuncName\":\"\",\"ywfuncPageId\":\"DYHKRZZL\",\"RZWAIT_ZLLIST\":{\"bod\":{\"autoLoad\":false,\"keys\":[\"GID\"],\"state\":4,\"supportDynamic\":true},\"listItemClass\":\"com.soft.grm.investfinancing.service.masterdata.model.bo.RzptZltsOldModel\",\"listType\":0,\"masterProperty\":[],\"notUpdateField\":[],\"tableName\":\"\",\"useColumnNameToXml\":true,\"metaList\":{\"GID\":{\"columnCaption\":\"GID\",\"columnIndex\":0,\"columnName\":\"GID\",\"length\":0,\"mapName\":\"GID\",\"nullAble\":true,\"scale\":-127,\"sqlType\":2},\"ZLTS\":{\"columnCaption\":\"ZLTS\",\"columnIndex\":2,\"columnName\":\"ZLTS\",\"length\":4,\"mapName\":\"ZLTS\",\"nullAble\":true,\"scale\":0,\"sqlType\":";

	/*
	 * record the start time
	 */
	struct timeval tv_start, tv_end;
	gettimeofday(&tv_start, NULL);

	int count = 0;
	for(int i = 0; i < LOOP_COUNT; i++)
	{
		if(boost::regex_search(target, pattern))
		{
			count++;
		}
	}

	/*
	 * record the end time
	 */
	gettimeofday(&tv_end, NULL);
	unsigned long time_used = (tv_end.tv_sec * 1000000 + tv_end.tv_usec - (tv_start.tv_sec * 1000000 + tv_start.tv_usec))/1000;

	printf("used:   %lu ms\n", time_used);
	printf("matched %d times\n", count);

	return 0;
}
結果如下:
[email protected]:~/test$ ./boost_regex_main 
used:   11 ms
matched 10000 times

這結果,竟然比C快了40倍,而且這都是在模式字串可以匹配目標字串的前提下的,如果測試不匹配的情況,Boost竟然比C快了4000倍,我不敢相信這個結果,在此貼上測試用的模式字元和目標字元,看有沒有人跟我一樣,或者有別的原因,例如跟正則表示式或者目標字串本身結構有關,測試字串如下:

	boost::regex pattern(".*CSZ.*XTCS.*CSMC.*NEWBB");
	std::string target ="<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><SOAP-ENV:Envelope xmlns:SOAPSDK1=\"http://www.w3.org/2001/XMLSchema\" xmlns:SOAPSDK2=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:SOAPSDK3=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><SOAPSDK4:GetSystemDate xmlns:SOAPSDK4=\"http://svr.blf.common.fmis.ygsoft.com\"/></SOAP-ENV:Body></SOAP-ENV:Envelope>";
所以,從以上對比結果中看出boost regex的表現似乎極為突出,但文1中最後的比較結果是C regex更快,我與其測試結果不同,希望看到更多的測試結果,搞清楚問題。不過,目前最期待的還是如果將專案中原來的C regex替換成Boost regex,不知道結果會怎麼樣,拭目以待吧。


相關推薦

#推薦Boost regex# CC++11Boostregex效能比較

在最近的一個專案中,發現之前的正則匹配模組對於長字串匹配效能損失比較厲害,因此對長字串下的各種正則匹配進行了略微研究並附有例項。本文參考了部落格http://www.cnblogs.com/pmars/archive/2012/10/24/2736831.html(下文稱文

乾貨分享iOS日誌顏色分類 豐富你的控制檯 簡直不要太好用 推薦

StarConsoleLink 這個工具的名字叫做:StarConsoleLink 他能豐富你的控制檯,給你的日誌加上超連結,並且集成了XcodeColors,讓你的日誌顏色多樣化,現已支援Xcode7.2,Xcode7.3.1,並支援直接sh安裝。 別忘了隨手點顆星哦。

Linux Shell 程式設計基礎詳解——吐血整理推薦

#第一部分:Linux Shell 簡介 Shell 是一個用 C 語言編寫的程式,它是使用者使用 Linux 的橋樑。Shell 既是一種命令語言,又是一種程式設計語言。 Shell 是指一種應用程式,這個應用程式提供了一個介面,使用者通過這個介面訪問作業系統核心的服務。 Ken Thompson 的 sh

(轉載)(推薦)神經網路的基本工作原理

作者:SoftwareTeacher  來源:CSDN  原文:https://blog.csdn.net/SoftwareTeacher/article/details/83991254  版權宣告:本文為博主原創文章,轉載請附上博文連結! ---------------

2017年全球最受歡迎的前端技術JS框架和薪酬排行(""推薦

回顧過去的一年,前端技術發展很快,讓我們看看全球前端技術的使用情況: 從圖中可以總結出以下以下幾點: I. 全球目前在使用並且想要使用的前三名(I’ve USED it before, and WOULD use it again): 第一名:Re

JAVA面向物件面試題帶答案(推薦

1) 在Java中,如果父類中的某些方法不包含任何邏輯,並且需要有子類重寫,應該使用(c)關鍵字來申明父類的這些方法。 a) Finalc b) Static c) Abstract d) Void2) 給定兩個java程式,如下:public interface Face{ int counter = 4

C#學習筆記(12)——方法操作XML

結點 記得 ext 應用程序 eval 資源 特性 pla cells 說明(2017-7-11 16:56:13): 原文地址: C#中常用的幾種讀取XML文件的方法 XML文件是一種常用的文件格式,例如WinForm裏面的app.config以及Web程序中的web.c

C#實現發送郵件的方法

thumbnail catch plugins () listbox 幫助 哈希 .text sbo 本文實例講述了C#實現發送郵件的三種方法。分享給大家供大家參考。具體方法分析如下: 一、問題: 最近公司由於一個R&I;項目的需要,用戶要求在購買產品或出貨等

Problem C HDU - 5687(字典樹的操作)

傳送門 題意:有三種操作,第一種是插入一個單詞,第二種是刪除具有這個字首的所有單詞,第三種是查詢是否具有這個字首的單詞 題解:使用字典樹,挑戰最大的是刪除這個操作,可以這樣,如果沒有這個字首直接退出,如果有這個字首,那麼先將這個字首之後所有的都消去,再回上來刪除具有這個字首的數量(很重要),

C++結構體多級排序的方法

C++結構體多級排序的三種方法 struct node{ int chinese,math; char name[15]; }; 需求:按數學成績從大到小排序  1.自定義比較器 //自定義比較函式 bool cmp(node a,node b){ return

C++ STL 建立執行緒的方式

使用 stl thread 編寫多執行緒程式時,編譯需要加 -pthread 通過函式指標建立執行緒 #include <iostream> #include <thread> using namespace std; void func(int id

初夏小談:斐波那契實現方法(C語言版)(第相信你沒見過)

斐波那契數列(Fibonaccisequnce),又稱黃金分割數列。研究斐波那契數列有相當重要的價值,例在現代物理、準晶體結構、化學等領域都有直接的應用。因此研究斐波那契數列也是很有必要的。 今天初夏將為大家帶來計算斐波那契數列第n位的三種方法 第一種利用遞迴的方法計算,程式碼相當簡單,但其

C++: 繼承和多型(一)繼承方式與許可權

繼承 在C++中,我們常要對某個函式進行多次複用,例如: 資訊管理系統中,對於教師、學生、教務人員等"類"而言,有部分資訊是通用的:姓名,性別,年齡,聯絡方式等。如果為每一種角色都編寫一個"類",會有不少重複的程式碼,造成效率上的浪費。       &nbs

c++】遍歷字串的方式

就以:把字串“1234”轉換為整形1234,為例來說明遍歷字串的三種方式: ①常規方式(下標+operator[]) #include <iostream> #include <string> #include <vector> #include <

C#中遍歷ArraryList的方法

using System; using System.Collections; using System.Linq; using System.Text; namespace ArrayListDemo { class Program { static void

c++ STL中sort函式的使用方法

複習一下~ STL,C++中的標準模板庫, 使用起來方便並且效率較高; sort函式有三種用法: 一:對基本型別陣列從小到大排序 sort( 陣列名+n1,陣列名+n2); 將陣列中下標從n1到n2的元素進行從小到大排序,不包括n2,通過n1,n2 可以對整

C語言學習(六)基本程式結構

例一:財務人員給員工發工資時經常遇到這樣一個問題,即根據每個人的工資額(以元作為單位)計算出各種面值的鈔票的張數,且要求總張數最少。 例如,某職工工資為3436元,發放方案為:100元34張,20元1張,10元1張,5元1張,1元1張。 #include <stdio

C語言寫一個計算器的方法

方法一:常規方法#include<stdio.h> int Add(int a, int b) { return a + b; } int Sub(int a, int b) { return a - b; } int Mul(int a, int b) {

C++ 有參建構函式的呼叫方法

class Test { private: int a; int b; public: //帶引數的建構函式 Test(int a) {

黃聰:C#獲取網頁HTML內容的方式

HttpWebRequest httpReq; HttpWebResponse httpResp; string strBuff = ""; char[] cbuffer = new char[256]; int byteRead = 0; string filename