寫在前面:字符是單個的,字符串一般有多個,但也可以是單個,甚至可以是空的
char c; c = 'a'; //字符a,注意使用單引號
c = "a'; //出錯!“a”使用的是雙引號,代表是字符串,而c是字符類型
string c="abcd"; string c1="a";單個字符,但是雙引號
在C++中,有兩種類型的字符串表示形式:
- C-風格字符串
- C++引入的string類
C-風格字符串
C 風格的字符串起源於 C 語言,並在 C++ 中繼續得到支持。字符串實際上是使用 null 字符 ‘\0’ 終止的一維字符數組。因此,一個以 null 結尾的字符串,包含了組成字符串的字符。
下面的聲明和初始化創建了一個 “Hello” 字符串。由於在數組的末尾存儲了空字符,所以字符數組的大小比單詞 “Hello” 的字符數多一個。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
其實不需要把 null 字符放在字符串常量的末尾。C++ 編譯器會在初始化數組時,自動把 ‘\0’ 放在字符串的末尾。所以也可以利用下面的形式進行初始化
char greeting[] = "Hello";
以下是 C/C++ 中定義的字符串的內存表示:
C++ 中有大量的函數用來操作以 null 結尾的字符串:
序號 | 函數 | 功能 |
---|---|---|
1 | strcpy(s1,s2) | 復制字符串 s2 到字符串 s1 |
2 | strcat(s1,s2) | 連接字符串 s2 到字符串 s1 的末尾 |
3 | strlen(s1) | 返回字符串 s1 的長度 |
4 | strcmp(s1,s2) | 返回s1與s2的比較結果 |
5 | strchr(s1,ch) | 返回一個指針,指向字符串s1中字符ch的第一次出現的位置 |
6 | strstr(s1,s2) | 返回一個指針,指向字符串s1中s2的第一次出現的位置 |
C++ 中的 String 類
C++ 標准庫提供了 string 類類型,支持上述所有的操作,另外還增加了其他更多的功能。比如:
- append() – 在字符串的末尾添加字符
- find() – 在字符串中查找字符串
- insert() – 插入字符
- length() – 返回字符串的長度
- replace() – 替換字符串
- substr() – 返回某個子字符串
- …
C++中的字符串一般有以下四種類型,
-
string
-
char*
- const char*
- char[]
下面分別做簡單介紹,並說明其中的一些區別
1)string
string是一個C++類庫中的一個類,它位於名稱空間std中,因此必須使用using編譯指令或者std::string來引用它。它包含了對字符串的各種常用操作,它較char*的優勢是內容可以動態拓展,以及對字符串操作的方便快捷,用+號進行字符串的連接是最常用的操作;
2)char*
char* 是指向字符串的指針(其實嚴格來說,它是指向字符串的首個字母),你可以讓它指向一串常量字符串;
3)const char*
該聲明指出,指針指向的是一個const char類型,即不能通過當前的指針對字符串的內容作出修改
注意這里有兩個概念:
- char * const [指向字符的靜態指針]
- const char * [指向靜態字符的指針]
前者const修飾的是指針,代表不能改變指針
后者const修飾的是char,代表字符不能改變,但是指針可以變,也就是說該指針可以指針其他的const char;
4)char[]
與char*與許多相同點,代表字符數組,可以對應一個字符串,如
char * a="string1"; char b[]="string2";
這里a是一個指向char變量的指針,b則是一個char數組(字符數組)
二者的不同點
一,char*是變量,值可以改變, char[]是常量,值不能改變!
a是一個char型指針變量,其值(指向)可以改變;
b是一個char型數組的名字,也是該數組首元素的地址,是常量,其值不可以改變
二,char[]對應的內存區域總是可寫,char*指向的區域有時可寫,有時只讀
比如:
char * a="string1"; char b[]="string2"; gets(a); //試圖將讀入的字符串保存到a指向的區域,運行崩潰!
gets(b) //OK
解釋: a指向的是一個字符串常量,即指向的內存區域只讀;
b始終指向他所代表的數組在內存中的位置,始終可寫!
注意,若改成這樣gets(a)就合法了
char * a="string1"; char b[]="string2"; a=b; //a,b指向同一個區域
gets(a) //OK
printf("%s",b) //會出現gets(a)時輸入的結果
解釋: a的值變成了是字符數組首地址,即&b[0],該地址指向的區域是char *或者說 char[8],習慣上稱該類型為字符數組,其實也可以稱之為“字符串變量”,區域可讀可寫。
總結:char *本身是一個字符指針變量,但是它既可以指向字符串常量,又可以指向字符串變量,指向的類型決定了對應的字符串能不能改變!
三,char * 和char[]的初始化操作有着根本區別:
char *a="Hello World"; char b[]="Hello World"; printf("%s, %d\n","Hello World", "Hello World"); printf("%s, %d %d\n", a, a, &a); printf("%s, %d %d\n", b, b, &b);
結果:
Hello World,13457308 Hello World,13457308 2030316 Hello World,2030316 2030316
結果可見:盡管都對應了相同的字符串,但”Hello World”的地址 和 a對應的地址相同,與b指向的地址有較大差異;&a 、&b都是在同一內存區域,且&b==b
根據c內存區域划分知識,我們知道,局部變量都創建在棧區,而常量都創建在文字常量區,顯然,a、b都是棧區的變量,但是a指向了常量(字符串常量),b則指向了變量(字符數組),指向了自己(&b==b==&b[0])。
char * a=”string1”;是實現了3個操作:
- 聲明一個char*變量(也就是聲明了一個指向char的指針變量);
- 在內存中的文字常量區中開辟了一個空間存儲字符串常量”string1”
- 返回這個區域的地址,作為值,賦給這個字符指針變量a
最終的結果:指針變量a指向了這一個字符串常量“string1”
(注意,如果這時候我們再執行:char * c=”string1”;則,c==a,實際上,只會執行上述步驟的1和3,因為這個常量已經在內存中創建)
char b[]=”string2”;則是實現了2個操作:
- 聲明一個char 的數組,
- 為該數組“賦值”,即將”string2”的每一個字符分別賦值給數組的每一個元素
最終的結果:“數組的值”(注意不是b的值)等於”string2”,而不是b指向一個字符串常量
實際上, char * a=”string1”; 的寫法是不規范的!
因為a指向了即字符常量,一旦strcpy(a,”string2”)就糟糕了,試圖向只讀的內存區域寫入,程序會崩潰的!盡管VS下的編譯器不會警告,但如果你使用了語法嚴謹的Linux下的C編譯器GCC,或者在windows下使用MinGW編譯器就會得到警告。
所以,我們還是應當按照”類型相同賦值”的原則來寫代碼:
onst char * a="string1";
保證意外賦值語句不會通過編譯。
const char*與char[]的區別:
const char * a=”string1”
char b[]=”string2”;
二者的區別在於:
-
a是const char 類型, b是char const類型
( 或者理解為 (const char)xx 和 char (const xx) ) -
a是一個指針變量,a的值(指向)是可以改變的,但a只能指向(字符串)常量,指向的區域的內容不可改變;
-
b是一個指針常量,b的值(指向)不能變;但b指向的目標(數組b在內存中的區域)的內容是可變的
-
作為函數的聲明的參數的時候,char []是被當做char *來處理的!兩種形參聲明寫法完全等效!
參考:https://blog.csdn.net/ksws0292756/article/details/79432329