2017-03-18 42 views
4

我有std::string問題..的std :: string停止在 0

問題是,'\0'被識別爲字符串作爲在類C的串的結束。

例如下面的代碼:

#include <iostream> 
#include <string> 

int main() 
{ 
    std::string s ("String!\0 This is a string too!"); 
    std::cout << s.length(); // same result as with s.size() 
    std::cout << std::endl << s; 

    return 0; 
} 

輸出這樣的:

7 
String! 

這裏有什麼問題嗎? std::string不應該與其他任何角色一樣對待'\0'嗎?

+3

爲什麼它是一個問題? – klutt

+0

因爲C++字符串不應該是空終止(我認爲),應該像對待任何其他字符 – galaxyworks

+0

是的,但是這並不回答我的問題。 :)爲什麼你在第一個字符串中有一個\ 0?無論如何,這不是一個可打印的字符。 – klutt

回答

7

想想看:如果你給出const char*,你將如何detemine,這裏是一個真正的終止符0,並在那裏被嵌入一個?

您需要可以明確地傳遞一個尺寸字符串,或從兩個迭代器構造字符串

#include <string> 
#include <iostream> 


int main() 
{ 
    auto& str = "String!\0 This is a string too!"; 
    std::string s(std::begin(str), std::end(str)); 
    std::cout << s.size() << '\n' << s << '\n'; 
} 

例(指針):http://coliru.stacked-crooked.com/a/d42211b7199d458d

編輯:@ Rakete1111提醒我關於字符串文字:

using namespace std::literals::string_literals; 
auto str = "String!\0 This is a string too!"s; 
+3

爲什麼不使用字符串文字? 'auto str =「String!\ 0這也是一個字符串!」s;' – Rakete1111

+0

這個答案與我所尋找的最接近!謝謝:) – galaxyworks

+1

有趣的推論問題是爲什麼不重寫'std :: string'構造函數來處理字符串文字來處理嵌入的空字符?從你的回答中可以清楚地看出,編譯器本身顯然對字符串結束位置沒有什麼困惑,否則'std :: end'也會給出錯誤的答案。只有在進入標準庫時,信息纔會被降級爲一個簡單的'const char *'並因此丟失。 – user4815162342

1

讓您遠離\ 0

std::string s ("String!\\0 This is a string too!"); 

,你會得到你所需要的:

31 
String!\0 This is a string too! 
+1

OP要他們的字符串包含一個NUL字符,而不是反斜槓後跟一個0. – chris

2

std::string實際上只有7個字符和終止'\0',因爲這是你如何構建它。查看list of std::basic_string constructors:沒有能夠記住字符串文字大小的數組版本。在這裏工作的一個是這樣的一種:

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

"String!\0 This is a string too!"char const[]陣列被轉換爲一個指向第一char元件。該指針被傳遞給構造函數,並且是所有的信息。爲了確定字符串的大小,構造函數必須增加指針,直到找到第一個'\0'。這恰好是數組中的一個。


如果你碰巧有很多零個字節字符串的工作,然後有機會,std::vector<char>甚至std::vector<unsigned char>將是一個更自然的解決您的問題。

-1

這不是問題,那是預期的行爲。

也許你可以詳細說明爲什麼你的字符串中有\ 0。

使用std :: vector將允許您在字符串中使用\ 0。

+1

'std :: string'對字符串中的'\ 0''字節是很好的,不需要使用'std :: vector'就是因爲它。 – hyde

1

\0被稱爲終止字符,因此您需要以某種方式跳過它。

String represntation

把它看作一個例子。

所以每當你想跳過特殊字符,你想用兩個反斜線 「\\0

而且'\\0'是兩個字符的文字

std::string test = "Test\\0 Test" 

結果:

Test\0 Test 

大多數初學者在加載時也會犯錯,例如。文件:

std::ifstream some_file("\new_dir\test.txt"); //Wrong 
//You should be using it like this : 
std::ifstream some_file("\\new_dir\\test.txt"); //Correct 
+0

您的結果不匹配。這會產生'Test \ 0 Test'。 – chris

+0

關於你的文件示例:正確的方法是隻寫'/ new_dir/test.txt'。大多數Windows子系統在路徑中正向斜槓的情況下工作得很好。 –

+0

@chris謝謝你,你是對的。對於那個很抱歉。 – lowarago

0

您正在從字符串文字構造std::string。字符串文字自動以'\0'終止。因此,一個字符串文字"f\0o"被編碼爲以下字符數組:

{'f', '\0', 'o', '\0'} 

string構造服用char const*將被調用,並且將實施這樣的事:

string(char const* s) { 
    auto e = s; 
    while (*e != '\0') ++e; 

    m_length = e - s; 
    m_data = new char[m_length + 1]; 
    memcpy(m_data, s, m_length + 1); 
} 

顯然,這ISN」技術上正確的實施,但你明白了。您手動插入的將被解釋爲字符串文字的結尾。

如果你想忽略額外'\0',你可以使用一個std::string文字:

#include <iostream> 
#include <string> 

int main() 
{ 
    using namespace std::string_literals; 

    std::string s("String!\0 This is a string too!"s); 
    std::cout << s.length(); // same result as with s.size() 
    std::cout << std::endl << s; 

    return 0; 
} 

輸出:

30 
String! This is a string too! 
0

在極少數的話,你就構造你的C++字符串中的標準C字符串。

而標準的C字符串是零終止的。所以,你的C字符串參數將在它能夠找到的第一個\0字符中被終止。並且該字符是您在字符串中明確提供的字符"String!\0 This is a string too!"

而不是在C標準字符串的末尾由編譯器隱含並自動提供的第二個字符。