2014-09-06 52 views
0

代碼:爲什麼你需要添加一個新的字符(str.length())?

string str = "Whats up"; 
char *c = new char[str.length() + 1]; 

我仍然可以寫char *c = new char[str.length()];

什麼是上添加長度+1點?

+4

http://en.wikipedia.org/wiki/Null-terminated_string這是不是從你從那裏獲得代碼的地方解釋的? – juanchopanza 2014-09-06 07:35:28

+0

爲尾部空白騰出空間。你應該在任何情況下使用strdup(),而free()釋放它。 – EJP 2014-09-06 07:52:25

回答

2

std::string不同,C風格的字符串使用特殊字符來表示其結尾,即空字符'\0',多餘的一個字符用於存儲終止的'\0'

+3

你的答案可能會引起誤解。 'std :: string'也使用'\ 0'。 'c_str()'方法返回一個指向底層數據的指針,該數據以NULL結尾 – Willem 2014-09-06 09:29:35

-6

代碼中存在缺陷。

應該

c* = new char[str.length()+1]; 

s.length()+ 1不會做任何事情。

雖然編譯器會自動爲您設置c字符串大小,但指定確切的大小是一種很好的做法,以便您能夠看到所有內容的機制。

C字符串總是需要比std :: string值多一個空格,因爲c字符串是在數組末尾具有終止空值的字符數組。這就是爲什麼你總是在最後給NULL空間。

+1

這根本不回答問題。 – juanchopanza 2014-09-06 07:49:56

+0

你是對的,只是回答了它。 – savageWays 2014-09-06 07:54:48

+0

但「雖然編譯器會自動爲你設置c字符串的大小......」聽起來很不對。 – juanchopanza 2014-09-06 07:56:10

6

您的代碼:

string str = "Whats up"; 
char *c = new char[str.length() + 1]; 

你的問題:

什麼是上添加長度+1點?

真正的問題應該是:在你的C++程序中使用C風格的字符串有什麼意義?你確定你需要他們嗎?

讓我解釋一下到底發生了什麼在你的兩個代碼行:

"Whats up"字符串文字,即恆定的一系列字符,一個char const[9]要精確。第9個字符是空字符,'\0',由編譯器自動添加。所以數組實際上是這樣的:

{ 'W', 'h', 'a', 't', 's', ' ', 'u', 'p', '\0' } 

事實上,你可能也寫:

char const array[9] = { 'W', 'h', 'a', 't', 's', ' ', 'u', 'p', '\0' }; 
std::string s = array; 

所以,你有一個char const[9]陣列,用來初始化std::stringstd::string的哪個構造函數在這裏實際使用?如果您在http://en.cppreference.com/w/cpp/string/basic_string/basic_string看一看,你會發現這一個:

basic_string(const CharT* s, 
       const Allocator& alloc = Allocator()); 

記住,std::string實際上是std::basic_string<char>一個typedef,所以你CharT在這種情況下是一個char,並構造全文:

string(const char* s, 
       const Allocator& alloc = Allocator()); 

也忽略alloc參數。向初學者解釋過於複雜,而且它有一個默認參數,所以幾乎可以隨時忽略它。這意味着你最終有:

string(const char* s); 

這本身就是寫作的另一種方式:

string(char const *s); 

所以,你可以初始化std::stringchar const *,你的代碼將構造一個char const[9]。這是因爲數組自動轉換爲指向其第一個元素的指針。

所以std::string需要你的數組,把它當作一個指針並複製9個字符。陣列大小信息9會丟失,但這並不重要,因爲您有終止的'\0',因此std::string知道停止哪裏。

到目前爲止,這麼好。您有一個std::string對象,其中包含"Whats up"的副本。你的下一行是這樣的:

所有的
char *c = new char[str.length() + 1]; 

首先,考慮str.length()length函數返回字符串大小,而不是數組大小。因此,雖然您傳遞了9個字符來構造字符串,但length返回8.這很有意義,因爲std::string旨在讓您忘記指針,數組和內存操作。它是文本,這裏的文本有8個字符。

因此,str.length() + 1等於8 + 1 = 9,所以你的代碼行等效於:

char *c = new char[9]; 

已創建一個名爲c指針,初始化爲指向的存儲器位置,其中有足夠爲9個字符,雖然什麼當前存儲有不確定,所以你一定不要嘗試從那裏尚未閱讀:

c 
| 
| 
+------+ 
     | 
     v 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
...| | | | | | | | | | | | ... 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
     0 1 2 3 4 5 6 7 8 

而您創建的std::string與內存c指向的內容之間沒有任何關係。他們生活在完全不同的地方:

c 
| 
| 
+------+ 
     | 
     v         0 1 2 3 4 5 6 7 8 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
... | | | | | | | | | | | | ... |W |h |a |t |s | |u |p |\0| ... 
+-+-+-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
     0 1 2 3 4 5 6 7 8   ^
              | 
              | 
      str -------(c_str())-----------+ 

但是如果你使用像strcpy C函數的std::string的內容複製到這些9個字符,那麼爲什麼你需要空間,9個字符變得清晰:

strcpy(c, str.c_str()); 

strcpy查看來源(str.c_str())並將一個字符依次複製到c,直到找到'\0'str內部以\0結尾,所以一切都很好。該功能從到位於此圖片的右側,並將所有內容複製到左側的至。

這最後回答你的問題:左側必須有9個字符的空間。否則,strcpy將嘗試將最終字符(\0)寫入不允許觸摸的內存位置。這會導致未定義的行爲並可能導致例如崩潰或隨機崩潰。

客房爲9個字符,strcpy成功完成:

c 
| 
| 
+------+ 
     | 
     v         0 1 2 3 4 5 6 7 8 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
... | |W |h |a |t |s | |u |p |\0| | ... |W |h |a |t |s | |u |p |\0| ... 
+-+-+-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
     0 1 2 3 4 5 6 7 8   ^
              | 
              | 
      str -------(c_str())-----------+ 

這個故事的寓意:

使用std::string。複製std::string可以使用內部非常類似的機制,但不必記住「+ 1」規則釋放你(除其他討厭的東西):

std::string s1 = "Whats up"; 
std::string s2 = "..."; 
s2 = s1; 
相關問題