1. 程式人生 > >【共讀Primer】19.<3.5> 數組-C風格字符串 Page109

【共讀Primer】19.<3.5> 數組-C風格字符串 Page109

lar 空格 特性 world 程序 c++ ges world! 所有

C風格的字符串是指以空字符‘\0’結尾的一個字符串。

這種字符串雖然在C++中兼容,但是極易引起內存安全問題,所以不建議使用。

但是作為一個語言特性,我們應該了解它,這樣才能在碰到的時候做到心中有數。

3.5.4 C標準庫string函數

這裏所說的string函數並不是std::string的函數,而是在C的標準庫中,對C風格字符串進行操作的一些全局函數。

    strlen(p);    //計算p的長度,不計入空字符結尾
    strcmp(p1, p2);    // 比較兩個字符串p1和p2是否相等,相等返回0,p1>p2返回正值, p1<p2返回負值
    strcat(p1, p2); //
將p2附加到p1後,返回p1 strcpy(p1, p2); // 將p2拷貝給p1, 返回p1

觀察以上函數,它們正常運行的基礎條件是在結尾有一個‘\0‘的空字符,如果這個條件沒有達到

,那麽對於上述的任何一個函數來說結果都將是災難性的。

對於下面的兩行代碼來說,返回的結果將是一個未知的值,因為ca這個字符串並沒有以空為結尾。

    char ca[] = {C, +, +};
    cout << strlen(ca) << endl;

比較字符串

在C風格的字符串進行比較的時候我們需要使用到strcmp函數來進行比較,而不是直接使用邏輯判斷符號進行比較

    // 使用C++的string類型進行比較
    string s1 = "A string example";
    string s2 = "A different string";
    if (s1 < s2) // false: s2 小於 s1
    {
        cout << "s1 < s2" << endl;
    }
    else
    {
        cout << "s1 > s2" << endl;
    }
    // 直接使用C風格的字符串進行比較
    const
char ca1[] = "A string example"; const char ca2[] = "A different string"; // if ( ca1 < ca2 ) // 這樣的比較結果是未定義的,因為比較的內容是兩個指針的值 if (strcmp(ca1, ca2)) // 這樣的寫法才會使結果與string對象的比較相同。 { cout << "s1 < s2" << endl; } else { cout << "s1 > s2" << endl; }

拼接字符串

我們在對C風格的字符串進行拼接的時候需要使用到如下的方法。

    string largeStr = s1 + " " + s2;
    // 這種以加號的連等來拼接的方式不適用於C風格的字符串
    // char ca3 = ca1 + " " + ca2; // 這個表達式是錯誤的
    // 針對C風格的字符串我們需要使用一下的方式來拼接
    strcpy(largeStr, ca1);    // 把 ca1拷貝給largeStr
    strcat(largeStr, " ");    // 把largeStr的末尾加上一個空格
    strcat(largeStr, ca2);    // 把 ca2連接到largeStr後面

但是一個潛在的問題是largeStr所需要的控件是不容易準確估計的,而一旦代碼發生改變,這個問題很可能被忽略,因為並不是每次都會出問題。

這將會成為程序運行的一個潛在風險

3.5.5 與舊代碼的接口

這裏的一些操作是,可以使用C風格字符串初始化string或對它進行賦值,在使用在加法操作中,允許使用C風格的字符串進行操作,但必須保證有string的出現。

    string s("Hello World"); // s 使用C風格字符串進行初始化
    // char *Cstr = s; // 這個等式是不成立的
    const char *str = s.c_str(); // 將 string的對象內容返回為一個C風格的字符串

    char Cstr[30] = {0};
stpcpy(Cstr, s.c_str());

 

而在上述代碼的最後一行中,我們無法保證c_str()的返回值一直有效,更安全的做法是對返回的C風格字符串進行拷貝。

    // 使用數組來進行vector的初始化, begin和end兩個函數是C++11特性
    int int_arr[] = {0,1,2,3,4,5};
    vector<int> ivec(begin(int_arr), end(int_arr));

雖然以上代碼是正確的,但是非常不建議使用,因為對指針的操作總是存在一定的危險性。

以下是所有代碼,可編譯的版本,大家可自行編譯執行或修改來查看變化。

#include <iostream>
#include <string>
#include <vector>


using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::begin;
using std::end;

int main()
{
    char p[] = "Hello World!";
    char p1[] = "Hello World!p1";
    char p2[] = "Hello World!p2";
    strlen(p);    //計算p的長度,不計入空字符結尾
    strcmp(p1, p2);    // 比較兩個字符串p1和p2是否相等,相等返回0,p1>p2返回正值, p1<p2返回負值
    strcat(p1, p2); // 將p2附加到p1後,返回p1
    strcpy(p1, p2);    // 將p2拷貝給p1, 返回p1
    
    char ca[] = {C, +, +};
    cout << strlen(ca) << endl;
    
    
    
    // 使用C++的string類型進行比較
    string s1 = "A string example";
    string s2 = "A different string";
    if (s1 < s2) // false: s2 小於 s1
    {
        cout << "s1 < s2" << endl;
    }
    else
    {
        cout << "s1 > s2" << endl;
    }
    // 直接使用C風格的字符串進行比較
    const char ca1[] = "A string example";
    const char ca2[] = "A different string";
    
    // if ( ca1 < ca2 ) // 這樣的比較結果是未定義的,因為比較的內容是兩個指針的值
    if (strcmp(ca1, ca2)) // 這樣的寫法才會使結果與string對象的比較相同。
    {
        cout << "s1 < s2" << endl;
    }
    else
    {
        cout << "s1 > s2" << endl;
    }
    
    string largeStr = s1 + " " + s2;
    // 這種以加號的連等來拼接的方式不適用於C風格的字符串
    // char ca3 = ca1 + " " + ca2; // 這個表達式是錯誤的
    // 針對C風格的字符串我們需要使用一下的方式來拼接
    char largeCStr[30] = {0};
    strcpy(largeCStr, ca1);    // 把 ca1拷貝給largeStr
    strcat(largeCStr, " ");    // 把largeStr的末尾加上一個空格
    strcat(largeCStr, ca2);    // 把 ca2連接到largeStr後面
    
    string s("Hello World"); // s 使用C風格字符串進行初始化
    // char *Cstr = s; // 這個等式是不成立的
    const char *str = s.c_str(); // 將 string的對象內容返回為一個C風格的字符串
    char Cstr[30] = {0};
    strcpy(Cstr, s.c_str());
    
    // 使用數組來進行vector的初始化, begin和end兩個函數是C++11特性
    int int_arr[] = {0,1,2,3,4,5};
    vector<int> ivec(begin(int_arr), end(int_arr));
}

【共讀Primer】19.<3.5> 數組-C風格字符串 Page109