關(guān)于C++字符串的若干討論

1. char*胳螟、char[] 與 std::string 之間的區(qū)別

char*是一個(gè)指向字符的指針糖耸,是一個(gè)內(nèi)置類型嘉竟【腧剑可以指向一個(gè)字符审丘,也可以表示字符數(shù)組的首地址(首字符的地址)滩报。我們更多的時(shí)候是用的它的第二的功能,來表示一個(gè)字符串可训,功能與字符串?dāng)?shù)組char ch[n]一樣握截,表示字符串時(shí),最后有一個(gè) '\0'結(jié)束符作為字符串的結(jié)束標(biāo)志胯努。

#include <iostream>

int main()
{
    char ch1 = 'c';
    char ch2[12] = "Hello Wrold";

    char* pch1 = "string";
    char* pch2 = ch2;
    char* pch3 = &ch1;
    char* pch4 = &ch2[2];

    std::cout << ch2 << std::endl;    // 輸出ch2[0]到\0之前的所有字符
    std::cout << pch1 << std::endl;   // 輸出ch1[0]到\0之前的所有字符
    std::cout << pch2 << std::endl;   // 輸出ch2[0]到\0之前的所有字符
    std::cout << pch4 << std::endl;   // 輸出ch2[2]到\0之前的所有字符
    std::cout << *pch3 << std::endl;  // 解引用pch3蒲讯,輸出pch3指向的字符
    std::cout << *pch4 << std::endl;  // 解引用pch4,輸出pch4指向的字符

    return 0;
}

輸出:

Hello Wrold
string
Hello Wrold
llo Wrold
c
l

char p[], 表示 p 是一個(gè)字符串的數(shù)組脊另;
std::string s, 表示 s 是一個(gè) std::string 類的對(duì)象。

#include <iostream>

int main()
{
    char p1[] = "12345";
    char* p2 = "12345";
    std::string p3 = "12345";
    std::cout << "sizeof(p1) is: " << sizeof(p1) << std::endl;
    std::cout << "strlen(p1) is: " << strlen(p1) << std::endl;
    std::cout << "sizeof(p2) is: " << sizeof(p2) << std::endl;
    std::cout << "strlen(p2) is: " << strlen(p2) << std::endl;
    std::cout << "sizeof(p3) is: " << sizeof(p3) << std::endl;
    std::cout << "strlen(p3) is: " << strlen(p3.c_str()) << std::endl;
    std::cout << "length(p3) is: " << p3.length() << std::endl;
    std::cout << "capacity(p3) is: " << p3.capacity() << std::endl;

    return 0;
}

輸出結(jié)果如下:

sizeof(p1) is: 6
strlen(p1) is: 5
sizeof(p2) is: 8
strlen(p2) is: 5
sizeof(p3) is: 24
strlen(p3) is: 5
length(p3) is: 5
capacity(p3) is: 22

p1是 char 型數(shù)組名稱,sizeof(p1)表示數(shù)組的長(zhǎng)度(整個(gè)數(shù)組所占的字節(jié)數(shù));
p2是指向 char 類型的指針反粥,sizeof(p2)表示其所指向的地址值所占的字節(jié)數(shù);
p3是 std::string 類型的對(duì)象,sizeof(p3)是 std::string 類型所占空間的大小尾组,無論賦給它多長(zhǎng)的字符串,sizeof(p3)都是固定值28;
strlen函數(shù)統(tǒng)計(jì)字符串的長(zhǎng)度,但不包含結(jié)束符’\0’,std::string 類的 length 函數(shù)同樣是統(tǒng)計(jì)字符串長(zhǎng)度咆耿,std::string 類的 capacity 函數(shù)的返回值一定會(huì)大于等于字符串的長(zhǎng)度,std::string 會(huì)預(yù)先分配一定的空間,空間不足時(shí)會(huì)重新分配吻商。

2. char*艾帐、char[] 與 std::string 之間的轉(zhuǎn)換

轉(zhuǎn)換

首先必須了解捎稚,string可以被看成是以字符為元素的一種容器。字符構(gòu)成序列(字符串)腥泥。有時(shí)候在字符序列中進(jìn)行遍歷,標(biāo)準(zhǔn)的string類提供了STL容器接口。具有一些成員函數(shù)比如begin()、end()孩等,迭代器可以根據(jù)他們進(jìn)行定位。

注意权她,與char*不同的是,string不一定以NULL('\0')結(jié)束步清。string長(zhǎng)度可以根據(jù)length()得到询微,string可以根據(jù)下標(biāo)訪問书聚。所以,不能將string直接賦值給char*。

2.1. string 轉(zhuǎn)換成 char*

