CString用法總結


 

  概述:CString是MFC中提供的用於處理字符串的類,是一種很有用的數據類型。

  它很大程度上簡化了MFC中的許多操作,使得MFC在做字符串操作時方便了很多。

  不管怎樣,使用CString有很多的特殊技巧,特別對於純C背景下走出來的程序員來說有點難以學習。

 

一、前言

  CString位於頭文件afx.h中,這篇文章就來討論這些技巧。

  參考百度百科並截取部分對我有用的內容記錄在這篇隨筆中,這篇文章包括以下內容:

    <1>CString對象的連接

    <2>格式化字符串(包括int轉化為CString)

    <3>CString類的成員函數

    <4>CString轉化為int型

    <5>CString和char*的相互轉化

        char*轉化為CString

        CString轉化為char*之一:使用LPCTSTR

        CString轉化為char*之二:使用CString對象的GetBuffer方法

        CString轉化為char*之三:和控件的接口

 

 

二、對象連接

  CString類重載了+運算符,因此CString對象能對直接使用+號進行連接。而不再使用strcat函數 

    CString s1, s2, s3;
    s1 = _T("Hello");
    s2 = _T("World");
    s3 = s1 + _T(",") + s2 +_T("!");
    MessageBox(s3);
View Code

  注意:MFC編程中,為了兼容Unicode編碼,字符串盡量都使用_T()宏

 

三、格式化字符串

  可以利用CString的Format方法使用C風格字符串格式化一個CString對象,而不再使用sprintf函數

        CString str;

    int dollar = 100;
    str.Format(_T("I have %d dollars\n"), dollar);    
View Code

 

四、成員函數

  1.構造函數

    CString有很多構造函數,下面只介紹幾個常用的:

    (注意函數原型的變量名都是我自己起的,源碼中名字可能不是這個名字,不過不影響)

    (另一個類對象引用名采用other, 字符個數采用n)

    <1>用已存在的 CString對象 初始化CString對象

       函數原型: CString(const CString& other);

    <2>可以使用常量字符串初始化CString對象

      函數原型: CString(const LPCTSTR other);  //這個原型是我猜的

      實例: CString str(_T("Hello,World!"));

    <3>將字符串other中的前n個字符拷貝到該CString對象

      函數原型: CString(LPCTSTR other,int n);

      實例: CString str(_T("Hello,World! this is redundant\n"), 12);

    <4>用n個字母ch初始化CString對象

      函數原型:CString(TCHAR ch,int n = 1);

      實例: CString str('6', 6);  //str初始化為6個6,即666666

    //構造函數
    CString s1 = _T("Hello,World!");    //用字符串初始化CString類對象
    CString s2 = s1;    //用CString類對象初始化CString類對象
    CString s3(s1, 5);    //用s1的前5個字符初始化類對象
    CString s4(_T("Hello,World!"), 5);    //用字符串的前n個字符初始化類對象
    CString s5(_T('6'), 5);    //用n個給定的字符初始化類對象

    MessageBox(s1);    //輸出Hello,World!
    MessageBox(s2);    //輸出Hello,World!
    MessageBox(s3);    //輸出Hello
    MessageBox(s4);    //輸出Hello
    MessageBox(s5);    //輸出66666
View Code

  注意:在初始化時使用=運算符調用的是相應類型的構造函數,而不是重載的=運算符,

     此外,部分構造函數無法寫成=的形式,比如使用n個ch初始化CString對象,使用字符串的前n個字符初始化類對象等

  

  2.CString類的大小寫轉換及順序轉換函數

    <1> 將字符串中的所有大寫字符轉換為小寫字符

      函數原型:CString& MakeLower();

    <2>將字符串中的所有小寫字符轉換為大寫字符

      函數原型:CString& MakeUpper();

    <3>將字符串中所有字符的順序顛倒

      函數原型:CString& MakeReverse()

    <4>要做相應操作,則使用類對象調用相應函數,那么該對象的值便被修改

    //CString類的大小寫轉換及順序轉換函數
    CString s1 = _T("aaBBCCddEe");

    s1.MakeLower();
    MessageBox(s1);    //輸出 aabbccddee
    s1.MakeUpper();
    MessageBox(s1);    //輸出 AABBCCDDEE
    MessageBox(s1.MakeLower().MakeReverse());    //輸出eeddccbbaa
    MessageBox(s1);    //輸出eeddccbbaa
