本文給出了一個對Microsoft
.NET
和Microsoft's
XML
Web服務平臺的總體介紹以及使用它們的好處。同時我們還將舉例說明
.NET
是如何改變終端用戶和商業的計算模式。
??
?? 在本文中我們不想涉及到很精深的技術,任何稍微懂一點電腦和Internet知識的人都可以理解本篇的內容。Micorosoft還為那些希望掌握
.NET
的公司執行官、IT領導和程序員們
??提供了更多的資源。
??
?? 什么是Microsoft
.NET
?
??
?? Microsoft
.NET
是Microsoft的
XML
Web服務平臺。
.NET
包含了建立和運行基于
XML
的
軟件
所需要的全部部件。
??
?? Microsoft
.NET
解決了下面這些當今
軟件
開發中的一些核心問題:
??
?? ●互操作性(Interoperability)、集成性(Integration)和應用程序的可擴展性(extensibility)太難實現而且代價很高。Microsoft
.NET
依靠
XML
(一個由World Wide Web Consortium(W3C)管理的開放標準)消除了數據共享和
軟件
集成的障礙。
??
?? ●無數具有相當競爭力的私有
軟件
技術使得
軟件
的集成變得非常復雜。而Microsoft
.NET
建立在一個開放的標準上,它包含了所有
編程
語言。
??
?? ●當終端用戶使用
軟件
時,他們總覺得不夠簡便。有時甚至感到很沮喪,因為他們無法在程序之間方便地共享數據或是無法對能訪問的數據進行操作。
XML
使數據交換變得容易了,并且
.NET
軟件
可以使得用戶只要一得到數據就能對它們進行操作。
??
?? ●終端用戶們在使用Web的時候,無法對自己的個人信息和數據進行控制,這導致了個人隱私和安全泄漏問題。而Microsoft
.NET
提供了一套服務,使用戶可以管理他們的個人信息,并且控制對這些信息的訪問。
??
?? ●.COM公司和Web站點開發者們很難為用戶們提供足夠的有價值的數據,至少有一部分原因是由于他們的應用程序和服務無法很好地和其他程序和服務合作,只是一個不和外界連接的信息孤島。而Microsoft
.NET
的設計宗旨就是為了使來自于多個站點和公司的數據或服務能夠整合起來。
??
?? 如同MS-DOS和Windows一樣,
.NET
將大大改變我們的計算領域。MS-DOS使得個人電腦在商業和家庭中廣為接受;Windows增強了用戶的圖形界面,使其成為首選的與
軟件
交互方式,最終使得圖形界面成為個人電腦的主流。而
.NET
則要把
XML
Web服務變成日后的主流計算模式。
??
??
XML
Web服務是建立在
XML
數據交換基礎上的
軟件
模型,它幫助應用程序、服務和設備一起工作。用
XML
進行共享的數據,彼此之間獨立,但同時又能夠松耦合地連接到一個執行某特定任務的合作組。
??
?? 想了解
XML
Web服務如何工作,最方便的方法就是把它和拼裝
游戲
作比較。
XML
Web服務和拼裝
游戲
的拼塊一樣是一些獨立的單元。后者用一個標準的方法相互咬合在一起,
XML
Web服務與這類似,但它是通過
XML
message實現相互交互的。當你把拼塊拼在一起時,你就得到了一個對象:一幢房子、一艘船或一架飛機。同樣,當你把
XML
Web服務結合在一起時,你就得到了一個完成某特定任務的
軟件
解決方案。同一拼塊可以用在很多不同對象中,而一個
XML
Web服務同樣也可以用在不同的方案組中,作為不同任務解決方案的一個組成部分。
??
??
XML
Web服務使開發者能夠對他們所要的程序的來源進行選擇,可以自己創建或購買程序的功能塊;同樣也可以選擇是讓自己的方案使用其他的
XML
Web服務,還是讓其他的程序使用自己的服務。這意味著一個公司不必為了給客戶一個完整的解決方案而不得不提供方案的每一個組成部分。
??
??
XML
Web服務除了個服務相互之間獨立以外,對訪問它們的設備而言也是獨立的。與獨立應用程序不同的是,
XML
Web服務并沒有束縛于某一特定的
編程
語言或商業應用程序或者是某一在線服務。這給了終端用戶足夠的自由,使其可以使用任何訪問設備,從臺式電腦到移動電話都可以。
??
??
.NET
戰略
??
?? Microsoft
.NET
程序員們設計編寫的是
XML
Web服務,而不是服務器或客戶端的獨立應用程序。他們把這些服務組合成松耦合,相互協作的
軟件
群,
XML
Web服務之間使用
XML
messaging進行通訊。為了做到這一點,程序員需要:
??
?? 1.一個
軟件
平臺,用于建立一種新的完整的個人用戶經驗。
??
?? 2.一個
編程
模型和工具,用以建立和整合
XML
Web服務。
??
?? 3.一套能為應用程序和服務提供基礎的可
編程
的服務
??
?? Microsoft的
.NET
戰略就瞄準了這三點。
??
??
.NET
包括:
??
?? ●
.NET
平臺,這是一套
編程
工具和基本構架,用來創建、發布、管理和整合
XML
Web服務
??
?? ●
.NET
體驗,這是終端用戶用以和
.NET
交互的手段
.NET
平臺
??
?? Microsoft的平臺是由用于創建和運行
XML
Web服務組成的。它包含了下面四個組件:
??
??
.NET
框架和Visual Studio
.NET
:這些是開發人員用來生成
XML
Web服務的工具。
.NET
框架是Microsoft
.NET
平臺核心中的一套
編程
接口;Visual Studio
.NET
是一套多語言系列的
??
編程
工具。
??
?? 服務器基本結構(Server Infrastructure):
.NET
的服務器基本結構是一系列用于生成、發布和操作
XML
Web服務的基礎程序,包括Windows和各種
.NET
企業服務器。主要的技術包括對
XML
、scale-out及跨程序和服務的商務流程(business process orchestration)的支持。這些服務器包括有:
??
?? ●Application Center 2000,用于scale-out solutions
??
?? ●BizTalk Server 2000,用于創建和管理基于
XML
的跨程序和服務的商務流程(business process orchestration across applications and services)
??
?? ●Host Integration Server 2000,用來訪問主機上的數據和應用程序
??
?? ●Mobile Information 2001 Server,使移動設備,比如移動電話,也能使用這些應用程序
??
?? ●
SQL
Server
2000儲存和檢索結構化的
XML數據
??
?? Building Block Services: Building Block Services是一套以用戶為中心的XML Web服務,它把用戶數據的控制權從應用程序移到了用戶手上,使Web有了一個翻天覆地的變化,做到了程序、服務和設備之間的簡單性及一致性,這保證了所有的交易都必須得到用戶的同意。這些服務包含了Passport(用于用戶身份驗證)、服務之間的消息傳遞、文件存儲、用戶個性設置的管理、日歷管理和其他一些功能。Microsoft將在那些對.NET基本結構起至關重要作用的領域內提供一些塊構建服務(building block services)。大量的合作伙伴和開發商將對這些塊構建服務作重要的擴展。
??
?? 智能設備(smart device): .NET利用軟件使智能設備,諸如手提電腦、輕便電話、游戲操縱臺等都能夠在.NET世界中得以使用。
??
?? 一個智能設備應該:
??
?? ●對用戶要智能:能根據用戶的.NET身份、檔案(profile)和有關數據簡化用戶的工作;另外要對用戶的存在足夠的智能,能根據你的在與不在對通知(notification)作出調整。
??
?? ●對網絡要智能:負責帶寬的限制;支持應用程序的在線和線下兩種使用模式;知道有哪些有效的服務。
??
?? ●對信息要智能:能在任何地方、任何時間訪問、分析和操作數據。
??
?? ●對其他的設備要智能:能發現和報告其他智能設備、服務和Internet的存在;知道如何為其他設備提供服務;能夠靈活方便地從PC上訪問信息。
??
?? ●對軟件和服務要智能:能根據表單的情況,最恰當地表現應用和數據;為終端用戶提供合適的輸入方法和連接;用XML、SOAP和UDDI來使用Web服務;對開發者來說,要具有可編程性和擴展性
??
?? Microsoft的一些軟件使能夠在智能設備上運行的,它們包括Windows XP、Windows Me、Windows CE、嵌入式Windows、.NET框架以及.NET Compact框架。
??
?? .NET體驗(.NET experiences)
??
?? 終端用戶是通過.NET體驗訪問XML Web服務的,這和現有的獨立應用程序有點類似,但在下列這些重要的方面是不同的:
??
?? ●.NET體驗可使用于多種設備我們無需為可能使用的每一個設備編寫一個不同XML Web服務和不同的.NET體驗,.NET體驗能夠讀取用戶選取設備的特征,給出一個恰當界面。
??
?? ●.NET體驗使用XML Web服務當.NET體驗連入網絡后就能有效地利用XML Web服務為用戶帶來額外的價值,以更好地解決問題。
??
?? ●.NET體驗是以用戶為中心的.NET體驗的焦點在終端用戶,使用基于身份驗證的塊構建服務來為用戶驗證、參數設定、通知機制和用戶數據提供服務。因為用戶數據是由塊構建服務管理的,而不是應用程序本身,所以用戶就能控制他們自己的數據,能保障它的正確性,并且可以在不同的程序和服務之間協調數據。
??
?? Microsoft正在使最受歡迎的四個產品過渡到.NET體驗。Microsoft Office XP為用戶提供.NET體驗方面跨出了第一步。另外,MSN,包括MSN Explorer本地客戶端的使用,正在創建一個基于消費者的.NET體驗。Microsoft bCentral的小型商務入口(business portal)正努力為小型事務(比如商品目錄管理)提供必要的XML Web服務,同時也使用一些重要的XML Web服務(比如eBay)。Visual Studio開發系統將為開發者們提供.NET體驗,可以在這些開發工具中直接得到MSDN信息。
??
?? .NET的好處
??
?? Microsoft .NET為程序員、商業領導、IT部門以及消費者帶來了很多好處。
??
?? ●相對來說,程序員是比較缺乏的,雇用的費用也很高。然而Microsoft .NET使編程工作變得更加容易,開發投資的回報率也趨最大化。開發者們可以創建能重用的XML Web服務,而不再是一個單一的程序;這些Web服務易于編程和調試,彼此之間相互獨立,通過XML message通訊及合作。所以對某一個服務的修改不會影響到其他的服務。
??
?? 由于XML Web服務可以被很多.NET體驗共同使用,所以對一個服務模塊的有效更新,也即更新了所有使用這個模塊的.NET體驗。任何編程語言都可以用來編寫XML Web服務(如:C、C++、Visual Basic、COBOL、Perl、Python和Java等),所以你的程序員可以選擇他們最熟悉的語言來編程,這大大提高了開發效率。更值得一體的是,他們并沒有因使用了不同的語言而失去跨服務或跨組件的調試能力。
??
?? ●Microsoft .NET減少了程序員要寫的代碼量。一個XML Web服務能適用于所以的設備,不必再去為每一個設備編寫一個不同的版本。另外,將顯示特性與.NET體驗分開以便以后加入新的接口技術,比如語音或手寫識別,而不必去重寫程序。
??
?? ●Microsoft .NET開創了全新的商業模型,它使得一個公司可以用多種方法來把自己的技術商品化。據個例子來說,一個通訊公司可以使用XML Web服務的方式提供語音信件和呼叫者ID的訪問,讓用戶從一個即時消息程序、電子郵件或用戶所選的其他信息編譯器中訪問到上述信息。技術提供商可以把他們現有的軟件包轉變為XML Web服務,并把這些服務出售給需要這些功能第三方,或是給.NET體驗提供商,用以構建新的軟件包。
●Microsoft .NET允許IT部門使用其他提供商的XML Web服務,減少內部研發的開銷,并能提高工作效率。
??
?? ●Microsoft .NET對"用戶界面友好"作了重新定義。終端用戶能夠徜徉于一個智能化的、個性化的Internet,它能記住用戶的個人設置,并在適當的時候,向用戶使用的智能設備上發送適當的數據。
.NET如何改變計算 ?? ?? Microsoft .NET將從根本上改變我們的思考和使用電腦的方式。目前"服務器"和"桌面電腦"這兩種概念占據了計算領域的統治地位。然而Microsoft .NET是一種分布式計算范例,它沒有了傳統上的服務器和桌面電腦的區別,取而代之的是,計算的處理被放在最合適的地方進行,可能是服務 ??器,或是PC,也有可能是手提電腦以及其他智能設備。這就是智能計算。 ?? ?? .NET的計算模型對商務和終端用戶都產生了重要影響,但方法不同。對終端用戶來說,這個新計算模式更具個性化、綜合程度更高,會給他們帶來一種史無前例的新體驗。對商務來說,這個模式改變了制造和銷售軟件的方法,使IT成為一個公司成功的重要貢獻者,并建立起新的商務模型。 ?? ?? 對終端用戶的改變 ?? ?? 這里有一個例子,說明了.NET體驗是如何對一個終端用戶產生影響的。 ?? ?? Bob,一個不安的商務旅行者,在芝加哥下了飛機,突然想起他竟忘了帶上他的那部智能電話。這下完了,沒了這電話他無法知道晚宴在哪里進行,無法知道原本打算在晚宴上見面的人的電話號碼,更慘的是,他無法在這個關鍵的會議之前再看一下重要的文件。但不用急,他從機場的租了一部智能電話,插入了自己的智能卡。很快通過內置的Internet連接,各種相關的重要數據全部被下載了下來,現在他能訪問他的所有信息,不光是日程安排和電話簿,還有所有通常用他的PC機能訪問到的所以文件。 ?? ?? 不幸的是,他在離開機場時不小心在自動扶梯上絆了一跤,腳踝嚴重扭傷,這個月這已經是第二次了。無奈,他強忍疼痛要求電話接Roger醫生的辦公室,聽電話的是接待員Mildred小姐。Bob通過電話確認了自己的身份,他授權于Mildred小姐,讓她訪問自己的所在位置和其他一些信息,以便使她可以在附近找一家整形外科診所。Mildred能夠知道哪家診所正在營業,有多遠,是否接受Bob的保險。Bob所要做的就是輕按電話上的按鈕授權給她,Mildred在找到診所后便會和醫生約時間。 ?? ?? 與Mildred通話結束后,Bob用他的智能電話訪問出租車服務,查找離他最近的出租車,并確認目的地。接下來Bob只需爬進車內,輕按電話的顯示屏確認支付的費用即可。 ?? ?? 從用戶角度來講,.NET提供的好處即超過了現在的獨立的程序,也勝過了純粹的Web站點。XML Web服務擁有傳統的軟件功能,如創建文檔、計算數字、存儲數據等。而且在下線后也能提供服務,比如呼叫出租車,這并不需要CPU的參與。 ?? ?? 從上面的例子我們可以看到,XML Web服務使終端用戶得到了更為個性化的、綜合性的體驗,同時便捷也是.NET給我們帶來的一大好處。 ?? ?? 對企業的改變 ?? ?? Bob那不走運的商務旅行結束了,他蹣跚地回到了家(雖然那個晚宴非常成功,但現在他不得不面對六個星期的身體治療)。接下來,Bob要提交費用報告。他拿出了他的PDA,驗明身份后,PDA列出了其信用卡上的支付紀錄。他標出了與這次芝加哥之行有關的費用,至于那些止痛藥和寄私人信件的費用,他標為個人開銷。信用卡公司將為其生成必要的賬單。 ?? ?? 因為Bob標記了一些個人費用,所以信用卡公司將根據他指定的方法為Bob生成一張個人帳單。在這個例子中,Bob使用的是直接從他銀行賬號中提錢的方法,但同時他也要一份藥費開支報告的硬拷貝。根據他的選擇,信用卡公司會Email發給他一個PDF文檔,Bob只需將它打印出來即可。 ?? ?? 對于那些業務上的開支,信用卡公司會給Bob的公司發出一張電子帳單,它被送到公司的會計部門,由公司會計Chris來處理。電子帳單到達時,Chris會收到一封自動生成的Email,隨后他登錄會計系統打開這份帳單。他仔細檢查每一筆費用,沒問題后,他進行支付,這也就是授權將一筆金從公司的賬戶轉移到信用卡公司的賬戶上。 ?? ?? 從企業角度講,.NET能夠自動地處理很多任務,節約了員工的大量時間。當用XML將系統和XML Web服務連接起來后,數據交換變得非常方便,數據處理也變得輕而易舉。在這個例子中,員工Bob和Chris分別只要單擊一下"同意"和啟動一個事務處理,無需花大量的時間去填寫報銷單或是往會計系統中手工錄入數據,一切都變得非常之簡單。 ?? ?? 對企業和企業終端用戶來說,.NET預示這些從XML Web服務衍生出來的應用程序有著很強的個性化和高度的整合性的特點,同時它們適用于各種智能設備,具有相當的靈活性。 ?? ?? 什么東西沒有變 ?? ?? 盡管Microsoft .NET給計算帶來了一些翻天覆地的變化,但還有很多東西依然沒有改變. ?? ?? ●終端用戶將依然使用熟悉的界面,就像.NET體驗中的Microsoft Office一樣。這可以減少再培訓的開支,也意味著用戶可以馬上開始使用.NET軟件。 ?? ?? ●硬件上運行的還是象Windows、Unix、Windows CE和Palm OS一樣的操作系統。實際上,.NET增加了軟件的運行場所,但同時減少了開發的負擔。由于XML Web服務只使用XML與設備通信,所以任何智能設備都可以享用XML Web服務。 ?? ?? ●對程序員來說,他們依然可以使用他們原先熟悉的編程語言。.NET平臺借助于.NET框架的公共語言運行時間庫(CLR)使得用不同語言開發的XML Web服務之間也可以相互操作。有沒有.NET體驗問題不大,你依舊可以用Visual Basic、Java、甚至是COBOL創建XML Web服務。這種對編程語言的中立性意味著不用為了進入.NET世界而拋棄已有的投資。 ?? ?? ●原先系統無需被替換。一部分的Microsoft .NET產品就是為了能方便地將現有的系統整合到新,的XML Web服務和.NET體驗中去而設計的。Host Integration Server就是個例子,它簡化了對主機的訪問。再比如就是BizTalk Server,它管理的商務流程(business process orchestration)包括了對現有系統和數據格式的支持,并會執行一些必要的轉換,將數據轉成XML。 ?? ?? 所以這種下一代的分布式計算是建立在目前這一代基礎上的。Microsoft .NET不是我們所想象的那樣,對現在的應用軟件作大規模的替換,而是一個自然的進化過程,在原先的技術孤島之間建立了協作關系,協同工作能力逐漸加強,我們也將從中受益無窮。 ?? ?? 總結 ?? ?? Microsoft .NET是Microsoft的XML Web服務的平臺。這是下一代的Internet計算模型,各個XML Web服務之間彼此是松耦合的,通過XML進行通訊,協同完成某一特定的任務。Microsoft .NET戰略提供了一個用以建立新.NET體驗的軟件平臺、一個編程模型、用以建立和整合XML Web服務的工具以及一套可編程的Web接口。 ?? ?? 現在我們正處于向.NET轉變的過程中。Microsoft已經宣布了.NET框架的第一個部分--.NET平臺、Visual Studio.NET和一些塊構建服務以及最初的.NET體驗。Microsoft在今年和明年中將會提供更多的工具和服務。 | [1]
|
|
posted @
2006-09-28 11:03 Bourne 閱讀(279) |
評論 (0) |
編輯 收藏
原型:extern void *memcpy(void *dest, void *src, unsigned int count);
用法:#include <string.h>
功能:由src所指內存區域復制count個字節到dest所指內存區域。
說明:src和dest所指內存區域不能重疊,函數返回指向dest的指針。
舉例:
// memcpy.c
#include <syslib.h>
#include <string.h>
main()
{
char *s="Golden Global View";
char d[20];
clrscr();
memcpy(d,s,strlen(s));
d[strlen(s)]=0;
printf("%s",d);
getchar();
return 0;
}
原型:extern char *strchr(char *s,char c);
用法:#include <string.h>
功能:查找字符串s中首次出現字符c的位置
說明:返回首次出現c的位置的指針,如果s中不存在c則返回NULL。
舉例:
// strchr.c
#include <syslib.h>
#include <string.h>
main()
{
char *s="Golden Global View";
char *p;
clrscr();
strchr(s,'V');
if(p)
printf("%s",p);
else
printf("Not Found!");
getchar();
return 0;
}
1 復制
?
char* strcpy (char *s1, const char *s2);
將字符串s2復制到s1指定的地址
?
char* strncpy (char *s1, const char *s2, size_t len);
void* ?memcpy (void *s1, const void *s2, size_t len);
將s2的前len個字符(字節)復制到s1中指定的地址, 不加'\0'
?
void* memmove (void *s1, const void *s2, size_t len);
當源單元和目的單元緩沖區交迭時使用
?
size_t strxfrm (char *s1, const char *s1, size_t len);
根據程序當前的區域選項, 將s2的前len個字符(字節)復制到s1中指定的地址, 不加'\0'
?
2 連接
?
char* strcat (char *s1, const char *s2);
將字符串s2連接到s1尾部
?
char* strncat (char *s1, const char *s2, size_t len);
將字符串s2的前len個字符連接到s1尾部, 不加'\0'
?
3 比較
?
int strcmp (const char *s1, const char *s2);
比較字符串s1和s2
?
int strncmp (const char *s1, const char *s2, size_t len);
int ?memcmp (const void *s1, const void *s2, size_t len);
對s1和s2的前len個字符(字節)作比較
?
int strcoll (const char *s1, const char *s2);
根據程序當前的區域選項中的LC_COLLATE, 比較字符串s1和s2
?
4 查找
?
char* strchr (const char *s, int ch);
void* memchr (const void *s, int ch, size_t len);
在s中查找給定字符(字節值)ch第一次出現的位置
?
char* strrchr (const char *s, int ch);
在串s中查找給定字符ch最后一次出現的位置, r表示從串尾開始
?
char* strstr (const char *s1, const char *s2);
在串s1中查找指定字符串s2第一次出現的位置
?
size_t strspn (const char *s1, const char *s2);
返回s1中第一個在s2中不存在的字符的索引(find_first_not_of)
?
size_t strcspn (const char *s1, const char *s2);
返回s1中第一個也在s2中存在的字符的索引(find_first_of)
?
char* strpbrk (const char *s1, const char *s2);
與strcspn類似, 區別是返回指針而不是索引
?
char* strtok (char *s1, const char *s2);
從串s1中分離出由串s2中指定的分界符分隔開的記號(token)
第一次調用時s1為需分割的字串, 此后每次調用都將s1置為NULL,
每次調用strtok返回一個記號, 直到返回NULL為止
?
5 其他
?
size_t strlen (const char *s);
求字符串s的長度
?
void* memset (void *s, int val, size_t len);
將從s開始的len個字節置為val
?
char* strerror (int errno);
返回指向錯誤信息字符串的指針
?
source: 《C & C++ Code Capsules》
posted @
2006-07-28 10:35 Bourne 閱讀(270) |
評論 (0) |
編輯 收藏
#i nclude <stdio.h>
#i nclude <stdlib.h>
#i nclude <string.h>
#i nclude <time.h>
//獲得prefix數組
int* GetPrefixValue(char* strPattern, int iPatternLen)
{
??? int i, j; /* i runs through the string, j counts the hits*/
??? int* prefix = (int*)malloc(iPatternLen*sizeof(int));
???
??? i = 1; j = 0;
??? prefix[0] = 0;
???
??? while(i<iPatternLen)
??? {
??????? if(strPattern[i] == strPattern[j])
??????? {
??????????? prefix[i] = ++j;
??????? }
??????? else
??????? {
??????????? j = 0;
??????????? prefix[i] = j;
??????? }
???????
??????? i++;
??? }
???
??? return prefix;??????????
}???
//返回target串在pattern串中第一次匹配的index
int KMPStringMatch(char* strPattern, int iPatternLen, char* strTarget, int iTargetLen, int* prefix)
{
??? int i = 0;
??? int j = 0;
???
??? while(i<iPatternLen && j<iTargetLen)
??? {
??????? if(j==0 || strPattern[i]==strTarget[j])
??????? {
??????????? i++;? j++;
??????? }
??????? else
??????? {
??????????? j = prefix[j];
??????? }
??? }????????????
???
??? free(prefix);
????
??? if(j==iTargetLen)
??? {
??????? return i-j;
??? }
??? else
??? {
??????? return -1;
??? }????????
}????????
int KMP(char* strPattern, char* strTarget)
{
??? int* prefix = GetPrefixValue(strPattern, strlen(strPattern));
??? int index = KMPStringMatch(strPattern, strlen(strPattern), strTarget, strlen(strTarget), prefix);
??? return index;
}
//在文本文件中查找target串出現的行數
int SearchInTxtFile(char* fileName, char* strTarget)
{
??? FILE* hFile = fopen(fileName, "r");
???
??? char str[1024];
??? int count = 0;
???
???
??? while(fgets(str, 1024, hFile))?
??? {
??????? if(KMP(str, strTarget)!=-1)
??????? {
??????????? count++;
??????? }???
??? }?????
???
??? fclose(hFile);
??? hFile=NULL;
???
??? return count;
}????
????????????
int main()
{
??? char ch;
??? char str1[] = "abcabcabctasksb,abTo";
??? char str2[] = "abc";
???
??? double t=clock();
??? printf("%d\n", KMP(str1,str2));
??? printf("耗時:%f毫秒!\n", (clock()-t));
???
??? t=clock();
??? printf("find %d \n", SearchInTxtFile("c:\\txt.txt", "NULL"));
??? printf("耗時:%f毫秒!\n", (clock()-t));
??? scanf("%c", &ch);
??? return 0;
}?
posted @
2006-07-05 23:48 Bourne 閱讀(4777) |
評論 (4) |
編輯 收藏
摘要:
本文從介紹基礎概念入手,探討了在C/C++中對日期和時間操作所用到的數據結構和函數,并對計時、時間的獲取、時間的計算和顯示格式等方面進行了闡述。本文還通過大量的實例向你展示了time.h頭文件中聲明的各種函數和數據結構的詳細使用方法。
關鍵字:UTC(世界標準時間),Calendar Time(日歷時間),epoch(時間點),clock tick(時鐘計時單元)
1.概念
在C/C++中,對字符串的操作有很多值得注意的問題,同樣,C/C++對時間的操作也有許多值得大家注意的地方。最近,在技術群中有很多網友也多次問到過C++語言中對時間的操作、獲取和顯示等等的問題。下面,在這篇文章中,筆者將主要介紹在C/C++中時間和日期的使用方法.
通過學習許多C/C++庫,你可以有很多操作、使用時間的方法。但在這之前你需要了解一些“時間”和“日期”的概念,主要有以下幾個:
Coordinated Universal Time(UTC):協調世界時,又稱為世界標準時間,也就是大家所熟知的格林威治標準時間(Greenwich Mean Time,GMT)。比如,中國內地的時間與UTC的時差為+8,也就是UTC+8。美國是UTC-5。
Calendar Time:日歷時間,是用“從一個標準時間點到此時的時間經過的秒數”來表示的時間。這個標準時間點對不同的編譯器來說會有所不同,但對一個編譯系統來說,這個標準時間點是不變的,該編譯系統中的時間對應的日歷時間都通過該標準時間點來衡量,所以可以說日歷時間是“相對時間”,但是無論你在哪一個時區,在同一時刻對同一個標準時間點來說,日歷時間都是一樣的。
epoch:時間點。時間點在標準C/C++中是一個整數,它用此時的時間和標準時間點相差的秒數(即日歷時間)來表示。
clock tick:時鐘計時單元(而不把它叫做時鐘滴答次數),一個時鐘計時單元的時間長短是由CPU控制的。一個clock tick不是CPU的一個時鐘周期,而是C/C++的一個基本計時單位。
我們可以使用ANSI標準庫中的time.h頭文件。這個頭文件中定義的時間和日期所使用的方法,無論是在結構定義,還是命名,都具有明顯的C語言風格。下面,我將說明在C/C++中怎樣使用日期的時間功能。
2. 計時
C/C++中的計時函數是clock(),而與其相關的數據類型是clock_t。在MSDN中,查得對clock函數定義如下:
clock_t clock( void );
這個函數返回從“開啟這個程序進程”到“程序中調用clock()函數”時之間的CPU時鐘計時單元(clock tick)數,在MSDN中稱之為掛鐘時間(wal-clock)。其中clock_t是用來保存時間的數據類型,在time.h文件中,我們可以找到對它的定義:
#ifndef _CLOCK_T_DEFINED
typedef long clock_t;
#define _CLOCK_T_DEFINED
#endif
很明顯,clock_t是一個長整形數。在time.h文件中,還定義了一個常量CLOCKS_PER_SEC,它用來表示一秒鐘會有多少個時鐘計時單元,其定義如下:
#define CLOCKS_PER_SEC ((clock_t)1000)
可以看到每過千分之一秒(1毫秒),調用clock()函數返回的值就加1。下面舉個例子,你可以使用公式clock()/CLOCKS_PER_SEC來計算一個進程自身的運行時間:
void elapsed_time()
{
printf("Elapsed time:%u secs.\n",clock()/CLOCKS_PER_SEC);
}
當然,你也可以用clock函數來計算你的機器運行一個循環或者處理其它事件到底花了多少時間:
#include “stdio.h”
#include “stdlib.h”
#include “time.h”
int main( void )
{
???long????i = 10000000L;
???clock_t start, finish;
???double??duration;
???/* 測量一個事件持續的時間*/
???printf( "Time to do %ld empty loops is ", i );
???start = clock();
???while( i-- )??????;
???finish = clock();
???duration = (double)(finish - start) / CLOCKS_PER_SEC;
???printf( "%f seconds\n", duration );
???system("pause");
}
在筆者的機器上,運行結果如下:
Time to do 10000000 empty loops is 0.03000 seconds
上面我們看到時鐘計時單元的長度為1毫秒,那么計時的精度也為1毫秒,那么我們可不可以通過改變CLOCKS_PER_SEC的定義,通過把它定義的大一些,從而使計時精度更高呢?通過嘗試,你會發現這樣是不行的。在標準C/C++中,最小的計時單位是一毫秒。
3.與日期和時間相關的數據結構
在標準C/C++中,我們可通過tm結構來獲得日期和時間,tm結構在time.h中的定義如下:
#ifndef _TM_DEFINED
struct tm {
????????int tm_sec;?????/* 秒 – 取值區間為[0,59] */
????????int tm_min;?????/* 分 - 取值區間為[0,59] */
????????int tm_hour;????/* 時 - 取值區間為[0,23] */
????????int tm_mday;????/* 一個月中的日期 - 取值區間為[1,31] */
????????int tm_mon;?????/* 月份(從一月開始,0代表一月) - 取值區間為[0,11] */
????????int tm_year;????/* 年份,其值等于實際年份減去1900 */
????????int tm_wday;????/* 星期 – 取值區間為[0,6],其中0代表星期天,1代表星期一,以此類推 */
????????int tm_yday;????/* 從每年的1月1日開始的天數 – 取值區間為[0,365],其中0代表1月1日,1代表1月2日,以此類推 */
????????int tm_isdst;???/* 夏令時標識符,實行夏令時的時候,tm_isdst為正。不實行夏令時的進候,tm_isdst為0;不了解情況時,tm_isdst()為負。*/
????????};
#define _TM_DEFINED
#endif
ANSI C標準稱使用tm結構的這種時間表示為分解時間(broken-down time)。
而日歷時間(Calendar Time)是通過time_t數據類型來表示的,用time_t表示的時間(日歷時間)是從一個時間點(例如:1970年1月1日0時0分0秒)到此時的秒數。在time.h中,我們也可以看到time_t是一個長整型數:
#ifndef _TIME_T_DEFINED
typedef long time_t;?????????/* 時間值 */
#define _TIME_T_DEFINED??????/* 避免重復定義 time_t */
#endif
大家可能會產生疑問:既然time_t實際上是長整型,到未來的某一天,從一個時間點(一般是1970年1月1日0時0分0秒)到那時的秒數(即日歷時間)超出了長整形所能表示的數的范圍怎么辦?對time_t數據類型的值來說,它所表示的時間不能晚于2038年1月18日19時14分07秒。為了能夠表示更久遠的時間,一些編譯器廠商引入了64位甚至更長的整形數來保存日歷時間。比如微軟在Visual C++中采用了__time64_t數據類型來保存日歷時間,并通過_time64()函數來獲得日歷時間(而不是通過使用32位字的time()函數),這樣就可以通過該數據類型保存3001年1月1日0時0分0秒(不包括該時間點)之前的時間。
在time.h頭文件中,我們還可以看到一些函數,它們都是以time_t為參數類型或返回值類型的函數:
double difftime(time_t time1, time_t time0);
time_t mktime(struct tm * timeptr);
time_t time(time_t * timer);
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);
此外,time.h還提供了兩種不同的函數將日歷時間(一個用time_t表示的整數)轉換為我們平時看到的把年月日時分秒分開顯示的時間格式tm:
struct tm * gmtime(const time_t *timer);??????????????????????????????????????????
struct tm * localtime(const time_t * timer);
通過查閱MSDN,我們可以知道Microsoft C/C++ 7.0中時間點的值(time_t對象的值)是從1899年12月31日0時0分0秒到該時間點所經過的秒數,而其它各種版本的Microsoft C/C++和所有不同版本的Visual C++都是計算的從1970年1月1日0時0分0秒到該時間點所經過的秒數。
4.與日期和時間相關的函數及應用
在本節,我將向大家展示怎樣利用time.h中聲明的函數對時間進行操作。這些操作包括取當前時間、計算時間間隔、以不同的形式顯示時間等內容。
4.1 獲得日歷時間
我們可以通過time()函數來獲得日歷時間(Calendar Time),其原型為:
time_t time(time_t * timer);
如果你已經聲明了參數timer,你可以從參數timer返回現在的日歷時間,同時也可以通過返回值返回現在的日歷時間,即從一個時間點(例如:1970年1月1日0時0分0秒)到現在此時的秒數。如果參數為空(NUL),函數將只通過返回值返回現在的日歷時間,比如下面這個例子用來顯示當前的日歷時間:
#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
lt =time(NUL);
printf("The Calendar Time now is %d\n",lt);
return 0;
}
運行的結果與當時的時間有關,我當時運行的結果是:
The Calendar Time now is 1122707619
其中1122707619就是我運行程序時的日歷時間。即從1970年1月1日0時0分0秒到此時的秒數。
4.2 獲得日期和時間
這里說的日期和時間就是我們平時所說的年、月、日、時、分、秒等信息。從第2節我們已經知道這些信息都保存在一個名為tm的結構體中,那么如何將一個日歷時間保存為一個tm結構的對象呢?
其中可以使用的函數是gmtime()和localtime(),這兩個函數的原型為:
struct tm * gmtime(const time_t *timer);??????????????????????????????????????????
struct tm * localtime(const time_t * timer);
其中gmtime()函數是將日歷時間轉化為世界標準時間(即格林尼治時間),并返回一個tm結構體來保存這個時間,而localtime()函數是將日歷時間轉化為本地時間。比如現在用gmtime()函數獲得的世界標準時間是2005年7月30日7點18分20秒,那么我用localtime()函數在中國地區獲得的本地時間會比世界標準時間晚8個小時,即2005年7月30日15點18分20秒。下面是個例子:
#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *local;
time_t t;
t=time(NUL);
local=localtime(&t);
printf("Local hour is: %d\n",local->tm_hour);
local=gmtime(&t);
printf("UTC hour is: %d\n",local->tm_hour);
return 0;
}
運行結果是:
Local hour is: 15
UTC hour is: 7
4.3 固定的時間格式
我們可以通過asctime()函數和ctime()函數將時間以固定的格式顯示出來,兩者的返回值都是char*型的字符串。返回的時間格式為:
星期幾 月份 日期 時:分:秒 年\n\0
例如:Wed Jan 02 02:03:55 1980\n\0
其中\n是一個換行符,\0是一個空字符,表示字符串結束。下面是兩個函數的原型:
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);
其中asctime()函數是通過tm結構來生成具有固定格式的保存時間信息的字符串,而ctime()是通過日歷時間來生成時間字符串。這樣的話,asctime()函數只是把tm結構對象中的各個域填到時間字符串的相應位置就行了,而ctime()函數需要先參照本地的時間設置,把日歷時間轉化為本地時間,然后再生成格式化后的字符串。在下面,如果t是一個非空的time_t變量的話,那么:
printf(ctime(&t));
等價于:
struct tm *ptr;
ptr=localtime(&t);
printf(asctime(ptr));
那么,下面這個程序的兩條printf語句輸出的結果就是不同的了(除非你將本地時區設為世界標準時間所在的時區):
#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
lt =time(NUL);
ptr=gmtime(<);
printf(asctime(ptr));
printf(ctime(<));
return 0;
}
運行結果:
Sat Jul 30 08:43:03 2005
Sat Jul 30 16:43:03 2005
4.4 自定義時間格式
我們可以使用strftime()函數將時間格式化為我們想要的格式。它的原型如下:
size_t strftime(
???char *strDest,
???size_t maxsize,
???const char *format,
???const struct tm *timeptr
);
我們可以根據format指向字符串中格式命令把timeptr中保存的時間信息放在strDest指向的字符串中,最多向strDest中存放maxsize個字符。該函數返回向strDest指向的字符串中放置的字符數。
函數strftime()的操作有些類似于sprintf():識別以百分號(%)開始的格式命令集合,格式化輸出結果放在一個字符串中。格式化命令說明串strDest中各種日期和時間信息的確切表示方法。格式串中的其他字符原樣放進串中。格式命令列在下面,它們是區分大小寫的。
%a 星期幾的簡寫
%A 星期幾的全稱
%b 月分的簡寫
%B 月份的全稱
%c 標準的日期的時間串
%C 年份的后兩位數字
%d 十進制表示的每月的第幾天
%D 月/天/年
%e 在兩字符域中,十進制表示的每月的第幾天
%F 年-月-日
%g 年份的后兩位數字,使用基于周的年
%G 年分,使用基于周的年
%h 簡寫的月份名
%H 24小時制的小時
%I 12小時制的小時
%j 十進制表示的每年的第幾天
%m 十進制表示的月份
%M 十時制表示的分鐘數
%n 新行符
%p 本地的AM或PM的等價顯示
%r 12小時的時間
%R 顯示小時和分鐘:hh:mm
%S 十進制的秒數
%t 水平制表符
%T 顯示時分秒:hh:mm:ss
%u 每周的第幾天,星期一為第一天 (值從0到6,星期一為0)
%U 第年的第幾周,把星期日做為第一天(值從0到53)
%V 每年的第幾周,使用基于周的年
%w 十進制表示的星期幾(值從0到6,星期天為0)
%W 每年的第幾周,把星期一做為第一天(值從0到53)
%x 標準的日期串
%X 標準的時間串
%y 不帶世紀的十進制年份(值從0到99)
%Y 帶世紀部分的十進制年份
%z,%Z 時區名稱,如果不能得到時區名稱則返回空字符。
%% 百分號
如果想顯示現在是幾點了,并以12小時制顯示,就象下面這段程序:
#include “time.h”
#include “stdio.h”
int main(void)
{
struct tm *ptr;
time_t lt;
char str[80];
lt=time(NUL);
ptr=localtime(<);
strftime(str,100,"It is now %I %p",ptr);
printf(str);
return 0;
}
其運行結果為:
It is now 4PM
而下面的程序則顯示當前的完整日期:
#include <stdio.h>
#include <time.h>
void main( void )
{
????????struct tm *newtime;
????????char tmpbuf[128];
????????time_t lt1;
????????time( <1 );
????????newtime=localtime(<1);
????????strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);
????????printf(tmpbuf);
}
運行結果:
Today is Saturday, day 30 of July in the year 2005.
4.5 計算持續時間的長度
有時候在實際應用中要計算一個事件持續的時間長度,比如計算打字速度。在第1節計時部分中,我已經用clock函數舉了一個例子。Clock()函數可以精確到毫秒級。同時,我們也可以使用difftime()函數,但它只能精確到秒。該函數的定義如下:
double difftime(time_t time1, time_t time0);
雖然該函數返回的以秒計算的時間間隔是double類型的,但這并不說明該時間具有同double一樣的精確度,這是由它的參數覺得的(time_t是以秒為單位計算的)。比如下面一段程序:
#include "time.h"
#include "stdio.h"
#include "stdlib.h"
int main(void)
{
time_t start,end;
start = time(NUL);
system("pause");
end = time(NUL);
printf("The pause used %f seconds.\n",difftime(end,start));//<-
system("pause");
return 0;
}
運行結果為:
請按任意鍵繼續. . .
The pause used 2.000000 seconds.
請按任意鍵繼續. . .
可以想像,暫停的時間并不那么巧是整整2秒鐘。其實,你將上面程序的帶有“//<-”注釋的一行用下面的一行代碼替換:
printf("The pause used %f seconds.\n",end-start);
其運行結果是一樣的。
4.6 分解時間轉化為日歷時間
這里說的分解時間就是以年、月、日、時、分、秒等分量保存的時間結構,在C/C++中是tm結構。我們可以使用mktime()函數將用tm結構表示的時間轉化為日歷時間。其函數原型如下:
time_t mktime(struct tm * timeptr);
其返回值就是轉化后的日歷時間。這樣我們就可以先制定一個分解時間,然后對這個時間進行操作了,下面的例子可以計算出1997年7月1日是星期幾:
#include "time.h"
#include "stdio.h"
#include "stdlib.h"
int main(void)
{
struct tm t;
time_t t_of_day;
t.tm_year=1997-1900;
t.tm_mon=6;
t.tm_mday=1;
t.tm_hour=0;
t.tm_min=0;
t.tm_sec=1;
t.tm_isdst=0;
t_of_day=mktime(&t);
printf(ctime(&t_of_day));
return 0;
}
運行結果:
Tue Jul 01 00:00:01 1997
現在注意了,有了mktime()函數,是不是我們可以操作現在之前的任何時間呢?你可以通過這種辦法算出1945年8月15號是星期幾嗎?答案是否定的。因為這個時間在1970年1月1日之前,所以在大多數編譯器中,這樣的程序雖然可以編譯通過,但運行時會異常終止。
5.總結
本文介紹了標準C/C++中的有關日期和時間的概念,并通過各種實例講述了這些函數和數據結構的使用方法。筆者認為,和時間相關的一些概念是相當重要的,理解這些概念是理解各種時間格式的轉換的基礎,更是應用這些函數和數據結構的基礎。
參考文獻
[1] 標準C++程序設計教程,電子工業出版社,2003。
[2] MSDN Library, Microsoft Corporation,2003。
posted @
2006-07-05 12:12 Bourne 閱讀(3843) |
評論 (1) |
編輯 收藏
上網搜東西的時候搜到了這個,覺得蠻使用的,放在這里以備后用!
--??LINK2001
學習VC++時經常會遇到鏈接錯誤LNK2001,該錯誤非常討厭,因為對于
編程者來說,最好改的錯誤莫過于編譯錯誤,而一般說來發生連接錯誤時,
編譯都已通過。產生連接錯誤的原因非常多,尤其LNK2001錯誤,常常使人不
明其所以然。如果不深入地學習和理解VC++,要想改正連接錯誤LNK2001非
常困難。
初學者在學習VC++的過程中,遇到的LNK2001錯誤的錯誤消息主要為:
unresolved external symbol “symbol”(不確定的外部“符號”)。
如果連接程序不能在所有的庫和目標文件內找到所引用的函數、變量或
標簽,將產生此錯誤消息。一般來說,發生錯誤的原因有兩個:一是所引用
的函數、變量不存在、拼寫不正確或者使用錯誤;其次可能使用了不同版本
的連接庫。
以下是可能產生LNK2001錯誤的原因:
一.由于編碼錯誤導致的LNK2001。
1.不相匹配的程序代碼或模塊定義(.DEF)文件能導致LNK2001。例如,
如果在C++ 源文件內聲明了一變量“var1”,卻試圖在另一文件內以變量
“VAR1”訪問該變量,將發生該錯誤。
2.如果使用的內聯函數是在.CPP文件內定義的,而不是在頭文件內定
義將導致LNK2001錯誤。
3.調用函數時如果所用的參數類型同函數聲明時的類型不符將會產生
LNK2001。
4.試圖從基類的構造函數或析構函數中調用虛擬函數時將會導致LNK2001。
5.要注意函數和變量的可公用性,只有全局變量、函數是可公用的。
靜態函數和靜態變量具有相同的使用范圍限制。當試圖從文件外部訪問
任何沒有在該文件內聲明的靜態變量時將導致編譯錯誤或LNK2001。
函數內聲明的變量(局部變量) 只能在該函數的范圍內使用。
C++ 的全局常量只有靜態連接性能。這不同于C,如果試圖在C++的
多個文件內使用全局變量也會產生LNK2001錯誤。一種解決的方法是需要時在
頭文件中加入該常量的初始化代碼,并在.CPP文件中包含該頭文件;另一種
方法是使用時給該變量賦以常數。
二.由于編譯和鏈接的設置而造成的LNK2001
1.如果編譯時使用的是/NOD(/NODEFAULTLIB)選項,程序所需要的運行
庫和MFC庫在連接時由編譯器寫入目標文件模塊, 但除非在文件中明確包含
這些庫名,否則這些庫不會被鏈接進工程文件。在這種情況下使用/NOD將導
致錯誤LNK2001。
2.如果沒有為wWinMainCRTStartup設定程序入口,在使用Unicode和MFC
時將得到“unresolved external on _WinMain@16”的LNK2001錯誤信息。
3.使用/MD選項編譯時,既然所有的運行庫都被保留在動態鏈接庫之內,
源文件中對“func”的引用,在目標文件里即對“__imp__func” 的引用。
如果試圖使用靜態庫LIBC.LIB或LIBCMT.LIB進行連接,將在__imp__func上發
生LNK2001;如果不使用/MD選項編譯,在使用MSVCxx.LIB連接時也會發生LNK2001。
4.使用/ML選項編譯時,如用LIBCMT.LIB鏈接會在_errno上發生LNK2001。
5.當編譯調試版的應用程序時,如果采用發行版模態庫進行連接也會產
生LNK2001;同樣,使用調試版模態庫連接發行版應用程序時也會產生相同的
問題。
6.不同版本的庫和編譯器的混合使用也能產生問題,因為新版的庫里可
能包含早先的版本沒有的符號和說明。
7.在不同的模塊使用內聯和非內聯的編譯選項能夠導致LNK2001。如果
創建C++庫時打開了函數內聯(/Ob1或/Ob2),但是在描述該函數的相應頭
文件里卻關閉了函數內聯(沒有inline關鍵字),這時將得到該錯誤信息。
為避免該問題的發生,應該在相應的頭文件中用inline關鍵字標志內聯函數。
8.不正確的/SUBSYSTEM或/ENTRY設置也能導致LNK2001。
其實,產生LNK2001的原因還有很多,以上的原因只是一部分而已,對初
學者來說這些就夠理解一陣子了。但是,分析錯誤原因的目的是為了避免錯
誤的發生。LNK2001錯誤雖然比較困難,但是只要注意到了上述問題,還是能
夠避免和予以解決的。
posted @
2006-06-20 16:36 Bourne 閱讀(2476) |
評論 (2) |
編輯 收藏
還是我做的那個鏈表的模板類
我分別寫了頭文件Chain.h,源文件Chain.cpp,并且在main.cpp中進行測試。
但是在連接的時候出現了問題,不知道什么原因,希望能夠有高手指點一下,非常感謝!
其中Chain.h聲明了類的數據成員和成員函數,具體內容如下:
#ifndef _CHAIN_H
#define _CHAIN_H
#include <iostream>
using namespace std;
template<class T>
class Chain;
template<class T>
class ChainNode
{
?friend class Chain<T>;
?friend ostream& operator<<(ostream& out, const Chain<T>& x);
private:
?T data;
?ChainNode<T> *link;
};
template<class T>
class Chain{
public:
?Chain(int p) {first = 0;};
?~Chain();
?bool IsEmpty() const {return first == 0;}
?int Length() const;
?bool Find(int k, T& x) const;
?int Search(const T& x) const;
?//Chain<T>& Delete(int k, T& x);
?Chain<T>& Insert(int k, const T& x);
?void Output(ostream& out = cout) const;
private:
?ChainNode<T> *first; // 指向第一個節點的指針
};
template<class T>
ostream& operator<<(ostream& out, const Chain<T>& x);
#endif? // _CHAIN
??在Chain.cpp中對Chain.h中聲明的函數進行了定義,具體內容如下:
#include "Chain.h"
#include <iostream>
using namespace std;
template<class T>
Chain<T>::~Chain()
{
?//鏈表的析構函數,用于刪除鏈表中的所有節點
?ChainNode<T> *ptr = first;
?while (ptr)
?{
??first = ptr->link;
??delete ptr;
??ptr = first;
?}
}
template<class T>
int Chain<T>::Length() const
{
?//返回鏈表中的元素總數
?int count = 0;
?ChainNode<T> *ptr = first;
?while (ptr)
?{
??++count;
??ptr = ptr->link;
?}
?return count;
}
template<class T>
bool Chain<T>::Find(int k, T& x) const
{
?//尋找鏈表中的第k個元素,并將其傳送至x
?//如果不存在第k個元素,則返回false,否則返回true
?if (k < 1)
?{
??return false;
?}
?int count = k;
?ChainNode<T> *ptr = first;
?while (count && ptr)
?{
??--count;
??ptr = ptr->link
?}
?if (!ptr)
?{
??return false;
?}
?x = ptr->data;
?return true;
}
template<class T>
int Chain<T>::Search(const T& x) const
{
?//尋找x,如果發現x,則返回x的地址
?//如果x不在鏈表中,則返回0
?int count = 1;
?ChainNode<T> *ptr = first;
?while(ptr && (ptr->data!=x))
?{
??++count;
??ptr = ptr->link;
?}
?if (ptr)
?{
??return count;
?}
?else
?{
??return 0;
?}
}
template<class T>
void Chain<T>::Output(ostream& out = cout) const
{
?ChainNode<T> *ptr = first;
?while (ptr)
?{
??out<<ptr->data<<"? ";
??ptr = ptr->link;
?}
}
//重載<<運算符
template<class T>
ostream& operator<<(ostream& out, const Chain<T>& x)
{
?x.Output(out);
?return out;
}
template<class T>
Chain<T>& Chain<T>::Insert(int k, const T& x)
{
?ChainNode<T> *ptr = first;
?int count = 0;
?while (ptr && count < k)
?{
??++count;
??ptr = ptr->link;
?}
?if (!ptr)? //如果沒到第k個節點
?{
?
?}
?else
?{
??//要插入的新節點
??ChainNode<T>* cn = new ChainNode<T>;
??cn->data = x;
??cn->link = 0;
??if (ptr->link==0)? //到達了鏈表的結尾
??{
???ptr->link = cn;
??}
??else? //沒到達結尾
??{?
???cn->link = ptr->link;
???ptr->link = cn;
??}
?}
?return *this
}
?在main.cpp中進行測試,測試的內容很少,但是剛開始就進行不了了。main.cpp內容如下:
#include "Chain.h"
using namespace std;
int main()
{
?Chain<int> c;
?cout<<c.Length();
?return 0;
}
編譯的時候沒有問題,但是在連接的時候就出現了問題,報錯如下:
--------------------Configuration: Chain - Win32 Debug--------------------
Linking...
main.obj : error LNK2001: unresolved external symbol "public: __thiscall Chain<int>::~Chain<int>(void)" (??1?$Chain@H@@QAE@XZ)
main.obj : error LNK2001: unresolved external symbol "public: int __thiscall Chain<int>::Length(void)const " (?Length@?$Chain@H@@QBEHXZ)
Debug/Chain.exe : fatal error LNK1120: 2 unresolved externals
Error executing link.exe.
Chain.exe - 3 error(s), 0 warning(s)
但是從報錯信息來看,應該是在main.cpp中沒有找到所用到的函數 ~Chain<int>(void)和Length()的定義,在main.cpp中一共用到了三個函數,構造函數Chain(),但是構造函數是在Chain.h中定義的,所以編譯器找到了其定義,但是另外兩個函數是在Chain.cpp中定義的,而且目前報錯沒有找到,但是如果在main.cpp中引入#include "Chain.cpp"時,編譯和連接就沒有問題,這就證實了原來的估計是沒有錯的。我實在是不知道問題出現在哪里,所以希望哪位高手看出問題來的話,請告訴我,多謝了!
posted @
2006-06-19 16:56 Bourne 閱讀(841) |
評論 (4) |
編輯 收藏
以前寫代碼的時候就遇到VC++對友元支持得不太好的問題,同時也看過侯捷老師對gnu c++, VC++, BCB 三種編譯器的比較,其中VC++對模板友元的支持就不是很好。
今天晚上寫了一個比較簡單的鏈表的模板類,其中頭文件Chain.h原來的代碼如下:
#include <iostream>
using namespace std;
#ifndef _CHAIN
#define _CHAIN
template<class T>
class?ChainNode
{
?friend class Chain<T>;
private:
?T data;
?ChainNode<T> *link;
};
template<class T>
class Chain{
public:
?Chain()
?{
??first = 0;
?};
?~Chain();
?bool IsEmpty() const {return first == 0;}
?int Length() const;
?bool Find(int k, T& x) const;
?int Search(const T& x) const;
?//Chain<T>& Delete(int k, T& x);
?Chain<T>& Insert(int k, const T& x);
?void Output(ostream& out = cout) const;
private:
?ChainNode<T> *first; // 指向第一個節點的指針
};
#endif? // _CHAIN
結果報錯:
--------------------Configuration: Chain - Win32 Debug--------------------
Compiling...
Chain.cpp
g:\work plan\c++ code practice\chain\chain.h(17) : error C2059: syntax error : '<'
??????? g:\work plan\c++ code practice\chain\chain.h(21) : see reference to class template instantiation 'ChainNode<T>' being compiled
g:\work plan\c++ code practice\chain\chain.h(17) : error C2238: unexpected token(s) preceding ';'
??????? g:\work plan\c++ code practice\chain\chain.h(21) : see reference to class template instantiation 'ChainNode<T>' being compiled
g:\work plan\c++ code practice\chain\chain.h(40) : error C2989: 'Chain' : template class has already been defined as a non-template class
??????? g:\work plan\c++ code practice\chain\chain.h(17) : see declaration of 'Chain'
g:\work plan\c++ code practice\chain\chain.cpp(6) : error C2059: syntax error : '<'
g:\work plan\c++ code practice\chain\chain.cpp(6) : error C2588: '::~Chain' : illegal global destructor
g:\work plan\c++ code practice\chain\chain.cpp(6) : fatal error C1903: unable to recover from previous error(s); stopping compilation
Error executing cl.exe.
Chain.obj - 6 error(s), 0 warning(s)
感覺從代碼來看應該是沒有問題的,如果哪個高手看出問題來了請一定告訴我啊,如果知道編譯不通過的原因也請一定要告訴我啊。沒辦法,最后采用解決的辦法就是修改ChainNode的定義了,定義為結構體:)
template<class T>
struct ChainNode
{
? T data;
? ChainNode<T> *link;
};
反正結構體中的數據成員都是public的,至于訪問限制的實現就依靠迭代器來實現了,g++的STL中的樹結點不也是結構體嗎?:)
posted @
2006-06-17 23:39 Bourne 閱讀(2643) |
評論 (4) |
編輯 收藏