如果要將string直接轉(zhuǎn)換成const char *類型鸽心,可以直接賦值太闺,string有2個(gè)函數(shù)可以運(yùn)用蟀淮。一個(gè)是.c_str(),一個(gè)是data成員函數(shù)逃延。

#include <iostream>
#include <string>

int main()
{
    std::string str = "abcdeg";
    const char* k = str.c_str();
    const char* t = str.data();
    
    printf("%s%s\n", k, t);
    std::cout << k << t << std::endl;
    
    return 0;
}

如上讽膏,都可以輸出。內(nèi)容是一樣的拄丰。但是只能轉(zhuǎn)換成const char*府树,如果去掉const編譯不能通過。

那么料按,如果要轉(zhuǎn)換成char*奄侠,可以用string的成員函數(shù)copy實(shí)現(xiàn)。

#include <iostream>
#include <string>

int main()
{
    std::string str = "abcdefg";

    int len = str.length();
    char* data = (char *)malloc((len + 1) * sizeof(char));
    str.copy(data, len, 0);
    
    printf("%s\n", data);
    std::cout << data << std::endl;
    
    return 0;
}

2.2. string 轉(zhuǎn)換成 char[]

不可以直接賦值载矿÷⒊保可以循環(huán)string字符串逐個(gè)字符賦值,也可以使用strcpy_s等函數(shù)(需調(diào)用string對(duì)象的c_str函數(shù)闷盔,返回類型為const char* )弯洗。

這樣的轉(zhuǎn)換不可直接賦值。

 #include <string>

int main()
{
    std::string str = "dagah";
    char ch[8];
    int i = 0;

    for( ; i < str.length(); ++i)
    {
        ch[i] = str[i];
    }

    ch[i] = '\0';

    printf("%s\n", ch);
    std::cout << ch << std::endl;

    return 0;
}

2.3. char* 轉(zhuǎn)換成 string

可以直接賦值逢勾。

#include <string>

int main()
{
    char* ch = "adghrtyh";
    std::string str = ch;

    printf("%s\n", str.c_str());
    std::cout << str << std::endl;

    return 0;
}

不過牡整,當(dāng)我們定義了一個(gè)string類型之后,用printf("%s", str);輸出是會(huì)出問題的溺拱。這是因?yàn)椤?s”要求后面的對(duì)象的首地址逃贝,但是string不是這樣的一個(gè)類型。所以肯定出錯(cuò)迫摔。

2.4. char[] 轉(zhuǎn)換成 string

這個(gè)也可以直接賦值秋泳。但是也會(huì)出現(xiàn)上面的問題。需要同樣的處理攒菠。

2.5. char* 轉(zhuǎn)換成 char []

不能直接賦值迫皱,可以循環(huán) char* 字符串逐個(gè)字符賦值,也可以使用strcpy_s等函數(shù)。

char *p="ertyu";

char r[10];

strcpy(r,p);

2.6. char[] 轉(zhuǎn)換成 char*

可以直接賦值卓起。

3. 問題

1和敬、char* pch = "abc"; // caution:ISO C++11 doesn't allow conversion from string literal to 'char*'
系統(tǒng)為可執(zhí)行文件寫下常量字符串,保存在可執(zhí)行文件里戏阅,運(yùn)行的時(shí)候加載到內(nèi)存中昼弟,無法修改。
解決辦法:

  • A奕筐、標(biāo)準(zhǔn)方法:將指針轉(zhuǎn)換為char const *類型
    char const* pch = "abc";
  • B舱痘、將字符串強(qiáng)制轉(zhuǎn)換為char*類型
    char* pch = (char*)"abc";

2、

char* pch = 'a';
char* pch = &'a';

第一行由于'a'是一個(gè)char類型的字符离赫,并不是一個(gè)有效的地址芭逝,無法用來初始化char*
第二行無法直接取到'a'這個(gè)char類型字符的地址。

解決辦法:
-A渊胸、動(dòng)態(tài)內(nèi)存申請(qǐng):
char* pch = new char('a');

-B旬盯、初始化一個(gè)新變量:

char ch = 'a';
char* pch = &ch;

注意:char *pch=ch是錯(cuò)誤的,因?yàn)閏h是一個(gè)char型變量的變量名翎猛,并不是一個(gè)有效地址胖翰。

3、Q: What is the difference between these initializations?

char a[] = "string literal";
char *p = "string literal";

My program crashes if I try to assign a new value to p[i].

A: A string literal (the formal term for a double-quoted string in C source) can be used in two slightly different ways:

As the initializer for an array of char, as in the declaration of char a[] , it specifies the initial values of the characters in that array (and, if necessary, its size).

Anywhere else, it turns into an unnamed, static array of characters, and this unnamed array may be stored in read-only memory, and which therefore cannot necessarily be modified. In an expression context, the array is converted at once to a pointer, as usual (see section 6), so the second declaration initializes p to point to the unnamed array's first element.