View Code

 

  3.CString對象的連接

    多個CString對象的連接可以通過重載運算符+、+=實現。

    詳細參見上面的內容(二、對象連接)

    //CString對象的連接
    CString s1 = _T("Hello");
    CString s2 = _T("World!");

    MessageBox(s1 + _T(",") + s2 + _T("!"));    //輸出Hello,World!
    
    s1 += _T(",");
    s1 += s2;
    s1 += _T("!");    //s1內容變為Hello,World!
    MessageBox(s1);    //輸出Hello,World!
View Code

 

  4.CString對象的比較

    CString對象的比較可以通過==、!=、<;、>;、<=、>=等重載運算符實現,也可以使用Compare和CompareNoCase成員函數實現。

    <1>==,!=,<,>,<=,>=都是根據ASCII值大小(字符串的字典序)進行比較,

      返回值為0或1,1表示使用的比較運算符判斷成立。

    <2>Compare函數類似strcmp函數,相等返回0,

      小於傳進來的參數則返回小於0的數,大於傳進來的參數則返回大於0的數

    <3>CompareNoCase類似Compare,只是不區分大小寫。

    //CString對象的比較
    CString s1 = _T("aabbcc");
    CString s2 = _T("aabbdd");
    CString s3 = _T("AAbbcc");
    CString s4 = _T("aabbcc");

    //部分運算符用法
    int a1 = (s1 == s2);    //s1 != s2,a1為0
    int a2 = (s1 != s2);    //s1 != s2,a2為1
    int a3 = (s1 <= s3);    //s1 > s3, a3為0, 注意大寫字母的ASCII碼比較小

    CString str1, str2, str3;
    str1.Format(_T("%d"), a1);
    str2.Format(_T("%d"), a2);
    str3.Format(_T("%d"), a3);
    MessageBox(str1);
    MessageBox(str2);
    MessageBox(str3);

    //Compare用法
    int a4 = s1.Compare(s2);    //s1 < s2,a4為-1
    int a5 = s1.Compare(s3);    //s1 > s2,a5為1
    int a6 = s1.Compare(s4);    //s1 = s2,a6為0

    CString str4,str5,str6;
    str4.Format(_T("%d"), a4);
    str5.Format(_T("%d"), a5);
    str6.Format(_T("%d"), a6);
    MessageBox(str4);
    MessageBox(str5);
    MessageBox(str6);


    //CompareNoCase用法
    int a7 = s1.CompareNoCase(s2);    //不區分大小寫, s1 < s2, a7 = -1
    int a8 = s1.CompareNoCase(s3);    //不區分大小寫, s1 = s2, a8 = 0
    int a9 = s1.CompareNoCase(s4);    //不區分大小寫, s1 = s2, a9 = 0

    CString str7, str8, str9;
    str7.Format(_T("%d"), a7);
    str8.Format(_T("%d"), a8);
    str9.Format(_T("%d"), a9);
    MessageBox(str7);
    MessageBox(str8);
    MessageBox(str9);
View Code

  

  5.CString對象字符串的提取操作

    <1>提取該字符串左邊nCount個字符的子字符串,並返回一個包含這個子字符串的拷貝的CString對象

      函數原型:CString Left(int nCount) const;

    <2>提取該字符串右邊nCount個字符的子字符串,並返回一個包含這個子字符串的拷貝的CString對象

      函數原型:CString Right(int nCount) const;
    <3>提取該字符串中以索引iFirst位置開始的nCount個字符組成的子字符串,並返回一個包含這個子字符串的拷貝的CString對象
      函數原型:
CString Mid(int iFirst,int nCount) const;
    提取該字符串中以索引iFirst位置開始直至字符串結尾的子字符串,並返回一個包含這個子字符串的拷貝的CString對象
      函數原型:CString Mid(int iFirst) const;
 
 
    //CString對象字符串的提取操作
    CString s1 = _T("aabbccddee");

    MessageBox(s1.Left(4));    //左邊四個字符,輸出aabb
    MessageBox(s1.Right(4));    //右邊4個字符,輸出ddee
    MessageBox(s1.Mid(4, 2));    //輸出從第4個位置開始的兩個字符,即輸出cc
    MessageBox(s1.Mid(4));    //輸出從第4個位置開始到結尾的子串,即輸出ccddee
