• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Beginning to 編程

            VC++ 方面編程文章

             

            轉(zhuǎn)換大小寫C函數(shù)

            ?

            Richard zeng? 3/19/2006 10:50:36 AM

            ?

            這幾天又把以前的 C 課程翻了出來(lái) , 因?yàn)樽约簩?duì) C 的指針和數(shù)組不是很 DEV.

            模擬 C 庫(kù)函數(shù)中的轉(zhuǎn)化大小寫函數(shù) .

            ?

            // 轉(zhuǎn)換成大寫 , 函數(shù)參數(shù)為字符數(shù)組

            // 利用字符串?dāng)?shù)組的結(jié)尾都是 \0

            void ToUpper(chars[])

            {

            ?????? int i=0;

            ?????? while(s[i++]!='\0' )

            ?????? {

            ????????????? // 判斷是否是小寫字母

            ????????????? if(s[i]>='a' && s[i]<='z' )

            ???????????????????? s[i] -= 32;???? // 小寫字母比大寫字母的 ASCII 32

            ?????? }

            }

            ?

            // 轉(zhuǎn)換成大寫 , 函數(shù)參數(shù)為字符指針

            void ToUpperPtr(char* s)

            {

            ?????? while(*s != '\0')

            ?????? {

            // 判斷是否是小寫字母

            ????????????? if(*s >='a' && *s <='z')

            ???????????????????? *s -= 32; ???? // 小寫字母比大寫字母的 ASCII 32

            ????????????? s++; // 指針的地址 ++

            ?????? }

            }

            posted @ 2006-03-19 10:56 Beginning to 編程 閱讀(5846) | 評(píng)論 (5)編輯 收藏

            波形顯示不是很難 /zhuan

            封裝了一下波形顯示,發(fā)現(xiàn)不是很難


            WaveShow_src.rar

            posted @ 2006-03-16 11:00 Beginning to 編程 閱讀(614) | 評(píng)論 (1)編輯 收藏

            大小寫轉(zhuǎn)換的方法【C/C++】 /zhuan

            ASCII碼表大家都很熟悉了吧,利用碼的排列規(guī)律,我們可以很容易的實(shí)現(xiàn)一些操作,比如判斷是否是數(shù)字、大小寫轉(zhuǎn)換等。
            這里寫大小寫轉(zhuǎn)換的函數(shù):
            char toUpper(const char& ch)
            {
                return ch & 0x5F;
            }
            char toLower(const char& ch)
            {
                return ch | 0x20;
            }
             
            函數(shù)原理:大小寫字母的差是32,比如大寫的A是65,小寫的A是97,所以我們把右邊數(shù)第6位置0或者1就能實(shí)現(xiàn)大小寫轉(zhuǎn)換。轉(zhuǎn)換成大寫時(shí),把第6位置0,用ch & 0x5F實(shí)現(xiàn)。轉(zhuǎn)換成小寫時(shí)置1,用ch | 0x20實(shí)現(xiàn)。怎么樣,相當(dāng)?shù)暮?jiǎn)單吧,由此,我們可以寫string類的toUpper和toLower函數(shù)了。^_^,更多技巧盡在探索中。

            posted @ 2006-03-15 13:31 Beginning to 編程 閱讀(949) | 評(píng)論 (0)編輯 收藏

            淺談CMPP協(xié)議(一) /zhuan

                CMPP協(xié)議的全稱是中國(guó)移動(dòng)通信互聯(lián)網(wǎng)短信網(wǎng)關(guān)接口協(xié)議,它是聯(lián)想亞信公司根據(jù)SMMP協(xié)議為中國(guó)移動(dòng)量身定做的,是符合中國(guó)國(guó)情的一個(gè)短信協(xié)議,閑話不多說(shuō)了,說(shuō)說(shuō)CMPP的主要功能吧。(1)短信發(fā)送(short message mobile originate)MO,就是手機(jī)給SP發(fā)短信;(2)短信接受(short message mobile terminated)MT,這個(gè)就是SP給手機(jī)發(fā)的短信了,通常我們手機(jī)上收到的不良短信就是SP給我們的MT。CMPP協(xié)議的通信基礎(chǔ)是TCP/IP為底層通信承載的,連接方式是長(zhǎng)連接方式。SP與ISMG之間,SMSC和ISMG之間的交互過(guò)程中均采用異步方式,即任一個(gè)網(wǎng)元在收到請(qǐng)求消息后應(yīng)立即回應(yīng)。
               下面看看它的消息定義:CMPP中的消息分為消息頭和消息體。消息頭定義如下
             
             

            字段名

            字節(jié)數(shù)

            類型

            描述

            Total_Length  

            4

            Unsigned Integer

            消息總長(zhǎng)度(含消息頭及消息體)

            Command_Id

            4

            Unsigned Integer

            命令或響應(yīng)類型

            Sequence_Id

            4

            Unsigned Integer

            消息流水號(hào),順序累加,步長(zhǎng)為1,循環(huán)使用(一對(duì)請(qǐng)求和應(yīng)答消息的流水號(hào)必須相同)

             
            那么下面就是SP連接到ISMG上了,看它的Bind連接消息定義
             

            字段名

            字節(jié)數(shù)

            屬性

            描述

            Source_Addr 

            6

            Octet String

            源地址,此處為SP_Id,即SP的企業(yè)代碼。

            AuthenticatorSource

            16

            Octet String

            用于鑒別源地址。其值通過(guò)單向MD5 hash計(jì)算得出,表示如下:

            AuthenticatorSource =

            MD5Source_Addr+9 字節(jié)的0 +shared secret+timestamp

            Shared secret 由中國(guó)移動(dòng)與源地址實(shí)體事先商定,timestamp格式為:MMDDHHMMSS,即月日時(shí)分秒,10位。

            Version

            1

            Unsigned Integer

            雙方協(xié)商的版本號(hào)(高位4bit表示主版本號(hào),低位4bit表示次版本號(hào)),對(duì)于3.0的版本,高4bit3,低4位為0

            Timestamp

            4

            Unsigned Integer

            時(shí)間戳的明文,由客戶端產(chǎn)生,格式為MMDDHHMMSS,即月日時(shí)分秒,10位數(shù)字的整型,右對(duì)齊

             
            根據(jù)上的定義我們可以寫出的代碼,如下,在VC環(huán)境下編寫的

            /*
             *函數(shù)功能:建立和CMPP網(wǎng)關(guān)的直接通路
             *輸入條件:SP用戶名const char *UserName,SP密碼const char *PWD 
             */
            void Ccmpp_API::CmppConnect(const char *UserName, const char *PWD)
            {
             char netbuf[100];
             CMPP_CONNECT *bufer;
             bufer=(CMPP_CONNECT*)netbuf;
             memset(bufer, 0, 100);
             bufer->nTotalLength = htonl(39);//CMPP_CONNECT消息總長(zhǎng)度
             bufer->nCommandId = htonl(CMPP_CONNECT_tag);//消息標(biāo)志
             //自動(dòng)產(chǎn)生SeqId號(hào)
                if (sequenceid == 123456789i32)
             {
              sequenceid = 1;
             }else{
              sequenceid++;
             }
             bufer->nSeqId = htonl(sequenceid);
               
             int MD5Len;
             MD5_CTX md5;//MD5源字串
             CTime TimeData = CTime::GetCurrentTime();
             CString timestamp = TimeData.Format("%m%d%H%M%S");
             unsigned char md5source[29];
             int Len1 = strlen(UserName);
             int Len2 = strlen(PWD); 
             MD5Len = Len1 + 9 +Len2 + timestamp.GetLength();
             memset(md5source, 0, MD5Len);
             
             memcpy(bufer->sSourceAddr, UserName, Len1);
             memcpy(md5source, UserName, Len1);
             
             for (int j = 0; j<Len2; j++)
             {
              md5source[j + Len1 + 9] = PWD[j];
             }
             for (int i=0;i<timestamp.GetLength();i++)
             {
              md5source[i + Len2 + Len1 + 9]=timestamp[i];
             }
             
             //進(jìn)行md5加密轉(zhuǎn)換
             md5.MD5Update(md5source, MD5Len);
             md5.MD5Final(md5source);
             memcpy(bufer->sAuthSource, md5source, 29);
             bufer->cVersion = 0x30;
             bufer->nTimeStamp = htonl(atoi(timestamp));
             CmppSocket.Send(bufer, 39, 0);//把消息打包發(fā)送
             return;
            }
             
            今天就到這,下次再寫,歡迎交流!
            posted on 2006-03-15 07:58 炙熱的太陽(yáng) 閱讀(38) 評(píng)論(2)  編輯 收藏 收藏至365Key


            FeedBack:

            # re: 淺談CMPP協(xié)議(一)
            2006-03-15 10:38 | 小明
            you say:
            SP與ISMG之間,SMSC和ISMG之間的交互過(guò)程中均采用異步方式,即任一個(gè)網(wǎng)元在收到請(qǐng)求消息后應(yīng)立即回應(yīng)。

            既然是異步方式,就不是收到請(qǐng)求后立即回應(yīng),否則就是同步方式了

            據(jù)我所知,CMPP采用的基于滑動(dòng)窗口的異步方式,默認(rèn)情況下可以發(fā)最多16的CMPP package,而不必等待他們的resp.  回復(fù)
              
            # re: 淺談CMPP協(xié)議(一)
            2006-03-15 11:21 | 炙熱的太陽(yáng)
            是的,你說(shuō)的沒(méi)有錯(cuò)。

            消息是采用并發(fā)方式發(fā)送,加以滑動(dòng)窗口流量控制,窗口大小參數(shù)W可配置,現(xiàn)階段的配置為16,即接收方在應(yīng)答前一次收到的消息最多不超過(guò)16條。這是它們之間的通信方式。

            而SP與ISMG之間,SMSC和ISMG之間的交互過(guò)程中均采用異步方式,即任一個(gè)網(wǎng)元在收到請(qǐng)求消息后應(yīng)立即回應(yīng)。這是它們交互過(guò)程中的應(yīng)答方式。即收到一個(gè)消息就應(yīng)該回一個(gè)回應(yīng)消息,而不管對(duì)方是否收到,所以上面講的并沒(méi)有錯(cuò)喲。


              回復(fù)

            posted @ 2006-03-15 12:25 Beginning to 編程 閱讀(871) | 評(píng)論 (0)編輯 收藏

            為什么在VS2005重載輸出運(yùn)算符那么難 /zhuan

                 摘要: 最近在VS2005下實(shí)現(xiàn)一個(gè)模版堆棧時(shí),想重載一下輸出運(yùn)算符。結(jié)果老是遇到問(wèn)題,如何都過(guò)不去,想不想去都不明白。還望高手指教。  一開始同樣的程序在VC2005和VC6.0下編譯都沒(méi)問(wèn)題,但是一到鏈接的時(shí)候就出現(xiàn)問(wèn)題了。都提示如下錯(cuò)誤:       error LNK2019: 無(wú)法解析的外部符號(hào) "cla...  閱讀全文

            posted @ 2006-03-15 11:57 Beginning to 編程 閱讀(1117) | 評(píng)論 (1)編輯 收藏

            VC中回調(diào)函數(shù)使用的變身大法 /zhuan

            對(duì)于回調(diào)函數(shù)的編寫始終是寫特殊處理功能程序時(shí)用到的技巧之一。先介紹一下回調(diào)的使用基本方法與原理。

              1、在這里設(shè):回調(diào)函數(shù)為A()(這是最簡(jiǎn)單的情況,不帶參數(shù),但我們應(yīng)用的實(shí)際情況常常很會(huì)復(fù)雜),使用回調(diào)函數(shù)的操作函數(shù)為B(), 但B函數(shù)是需要參數(shù)的,這個(gè)參數(shù)就是指向函數(shù)A的地址變量,這個(gè)變量一般就是函數(shù)指針。使用方法為:

            int A(char *p); // 回調(diào)函數(shù)
            typedef int(*CallBack)(char *p) ; // 聲明CallBack 類型的函數(shù)指針
            CallBack myCallBack ; // 聲明函數(shù)指針變量
            myCallBack = A; // 得到了函數(shù)A的地址

              B函數(shù)一般會(huì)寫為 B(CallBack lpCall,char * P,........); // 此處省略了p后的參數(shù)形式 。

              所以回調(diào)機(jī)制可解為,函數(shù)B要完成一定功能,但他自己是無(wú)法實(shí)現(xiàn)全部功能的。 需要借助于函數(shù)A來(lái)完成,也就是回調(diào)函數(shù)。B的實(shí)現(xiàn)為:

            B(CallBack lpCall,char *pProvide)
            {
             ........... // B 的自己實(shí)現(xiàn)功能語(yǔ)句
             lpCall(PpProvide); // 借助回調(diào)完成的功能 ,也就是A函數(shù)來(lái)處理的。
             ........... // B 的自己實(shí)現(xiàn)功能語(yǔ)句
            }
            // -------------- 使用例子 -------------
            char *p = "hello!";
            CallBack myCallBack ;
            myCallBack = A ;
            B(A, p);

              以上就是回調(diào)的基本應(yīng)用,本文所說(shuō)的變身,其實(shí)是利用傳入不同的函數(shù)地址,實(shí)現(xiàn)調(diào)用者類與回調(diào)函數(shù)所在類的不同轉(zhuǎn)換。

              1、問(wèn)題描述

              CUploadFile 類完成數(shù)據(jù)上傳,與相應(yīng)的界面進(jìn)度顯示。

              主要函數(shù)Send(...) 和回調(diào)函數(shù) GetCurState() ;

            class CUploadFile : public CDialog
            {
             ......
             int Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath) ;
             static int GetCurState(int nCurDone, int nInAll, void * pParam) ;
             ......
            }
            int CUploadFile ::Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath)
            {
             ... // 導(dǎo)出傳輸數(shù)據(jù)的函數(shù)
             int ret = Upload( (LPSTR)(LPCTSTR)m_strData,
                GetCurState, // 在這個(gè)回調(diào)函數(shù)中處理界面
                this, // CUploadFile 的自身指針 ,也就是pParam 所接受的參數(shù)
                (LPSTR)(LPCTSTR)UploadFilePath,
                "",
                "",
             );
            }
            int CUploadFile ::GetCurState(int nCurData, int nInAll, void * pParam)
            {
             .........
             UploadFile *pThis = (UploadFile *)pParam; // nCurData 當(dāng)前以傳出的數(shù)據(jù)量
             // nInAll 總的數(shù)據(jù)量
             // 有了pThis可以對(duì)界面進(jìn)行各種操作了。
             .............
            }

              但大家仔細(xì)觀察就可以發(fā)現(xiàn),這個(gè)類把數(shù)據(jù)傳送和界面顯示聚和到了一起,不容易得到復(fù)用。而且在復(fù)用過(guò)程中需要改動(dòng)較多的地方 。

              請(qǐng)大家記住現(xiàn)在的回調(diào)函數(shù)傳入的類本身的靜態(tài)成員函數(shù)。

              現(xiàn)在我們把數(shù)據(jù)的傳送和界面的顯示分離。回調(diào)則要傳入的是界面處理類的靜態(tài)函數(shù)。

              界面處理類 CShowGUI,數(shù)據(jù)上傳類 CUploadData

            class CUploadData
            {
             ......
             typedef int(*SetUploadCaller)(int nCurData, int nInAll, void * pParam);
             int UploadFile(LPCTSTR lpFileNamePath,LPVOID lparam,SetUploadCaller Caller );
             // 接受外界出入的參數(shù),主要是回調(diào)函數(shù)的地址通過(guò)參數(shù)Caller,
             int Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath) ;
             ...... // 注意此時(shí)不在需要GetCurState 函數(shù)了 。
            }

            class CShowGUI: public CDialog
            {
             .......
             typedef int(*SetUploadCaller)(int nCurData, int nInAll, void * pParam);
             void SetCallBack(LPCTSTR strPath);
             static int GetCurState(int nCurData, int nInAll, void * pParam) ;
             CUploadData m_Uploa
             d ; // 數(shù)據(jù)上傳類是界面顯示類的一個(gè)成員變量。
             .......
            }

            void CShowGUI :: SetCallBack(LPCTSTR strPath)
            {
             CUploadData myUploadData ;
             SetUploadCaller myCaller; // 聲明一個(gè)函數(shù)指針變量
             myCaller = CurState ; // 取得界面處理函數(shù)的地址
             myUploadData .UploadFile(strPath,this,myCaller); // 界面處理類的函數(shù)傳入,實(shí)現(xiàn)了數(shù)據(jù)傳入與界面處理的分離 .
            }

              通過(guò)上面的演示做到了界面與數(shù)據(jù)的分離,回調(diào)函數(shù)分別扮演了不同角色,所以隨著處理問(wèn)題的不同應(yīng)靈活應(yīng)用,但同樣因?yàn)樘幚頂?shù)據(jù)類不知道界面處理類或外部調(diào)用類的類型,而更無(wú)法靈活地處理界面的不同顯示方式。這方面還希望喜歡鉆研技術(shù)的朋友繼續(xù)研究。陳剛

            posted @ 2006-03-14 17:33 Beginning to 編程 閱讀(319) | 評(píng)論 (0)編輯 收藏

            C++指針探討 (二) 函數(shù)指針 /zhuan

            在C/C++中,數(shù)據(jù)指針是最直接,也最常用的,因此,理解起來(lái)也比較容易。而函數(shù)指針,作為運(yùn)行時(shí)動(dòng)態(tài)調(diào)用(比如回調(diào)函數(shù) CallBack Function)是一種常見(jiàn)的,而且是很好用的手段。

              我們先簡(jiǎn)單的說(shuō)一下函數(shù)指針。(這一部份沒(méi)什么價(jià)值,純是為了引出下一節(jié)的內(nèi)容)
               
             2 常規(guī)函數(shù)指針

                    void(*fp)();

              fp 是一個(gè)典型的函數(shù)指針,用于指向無(wú)參數(shù),無(wú)返回值的函數(shù)。

                    void(*fp2)(int);

              fp2 也是一個(gè)函數(shù)指針,用于指向有一個(gè)整型參數(shù),無(wú)返回值的函數(shù)。
              當(dāng)然,有經(jīng)驗(yàn)人士一般都會(huì)建議使用typedef來(lái)定義函數(shù)指針的類型,如:

                    typedef void(* FP)();
                    FP fp3; 
            // 和上面的fp一樣的定義。

              函數(shù)指針之所以讓初學(xué)者畏懼,最主要的原因是它的括號(hào)太多了;某些用途的函數(shù)指針,往往會(huì)讓人陷在括號(hào)堆中出不來(lái),這里就不舉例了,因?yàn)椴皇潜疚挠懻摰姆秶籺ypedef 方法可以有效的減少括號(hào)的數(shù)量,以及理清層次,所以受到推薦。本文暫時(shí)只考慮簡(jiǎn)單的函數(shù)指針,因此暫不用到typedef。

              假如有如下兩個(gè)函數(shù):

              void f1()
              
            {
                  std::cout 
            << "call f " << std::endl;
              }

              
              
            void f2(int a)
              
            {
                  std::cout 
            << "call f2( " << a << " )" << std::endl;
              }

              現(xiàn)在需要通過(guò)函數(shù)指針來(lái)調(diào)用,我們需要給指針指定函數(shù):

              fp = &f1; // 也可以用:fp = f1;
              fp2= &f2; // 也可以用:fp2= f2;
              void (*fp3)() = &f1; // 也可以用:void (*fp3)() = f1;  
              
            //調(diào)用時(shí)如下:
              fp(); // 或 (*fp)();
              fp2(1); // 或 (*fp2)(1);
              fp3();  // 或 (*fp3)();

              對(duì)于此兩種調(diào)用方法,效果完全一樣,我推薦用前一種。后一種不僅僅是多打了鍵盤,而且也損失了一些靈活性。這里暫且不說(shuō)它。
              
              C++強(qiáng)調(diào)類型安全。也就是說(shuō),不同類型的變量是不能直接賦值的,否則輕則警告,重則報(bào)錯(cuò)。這是一個(gè)很有用的特性,常常能幫我們找到問(wèn)題。因此,有識(shí)之士認(rèn)為,C++中的任何一外警告都不能忽視。甚至有人提出,編譯的時(shí)候不能出現(xiàn)任何警告信息,也就是說(shuō),警告應(yīng)該當(dāng)作錯(cuò)誤一樣處理。
              
              比如,我們把f1賦值給fp2,那么C++編譯器(vc7.1)就會(huì)報(bào)錯(cuò):

              fp2 = &f1; // error C2440: “=” : 無(wú)法從“void (__cdecl *)(void)”轉(zhuǎn)換為“void (__cdecl *)(int)”
              fp1 = &f1; // OK

              這樣,編譯器可以幫我們找出編碼上的錯(cuò)誤,節(jié)省了我們的排錯(cuò)時(shí)間。
              
              考慮一下C++標(biāo)準(zhǔn)模板庫(kù)的sort函數(shù):

              // 快速排序函數(shù)
              template<typename RandomAccessIterator, typename BinaryPredicate>
                 
            void sort(
                    RandomAccessIterator _First, 
            // 需排序數(shù)據(jù)的第一個(gè)元素位置
                    RandomAccessIterator _Last,  // 需排序數(shù)據(jù)的最后一個(gè)元素位置(不參與排序)
                    BinaryPredicate _Comp     // 排序使用的比較算法(可以是函數(shù)指針、函數(shù)對(duì)象等)
                 );

              比如,我們有一個(gè)整型數(shù)組:

              int n[5= {3,2,1,8,9};

              要對(duì)它進(jìn)行升序排序,我們需定義一個(gè)比較函數(shù):

              bool less(int a, int b)
              
            {
                  
            return a < b; 
              }

              然后用:

              sort(n, n+5, less);

              要是想對(duì)它進(jìn)行降序排序,我們只要換一個(gè)比較函數(shù)就可以了。C/C++的標(biāo)準(zhǔn)模板已經(jīng)提供了less和great函數(shù),因此我們可以直接用下面的語(yǔ)句來(lái)比較:  

              sort(n, n+5, great);


              這樣,不需要改變sort函數(shù)的定義,就可以按任意方法進(jìn)行排序,是不是很靈活?  
              這種用法以C++的標(biāo)準(zhǔn)模板庫(kù)(STL)中非常流行。另外,操作系統(tǒng)中也經(jīng)常使用回調(diào)(CallBack)函數(shù),實(shí)際上,所謂回調(diào)函數(shù),本質(zhì)就是函數(shù)指針。

              看起來(lái)很簡(jiǎn)單吧,這是最普通的C語(yǔ)言指針的用法。本來(lái)這是一個(gè)很美妙的事情,但是當(dāng)C++來(lái)臨時(shí),世界就開始變了樣。
              假如,用來(lái)進(jìn)行sort的比較函數(shù)是某個(gè)類的成員,那又如何呢?

            posted @ 2006-03-14 16:44 Beginning to 編程 閱讀(326) | 評(píng)論 (0)編輯 收藏

            C++指針探討 (一)數(shù)據(jù)指針 /zhuan

              指針,在C/C++語(yǔ)言中一直是很受寵的;幾乎找不到一個(gè)不使用指針的C/C++應(yīng)用。用于存儲(chǔ)數(shù)據(jù)和程序的地址,這是指針的基本功能。用于指向整型數(shù),用整數(shù)指針(int*);指向浮點(diǎn)數(shù)用浮點(diǎn)數(shù)指針(float*);指向結(jié)構(gòu),用對(duì)應(yīng)的結(jié)構(gòu)指針(struct xxx *);指向任意地址,用無(wú)類型指針(void*)。
                有時(shí)候,我們需要一些通用的指針。在C語(yǔ)言當(dāng)中,(void*) 可以代表一切;但是在C++中,我們還有一些比較特殊的指針,無(wú)法用(void*)來(lái)表示。事實(shí)上,在C++中,想找到一個(gè)通用的指針,特別是通用的函數(shù)指針簡(jiǎn)直是一個(gè)“不可能任務(wù)”。
               
                C++是一種靜態(tài)類型的語(yǔ)言,類型安全在C++中舉足輕重。在C語(yǔ)言中,你可以用void*來(lái)指向一切;但在C++中,void*并不能指向一切,就算能,也失去了類型安全的意義了。類型安全往往能幫我們找出程序中潛在的一些BUG。
               
                下面我們來(lái)探討一下,C++中如何存儲(chǔ)各種類型數(shù)據(jù)的指針。

            C++指針探討 (一)數(shù)據(jù)指針      沐楓網(wǎng)志
               
                1.  數(shù)據(jù)指針
                 數(shù)據(jù)指針?lè)譃閮煞N:常規(guī)數(shù)據(jù)指針和成員數(shù)據(jù)指針
                 
                1.1 常規(guī)數(shù)據(jù)指針
                 這個(gè)不用說(shuō)明了,和C語(yǔ)言一樣,定義、賦值是很簡(jiǎn)單明了的。常見(jiàn)的有:int*, double* 等等。
                 如:
                 int value = 123;
                 
            int * pn = &value;
               
                 
                1.2 成員數(shù)據(jù)指針
                 有如下的結(jié)構(gòu):
                 struct MyStruct
                 {
                   
            int key;
                   
            int value;
                 };
               
                 現(xiàn)在有一個(gè)結(jié)構(gòu)對(duì)象:
                 MyStruct me;
                 MyStruct* pMe = &me;
               
                 我們需要 value 成員的地址,我們可以:
                 int * pValue = &me.value;
                 //
                 int * pValue = &pMe->value;
               
                 當(dāng)然了,這個(gè)指針仍然是屬于第一種范籌----常規(guī)數(shù)據(jù)指針。
                 
                 好了,我們現(xiàn)在需要一種指針,它指向MyStruct中的任一數(shù)據(jù)成員,那么它應(yīng)該是這樣的子:
                 int MyStruct::* pMV = &MyStruct::value;
                 
            //
                 int MyStruct::* pMK = &MyStruct::key;
               
                 這種指針的用途是用于取得結(jié)構(gòu)成員在結(jié)構(gòu)內(nèi)的地址。我們可以通過(guò)該指針來(lái)訪問(wèn)成員數(shù)據(jù):
                 int value = pMe->*pMV; // 取得pMe的value成員數(shù)據(jù)。
                 int key = me.*pMK; // 取得me的key成員數(shù)據(jù)。
               
                 那么,在什么場(chǎng)合下會(huì)使用到成員數(shù)據(jù)指針呢?
                 確實(shí),成員指針本來(lái)就不是一種很常用的指針。不過(guò),在某些時(shí)候還是很有用處的。我們先來(lái)看看下面的一個(gè)函數(shù):
              int sum(MyStruct* objs, int MyStruct::* pm, int count)
              {
                  
            int result = 0;
                  
            for(int i = 0; i < count; ++i)
                      result 
            += objs[i].*pm;
                  
            return result;
              }
                 
                 這個(gè)函數(shù)的功能是什么,你能看明白嗎?它的功能就是,給定count個(gè)MyStruct結(jié)構(gòu)的指針,計(jì)算出給定成員數(shù)據(jù)的總和。有點(diǎn)拗口對(duì)吧?看看下面的程序,你也許就明白了:
                 
                 MyStruct me[10=
                 {
                  {
            1,2},{3,4},{5,6},{7,8},{9,10},{11,12},{13,14},{15,16},{17,18},{19,20}
                 };
                 
                 
            int sum_value = sum(me, &MyStruct::value, 10);
                 
            //計(jì)算10個(gè)MyStruct結(jié)構(gòu)的value成員的總和: sum_value 值 為 110     (2+4+6+8++20)
                 
                 
            int sum_key = sum(me, &MyStruct::key, 10);
                 
            //計(jì)算10個(gè)MyStruct結(jié)構(gòu)的key成員的總和:   sum_key 值 為 100       (1+3+5+7++19)
               
                 
                 也許,你覺(jué)得用常規(guī)指針也可以做到,而且更易懂。Ok,沒(méi)問(wèn)題:
                 int sum(MyStruct* objs, int count)
                 {
                  
            int result = 0;
                  
            for(int i = 0; i < count; ++i)
                   result 
            += objs[i].value;
                  
            return result;
                 }

                 你是想這么做嗎?但這么做,你只能計(jì)算value,如果要算key的話,你要多寫一個(gè)函數(shù)。有多少個(gè)成員需要計(jì)算的話,你就要寫多少個(gè)函數(shù),多麻煩啊。

            posted @ 2006-03-14 16:43 Beginning to 編程 閱讀(174) | 評(píng)論 (0)編輯 收藏

            C++指針探討 (三) 成員函數(shù)指針 /zhuan

            C語(yǔ)言的指針相當(dāng)?shù)撵`活方便,但也相當(dāng)容易出錯(cuò)。許多C語(yǔ)言初學(xué)者,甚至C語(yǔ)言老鳥都很容易栽倒在C語(yǔ)言的指針下。但不可否認(rèn)的是,指針在C語(yǔ)言中的位置極其重要,也許可以偏激一點(diǎn)的來(lái)說(shuō):沒(méi)有指針的C程序不是真正的C程序。
              然而C++的指針卻常常給我一種束手束腳的感覺(jué)。C++比C語(yǔ)言有更嚴(yán)格的靜態(tài)類型,更加強(qiáng)調(diào)類型安全,強(qiáng)調(diào)編譯時(shí)檢查。因此,對(duì)于C語(yǔ)言中最容易錯(cuò)用的指針,更是不能放過(guò):C++的指針被分成數(shù)據(jù)指針,數(shù)據(jù)成員指針,函數(shù)指針,成員函數(shù)指針,而且不能隨便相互轉(zhuǎn)換。而且這些指針的聲明格式都不一樣:

            數(shù)據(jù)指針 T *
            成員數(shù)據(jù)指針 T::*
            函數(shù)指針 R (*)(...)
            成員函數(shù)指針 R (T::*)(...)

              盡管C++中仍然有萬(wàn)能指針void*,但它卻屬于被批斗的對(duì)象,而且再也不能“萬(wàn)能”了。它不能轉(zhuǎn)換成成員指針。

              這樣一來(lái),C++的指針就變得很尷尬:我們需要一種指針能夠指向同一類型的數(shù)據(jù),不管這個(gè)數(shù)據(jù)是普通數(shù)據(jù),還是成員數(shù)據(jù);我們更需要一種指針能夠指向同一類型的函數(shù),不管這個(gè)函數(shù)是靜態(tài)函數(shù),還是成員函數(shù)。但是沒(méi)有,至少?gòu)默F(xiàn)在的C++標(biāo)準(zhǔn)中,還沒(méi)有看到。
             
            沐楓網(wǎng)志 C++指針探討(三)成員函數(shù)指針

              自從有了類,我們開始按照 數(shù)據(jù)+操作 的方式來(lái)組織數(shù)據(jù)結(jié)構(gòu);自從有了模板,我們又開始把 數(shù)據(jù) 和 算法 分離,以便重用,實(shí)在夠折騰人的。但不管怎么折騰,現(xiàn)在大多數(shù)函數(shù)都不再單身,都嫁給了類,進(jìn)了圍城。可是我們?nèi)匀恍枰軌蜃杂烧{(diào)用這些成員函數(shù)。
              考慮一下windows下的定時(shí)調(diào)用。SetTimer函數(shù)的原型是這樣的:

            UINT_PTR SetTimer(
                HWND hWnd,
                UINT_PTR nIDEvent,
                UINT uElapse,
                TIMERPROC lpTimerFunc
            );
              其中,參數(shù)就不解釋了,這個(gè)函數(shù)估計(jì)大多數(shù)windows開發(fā)人員都知道。lpTimerFunc是個(gè)會(huì)被定時(shí)調(diào)用的函數(shù)指針。假如我們不通過(guò)WM_TIMER消息來(lái)觸發(fā)定時(shí)器,而是通過(guò)lpTimerFunc來(lái)定時(shí)工作,那么我們就只能使用普通函數(shù)或靜態(tài)函數(shù),而無(wú)論如何都不能使用成員函數(shù),哪怕通過(guò)靜態(tài)函數(shù)轉(zhuǎn)調(diào)也不行。

              再考慮一下線程的創(chuàng)建:
            uintptr_t _beginthread( 
               
            void*start_address )( void * ),
               unsigned stack_size,
               
            void *arglist 
            );
              start_address仍然只支持普通函數(shù)。不過(guò)這回好了,它允許回調(diào)函數(shù)一個(gè)void*參數(shù),它將會(huì)arglist作為參數(shù)來(lái)調(diào)用start_address。于是,聰明的C++程序員,就利用arglist傳遞this指針,從而利用靜態(tài)函數(shù)成功的調(diào)用到了成員函數(shù)了:
            class mythread
            {
              
            public:
                
            static void doit(void* pThis)
                
            {
                ((mythread*)pThis)
            ->doit();
                }

                
            void doit(){}
            }
            ;

            main()
            {
              
              mythread
            * pmt = new mythread;
              _beginthread(
            &mythread::doit, 0, (void*)pmt);
              
            }

              但是顯然,C++程序員肯定不會(huì)因此而滿足。這里頭有許多被C++批判的不安定因素。它使用了C++中被認(rèn)為不安全的類型轉(zhuǎn)換,不安全的void*指針,等等等等。但這是系統(tǒng)為C語(yǔ)言留下的調(diào)用接口,這也就認(rèn)了。那么假如,我們就在C++程序中如何來(lái)調(diào)用成員函數(shù)指針呢?
              如下例,我們打算對(duì)vector中的所有類調(diào)用其指定的成員函數(shù):

            #include <vector>
            #include 
            <algorithm>
            #include 
            <functional>
            #include 
            <iostream>
            using namespace std;

            class A
            {
                
            int value;
            public:
                A(
            int v){value = v;}
                
            void doit(){ cout << value << endl;};
                
            static void call_doit(A& rThis)
                
            {
                    rThis.doit();
                }

            }
            ;


            int main()
            {
                vector
            <A> va;
                va.push_back(A(
            1));
                va.push_back(A(
            2));
                va.push_back(A(
            3));
                va.push_back(A(
            4));
                
            //方法1:
                
            //for_each(va.begin(), va.end(), &A::doit); //error
                
            //方法2:
                for_each(va.begin(), va.end(), &A::call_doit);
                
            //方法3:
                for_each(va.begin(), va.end(), mem_fun_ref<void, A>(&A::doit));

                system(
            "Pause");

                
            return 0;
            }

              方法1,編譯不能通過(guò)。for_each只允許具有一個(gè)參數(shù)的函數(shù)指針或函數(shù)對(duì)象,哪怕A::doit默認(rèn)有一個(gè)this指針參數(shù)也不行。不是for_each沒(méi)考慮到這一點(diǎn),而是根本做不到!
              方法2,顯然是受到了beginthread的啟發(fā),使用一個(gè)靜態(tài)函數(shù)來(lái)轉(zhuǎn)調(diào)用,哈哈成功了。但是不爽!這不是C++。
              方法3,呼,好不容易啊,終于用mem_fun_ref包裝成功了成員函數(shù)指針。
              似乎方法3不錯(cuò),又是類型安全的,又可以通用--慢著,首先,它很丑,哪有調(diào)用普通C函數(shù)指針那么漂亮啊(見(jiàn)方法2),用了一大串包裝,又是尖括號(hào)又是圓括號(hào),還少不了&號(hào)!其次,它只能包裝不超過(guò)一個(gè)參數(shù)的函數(shù)!盡管它在for_each中夠用了,但是你要是想用在超過(guò)一個(gè)參數(shù)的場(chǎng)合,那只有一句話:不可能的任務(wù)。

              是的,在標(biāo)準(zhǔn)C++中,這是不可能的任務(wù)。但事情并不總是悲觀的,至少有許多第三方庫(kù)提供了超越mem_fun的包裝。如boost::function等等。但是它也有限制:它所支持的參數(shù)仍然是有限的,只有十多個(gè),盡管夠你用的了;同樣,它也是丑陋的,永遠(yuǎn)不要想它能夠簡(jiǎn)單的用&來(lái)搞定。

              也許,以失去美麗的代價(jià),來(lái)?yè)Q取質(zhì)量上的保證,這也是C++對(duì)于函數(shù)指針的一種無(wú)奈吧……

              期待C++0x版本。它通過(guò)可變模板參數(shù),能夠讓mem_fun的參數(shù)達(dá)到無(wú)限個(gè)……

            --------
               BTW: C++Builder擴(kuò)展了一個(gè)關(guān)鍵字 closure ,允許成員函數(shù)指針如同普通函數(shù)指針一樣使用。也許C++0x能考慮一下……

            posted @ 2006-03-14 16:42 Beginning to 編程 閱讀(343) | 評(píng)論 (0)編輯 收藏

            一些基本的GDI操作BITMAP的方法 /zhuan

                 摘要: 1  2 #ifndef _BITMAP_H 3 #define _BITMAP_H 4  5 #include <windows.h> 6  7 void SaveImage(const char ...  閱讀全文

            posted @ 2006-03-10 11:27 Beginning to 編程 閱讀(1431) | 評(píng)論 (0)編輯 收藏

            僅列出標(biāo)題
            共3頁(yè): 1 2 3 

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(4)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊(cè)

            BlogDev

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            中文精品久久久久人妻| 少妇内射兰兰久久| 伊人久久精品无码二区麻豆| 久久er国产精品免费观看2| 久久天天日天天操综合伊人av| 中文字幕无码免费久久| 国产精品gz久久久| 久久综合狠狠综合久久| 久久亚洲2019中文字幕| 久久er热视频在这里精品| 久久久久久久波多野结衣高潮| 狠狠久久综合| 久久综合久久综合久久| 久久午夜羞羞影院免费观看| 狠狠色丁香婷婷久久综合| 久久精品人妻一区二区三区| 国产精品视频久久| 人妻精品久久久久中文字幕一冢本| 欧洲性大片xxxxx久久久| 大美女久久久久久j久久| 久久综合综合久久狠狠狠97色88| 日韩精品久久无码人妻中文字幕 | 亚洲精品无码久久千人斩| 久久久久久亚洲精品不卡| 久久WWW免费人成—看片| 久久99国产精品99久久 | 精品人妻伦九区久久AAA片69| 国产午夜福利精品久久| 久久婷婷国产麻豆91天堂| 久久国产精品成人片免费| 久久天天躁狠狠躁夜夜躁2O2O| 亚洲精品无码久久久久去q| 亚洲精品无码久久久久sm| 亚洲中文久久精品无码| 精品久久久久久中文字幕大豆网| 亚洲午夜久久久| 欧美日韩精品久久久久| 久久精品国产亚洲av麻豆图片| 久久久久久久综合狠狠综合| 久久精品桃花综合| AV无码久久久久不卡蜜桃|