Some compilers have a switch controlling whether string literals are writable or not (for compiling old code), and some may have options to cause string literals to be formally treated as arrays of const char (for better error catching).

C and C++ differ in the type of the string literal. In C the type is array of char and in C++ it is constant array of char. In any case, you are not allowed to change the characters of the string literal, so the const in C++ is not really a restriction but more of a type safety thing. A conversion from const char* to char* is generally not possible without an explicit cast for safety reasons. But for backwards compatibility with C the language C++ still allows assigning a string literal to a char* and gives you a warning about this conversion being deprecated.

4. int/double 與 char*/std::string的轉(zhuǎn)換

//-------------------------------------------------
    // double/int --> char*
    // itoa 不是標(biāo)準(zhǔn)庫函數(shù)

    // int-->char*
    int digit1 = 167;
    char str1[20];
    sprintf(str1, "%d", digit1);

    // double-->char*
    double digit2 = 168.2;
    char str2[20];
    sprintf(str2, "%f", digit2);

    // link
    char* str3 = "Hello";
    char* str4 = "World";
    
    // 1
    char str5[20];
    strcpy(str5, str3);
    strcat(str5, str4);

    // 2
    char str6[20];
    sprintf(str6, "%s%s", str1, str2);

    // 兩個(gè)double轉(zhuǎn)為char*
    double digit7 = 12.3;
    double digit8 = 23.4;
    char str7[20];
    sprintf(str7, "%f%f", digit7, digit8);
    //-------------------------------------------------


    //-------------------------------------------------
    // char*-->double/int
    // atoi atof
    // ...

    double digit9 = atof("123");

    //-------------------------------------------------


    //-------------------------------------------------
    // double/int --> std::string
    // std::to_string()
    double digit11 = 451.7;
    std::string str11 = "score" + std::to_string(digit11);
    //-------------------------------------------------


    //-------------------------------------------------
    // std::string-->double/int
    // std::stoi std::stof std::stol
    std::string str12("123");
    double digit12 = std::stof(str12);
    //-------------------------------------------------

5. 參考

https://stackoverflow.com/questions/28861475/conversion-from-string-literal-to-char
https://stackoverflow.com/questions/1704407/what-is-the-difference-between-char-s-and-char-s/1704433#1704433
https://stackoverflow.com/questions/164194/why-do-i-get-a-segmentation-fault-when-writing-to-a-string-initialized-with-cha
https://stackoverflow.com/questions/9650058/deprecated-conversion-from-string-literal-to-char
https://stackoverflow.com/questions/1524356/c-deprecated-conversion-from-string-constant-to-char

http://c-faq.com/decl/strlitinit.html
https://www.codeguru.com/cpp/cpp/cpp_mfc/general/article.php/c6967/Constant-Pointers-and-Pointers-to-Constants.htm
https://blog.csdn.net/doem97/article/details/51730225

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末切厘,一起剝皮案震驚了整個(gè)濱河市萨咳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疫稿,老刑警劉巖培他,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異而克,居然都是意外死亡靶壮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門员萍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腾降,“玉大人,你說我怎么就攤上這事碎绎◇θ溃” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵筋帖,是天一觀的道長(zhǎng)奸晴。 經(jīng)常有香客問我,道長(zhǎng)日麸,這世上最難降的妖魔是什么寄啼? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任逮光,我火速辦了婚禮,結(jié)果婚禮上墩划,老公的妹妹穿的比我還像新娘涕刚。我一直安慰自己,他們只是感情好乙帮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布杜漠。 她就那樣靜靜地躺著,像睡著了一般察净。 火紅的嫁衣襯著肌膚如雪驾茴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天氢卡,我揣著相機(jī)與錄音锈至,去河邊找鬼。 笑死异吻,一個(gè)胖子當(dāng)著我的面吹牛裹赴,可吹牛的內(nèi)容都是我干的喜庞。 我是一名探鬼主播诀浪,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼延都!你這毒婦竟也來了雷猪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤晰房,失蹤者是張志新(化名)和其女友劉穎求摇,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體殊者,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡与境,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猖吴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摔刁。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖海蔽,靈堂內(nèi)的尸體忽然破棺而出共屈,到底是詐尸還是另有隱情,我是刑警寧澤党窜,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布拗引,位于F島的核電站,受9級(jí)特大地震影響幌衣,放射性物質(zhì)發(fā)生泄漏矾削。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哼凯。 院中可真熱鬧垦细,春花似錦、人聲如沸挡逼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽家坎。三九已至嘱能,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虱疏,已是汗流浹背惹骂。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留做瞪,地道東北人对粪。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像装蓬,于是被迫代替她去往敵國(guó)和親著拭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容