View Code
 

  6.CString對象字符串的查找操作

    <1>在CString對象字符串的iStart索引位置開始,查找子字符串pszSub或字符ch第一次出現的位置,如果沒有找到則返回-1
        int Find(PCXSTR pszSub,int iStart=0) const throw();  //查找子串第一次出現位置
        int Find(XCHAR ch,int iStart=0) const throw();    //查找某字符第一次出現位置
    <2>查找pszCharSet字符串中的任意字符,返回第一次出現的位置,找不到則返回-1
        int FindOneOf(PCXSTR pszCharSet) const throw();  //查找給定字符串中的任意一個字符在原串的第一次出現位置
    <3>從字符串末尾開始查找指定的字符ch,返回其位置,找不到則返回-1。這里要注意,盡管是從后向前查找,但是位置的索引還是要從開始算起
        int ReverseFind(XCHAR ch) const throw();
    //CString對象字符串的查找操作
    CString s1 = _T("aabbccbbaa");

    //查找子串
    int p1 = s1.Find(_T("aa"));    //第二個參數默認為0, 故p1為0,
    int p2 = s1.Find(_T("aa"), 1);    //從下表為1開始往后找子串aa, 故p2為8
    int p3 = s1.Find(_T("abc"));    //未找到,返回-1,即-1

    CString str1, str2, str3;
    str1.Format(_T("%d"), p1);
    str2.Format(_T("%d"), p2);
    str3.Format(_T("%d"), p3);
    MessageBox(str1);
    MessageBox(str2);
    MessageBox(str3);

    //查找字符
    int p4 = s1.Find(_T('b'));    //第二個參數默認為0,p4為2
    int p5 = s1.Find(_T('b'), 4);    //從標為4的位置開始往后找,p5為6
    int p6 = s1.Find(_T('c'), 6);    //未找到,p6為-1

    CString str4, str5, str6;
    str4.Format(_T("%d"), p4);
    str5.Format(_T("%d"), p5);
    str6.Format(_T("%d"), p6);
    MessageBox(str4);
    MessageBox(str5);
    MessageBox(str6);
View Code
  
  7.CString類對象字符串的替換與刪除
    <1>用字符串pszNew替換CString對象中的子字符串pszOld,返回替換的字符串個數
        int Replace(PCXSTR pszOld,PCXSTR pszNew);    //替換子串
    //使用Replace替換子串
    CString s1 = _T("aabbccddaabbccdd");
    int cnt = s1.Replace(_T("aa"), _T("##"));
    CString s2;
    s2.Format(_T("%d"), cnt);
    MessageBox(s1);    //輸出##bbccdd##bbccdd
    MessageBox(s2);    //輸出2
View Code
    <2>用字符chNew替換CString對象中的字符chOld,返回替換的字符個數
        int Replace(XCHAR chOld,XCHAR chNew);    //替換字符
    //使用Replace替換字符
    CString s1 = _T("aabbccddaabbccdd");
    int cnt = s1.Replace('a', '#');
    CString s2;
    s2.Format(_T("%d"), cnt);

    MessageBox(s1);    //輸出##bbccdd##bbccdd
    MessageBox(s2);    //輸出4
View Code
    <3>從字符串中刪除iIndex位置開始的nCount個字符,返回刪除操作后的字符串的長度
        int Delete(int iIndex,int nCount = 1);
    //使用Delete刪除字符
    CString s1 = _T("aabbccdd");
    int len = s1.Delete(2, 2);    //刪除bb,len應為6
    CString s2;
    s2.Format(_T("%d"), len);

    MessageBox(s1);        //輸出aaccdd
    MessageBox(s2);        //輸出6
View Code
    <4>刪除字符串中的所有由chRemove指定的字符,返回刪除的字符個數。
        int Remove(XCHAR chRemove);
    //使用Remove刪除字符
    CString s1 = _T("aabbccdd");
    int len = s1.Remove(_T('b'));    //len為刪除字符個數,應該為2
    CString s2;
    s2.Format(_T("%d"), len);

    MessageBox(s1);    //輸出aaccdd
    MessageBox(s2);    //輸出2
View Code

 

  8.CString類的格式化字符串方法
    <1>使用CString類的Format成員函數可以將int、short、long、float、double等數據類型格式化為字符串對象。
      函數原型: void __cdecl Format(PCXSTR pszFormat,[,argument]...);
    <2>參數pszFormat為格式控制字符串;參數argument可選,為要格式化的數據,
      一般每個argument在pszFormat中都有對應的表示其類型的子字符串,int型的argument對應的應該是"%d",float型的應對應"%f",等等
    //CString類格式化字符串的方法
    CString s1, s2;
    int cnt = 100;
    const double PI = 3.141592653;
    s1.Format(_T("I have %d dollars!"), cnt);
    s2.Format(_T("PI is approximate to %.2f!"), PI);

    MessageBox(s1); //輸出I have 100 dollars!
    MessageBox(s2);    //輸出PI is approximate to 3.14!
View Code
 
  9.做編譯原理作業時,需要用到Insert方法,特地去查詢了一下,特此補充:
    <1>函數原型
      int Insert(int iIndex, PCXSTR psz);
      int Insert(int iIndex, XCHAR ch);
    <2>參數說明
      iIndex 要往該位置之前插入字符或字符串
      psz  要插入的字符串
      ch   要插入的字符
    <3>返回新的CString的長度
    <4>iIndex 參數標識是移動騰出空間。字符或子字符串的第一個字符。
      如果 nIndex 為零,在整個字符串之前發生。如果 nIndex 高於該字符串的長度,函數將連接 ch 或 psz和新材料提供的當前字符串
    CString s1 = _T(", World!");
    s1.Insert(0, _T("Hello")); //s1為"Hello, World!"
    MessageBox(s1);

    CString s2 = _T("ello, World!");
    s2.Insert(0, _T('H'));    //s2為"Hello, World!"
    MessageBox(s2);
View Code
 
五、int型
  把 CString 類型的數據轉化成整數類型最簡單的方法就是使用標准的字符串到整數轉換例程
  <1>雖然通常你懷疑使用_atoi()函數是一個好的選擇,它也很少會是一個正確的選擇
  <2>如果你准備使用 Unicode 字符,你應該用_ttoi(),它在 ANSI 編碼系統中被編譯成_atoi(),而在 Unicode 編碼系統中編譯成_wtoi()。
     注意:第一個參數為要轉化的字符串,第二個參數為結尾位置,一般設置為NULL,第三個為需要轉化的參數
  <3>你也可以考慮使用_tcstoul()或者_tcstol(),它們都能把字符串轉化成任意進制的長整數(如二進制、八進制、十進制或十六進制),
    不同 點在於前者轉化后的數據是無符號的(unsigned),而后者相反。
    CString s1 = _T("123");
    int n1 = _ttoi(s1);    //
    unsigned long long n2 = _tcstoul(s1, 0, 10);    //結果123
    long long n3 = _tcstol(s1, 0, 8);    //結果為83,八進制123的十進制為83

    CString str1, str2, str3;
    str1.Format(_T("%d"), n1);
    str2.Format(_T("%llu"), n2);
    str3.Format(_T("%lld"), n3);
    MessageBox(str1);
    MessageBox(str2);
    MessageBox(str3);
View Code
 
 
六、CString和char*的相互轉化
  1.char*轉化為CString 
//char*和CString
    CString s1 = _T("Hello,World!");

    CString s2;
    s2.Format(_T("Hello,World!"));
View Code

  2.CString轉化為char*

    <1>強制類型轉換為 LPCTSTR

      A.這是一種略微硬性的轉換,有關"正確"的做法,人們在認識上還存在許多混亂,

      正確的使用方法有很多,但錯誤的使用方法可能與正確的使用方法一樣多。

      我們首先要了解 CString 是一種很特殊的 C++ 對象,它里面包含了三個值:
      一個指向某個數據緩沖區的指針、一個是該緩沖中有效的字符記數以及一個緩沖區長度。
      有效字符數的大小可以是從0到該緩沖最大長度值減1之間的任何數(因為字符串結尾有一個NULL字符)。
      字符記數和緩沖區長度被巧妙隱藏。
      除非你做一些特殊的操作,否則你不可能知道給CString對象分配的緩沖區的長度。
      這樣,即使你獲得了該0緩沖的地址,你也無法更改其中的內容,不能截短字符串,也 絕對沒有辦法加長它的內容,否則第一時間就會看到溢出。
      LPCTSTR 操作符(或者更明確地說就是 TCHAR * 操作符)在 CString 類中被重載了,該操作符的定義是返回緩沖區的地址,
      因此,如果你需要一個指向 CString 的 字符串指針的話,可以這樣做:
        CString s("GrayCat");
        LPCTSTR p = s;  //是指針常量,不可更改其值
      它可以正確地運行。這是由C語言的強制類型轉化規則實現的。當需要強制類型轉化時,C++規則容許這種選擇。
      
      B.如果你要格式化字符串怎么辦呢?
        CString graycat("GrayCat");
        CString s;
        s.Format("Mew! I love %s",graycat);  //注意這里使用的是類對象而沒有使用顯示轉換
      注意由於在可變參數列表中的值(在函數說明中是以"..."表示的)並沒有隱含一個強制類型轉換操作符。你會得到什么結果呢?
      一個令人驚訝的結果,我們得到的實際結果串是:
        "Mew! I love GrayCat"。
      因為 MFC 的設計者們在設計 CString數據類型時非常小心, CString 類型 表達式求值后指向了字符串,
      所以這里看不到任何象 Format 或 sprintf 中的強制類型轉換,你仍然可以得到正確的行為。
      描述 CString 的附加數據實際上在 CString 名義地址之后。(名即代表地址)
 
      C.有一件事情你是不能做的,那就是修改字符串,因為返回的是指針常量。
    
    <2>CString轉化成char* 之二:使用 CString 對象的 GetBuffer 方法
      
      A.如果你需要修改 CString 中的內容,它有一個特殊的方法可以使用,那就是 GetBuffer,
      它的作用是返回一個可寫的緩沖 指針
      如果你只是打算修改 字符或者截短字符串,你完全可以這樣做:
        CString s(_T("File.ext"));
        LPTSTR p = s.GetBuffer();
        LPTSTR dot = strchr(p,.); // OK,should have used s.Find...
        if(p != NULL)
          *p = _T(\0);
        s.ReleaseBuffer();
      這是 GetBuffer 的第一種用法,也是最簡單的一種,
      不用給它傳遞參數,它使用默認值 0,意思是:"給我這個字符串的 指針,我保證不加長它"。
      當你調用 ReleaseBuffer 時,字符串的實際長度會被重新計算,然后存入 CString 對象中。
 
      B.必須強調一點,在 GetBuffer 和 ReleaseBuffer 之間這個范圍,一定不能使用你要操作的這個緩沖的 CString 對象的任何方法。
       因為 ReleaseBuffer 被調用之前,該 CString 對象的完整性得不到保障。研究以下代碼:
          CString s(...);
          LPTSTR p = s.GetBuffer();
          //... 這個 指針p 發生了很多事情
          int n = s.GetLength(); // 很糟D!!!!! 有可能給出錯誤的答案!!!
          s.TrimRight(); // 很糟!!!!! 不能保證能正常工作!!!!
          s.ReleaseBuffer(); // 應該 OK
          int m = s.GetLength(); // 這個結果可以保證是正確的。
          s.TrimRight(); // 將正常工作。
      
      C.假設你想增加字符串的長度,你首先要知道這個字符串可能會有多長,好比是聲明字符串 數組的時候用:
          char buffer[1024];
       表示 1024 個字符空間足以讓你做任何想做得事情。
       在 CString 中與之意義相等的表示法:
          LPTSTR p = s.GetBuffer(1024);
       調用這個函數后,你不僅獲得了 字符緩沖區指針,而且同時還獲得了長度至少為 1024 個字符的空間
      (注意,我說的是"字符",而不是"字節",因為 CString 是以隱含方式感知 Unicode 的)。
    
      D.同時,還應該注意的是,如果你有一個 常量串指針,這個串本身的值被存儲在只讀內存中,
       如果試圖存儲它,即使你已經調用了 GetBuffer ,並獲得一個只讀內存的指針,存入操作會失敗,並報告存取錯誤。
       我沒有在 CString 上證明這一點,但我看到過大把的 C 程序員經常犯這個錯誤。
      
      E.C 程序員有一個通病是分配一個固定長度的緩沖,對它進行 sprintf 操作,然后將它賦值給一個 CString:
          char buffer[256];
          sprintf(buffer,"%......",args,...); // ... 部分省略許多細節
          CString s = buffer;
       雖然更好的形式可以這么做:
          CString s;
          s.Format(_T("%...."),args,...);
       如果你的 字符串長度萬一超過 256 個字符的時候,不會破壞 堆棧
       另外一個常見的錯誤是:既然固定大小的內存不工作,那么就采用動態分配字節,這種做法弊端更大:
          int len = lstrlen(parm1) + 13 lstrlen(parm2) + 10 + 100;
          char * buffer = new char[len];
          sprintf(buffer,"%s is equal to %s,valid data",parm1,parm2);
          CString s = buffer;
          ......
          delete [] buffer;
       它可以能被簡單地寫成:
          CString s;
          s.Format(_T("%s is equal to %s,valid data"),parm1,parm2);
       需要注意 sprintf 例子都不是 Unicode 就緒的,盡管你可以使用 tsprintf 以及用 _T() 來包圍格式化字符串,
       但是基本 思路仍然是在走彎路,這這樣很容易出錯。

 

  參考:百度百科


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM