[英]C++: Is “my text” a std::string, a *char or a c-string?
我剛剛做了一個看似常見的新手錯誤 :
首先,我們閱讀了許多教程之一,如下所示:
#include <fstream>
int main() {
using namespace std;
ifstream inf("file.txt");
// (...)
}
其次,我們嘗試在代碼中使用類似的東西,如下所示:
#include <fstream>
int main() {
using namespace std;
std::string file = "file.txt"; // Or get the name of the file
// from a function that returns std::string.
ifstream inf(file);
// (...)
}
第三,新手開發人員對一些神秘的編譯器錯誤消息感到困惑。
問題是ifstream將const * char
作為構造函數參數。
解決方案是將std :: string轉換為const * char 。
現在,真正的問題是,對於一個新手來說,幾乎所有教程中給出的“file.txt”或類似的例子看起來都像std :: string。
那么,“我的文本”是std :: string,c-string還是* char,還是取決於上下文?
您能否舉例說明“我的文本”將如何根據上下文進行不同的解釋?
[編輯:我認為上面的例子會讓它顯而易見,但我應該更明確一點:我的意思是雙引號中包含的任何字符串的類型,即“myfilename.txt”,而不是單詞的含義'串'。]
謝謝。
那么,“string”是std :: string,c-string還是* char,還是取決於上下文?
const char *
(或者精確的是const char []
)。 “C string”通常是指這個,特別是帶有null終止符的字符數組。 std::string
是一個將原始字符串包裝到對象中的便捷類。 通過使用它,您可以避免必須自己執行(雜亂)指針算法和內存重新分配。 char *
(或const char *
)參數。 char *
隱式轉換為std::string
因為后者有一個構造函數來執行此操作。 c_str()
方法將std::string
顯式轉換為const char *
。 感謝Clark Gaebel指出const
,jalf和GMan提到它實際上是一個數組。
"myString"
是一個字符串文字,其類型為const char[9]
,一個9個常量char
的數組。 請注意,它有足夠的空間用於null終止符。 所以"Hi"
是一個const char[3]
,依此類推。
這幾乎總是正確的,沒有歧義。 但是,必要時, const char[9]
將衰減為指向其第一個元素的const char*
。 並且std::string
有一個隱式構造函數,它接受一個const char*
。 因此,雖然它始終以char數組開頭,但如果需要它,它可以成為其他類型。
請注意,字符串文字具有const char[N]
也可以衰減為char*
的唯一屬性,但不推薦使用此行為。 如果您嘗試以這種方式修改基礎字符串,則最終會出現未定義的行為。 這不是一個好主意。
std::string file = "file.txt";
=
的右側包含一個(原始)字符串文字(即一個以空字符結尾的字節字符串)。 它的有效類型是array of const char
。
=
這里是一個棘手的小馬:沒有任務分配。 std::string
類有一個構造函數,它將一個指向char的指針作為參數,並調用它來創建一個臨時的std::string
,這用於復制構造(使用std::string
的copy ctor) std::string
類型的目標file
。
編譯器可以自由地刪除copy ctor並直接實例化文件。
但是,請注意, std:string
與C樣式的以null結尾的字符串不同。 它甚至不需要以空終止。
ifstream inf("file.txt");
std::ifstream
類有一個ctor,它接受一個const char *
,傳遞給它的字符串文字衰減到一個指向字符串第一個元素的指針。
要記住的是: std::string
從C風格的字符串提供(幾乎無縫)轉換。 您必須查找函數的簽名,以查看是否傳入了const char *
或std::string
(后者是因為隱式轉換)。
那么,“string”是
std::string
,c-string還是char*
,還是取決於上下文?
這完全取決於背景。 :-)歡迎使用C ++。
AC字符串是以空字符結尾的字符串,它幾乎總是與char*
相同。
根據您使用的平台和框架,“string”這個詞可能有更多含義(例如,它也用於引用Qt中的QString
或MFC中的CString
)。
C和C ++都沒有內置的字符串數據類型。
當編譯器在編譯過程中發現隱式引用雙引號字符串時(參見下面的代碼),字符串本身存儲在程序代碼/文本中,並生成代碼以創建偶數字符數組:
所以最后,你有這個常量靜態字符數組的const char * 。
const char* v()
{
char* text = “Hello”;
return text;
// Above code can be reduced to:
// return “Hello”;
}
在程序運行期間,當控件找到開括號時,它在堆棧中創建“text”,char *指針,並在靜態存儲區中創建6個元素的常量數組(包括末尾的空終止符'\\ 0')。 當控件找到下一行(char * text =“Hello”;)時,6元素數組的起始地址被分配給“text”。 在下一行(返回文本;)中,它返回“text”。 使用右括號“text”將從堆棧中消失,但是數組仍然在靜態存儲區中。
你不需要使返回類型為const。 但是如果你嘗試使用非常量char *更改靜態數組中的值,它仍會在運行時給出錯誤,因為數組是常量。 因此,確保返回常量總是好的,它不能被非常量指針引用。
但是如果編譯器發現雙引號字符串被明確地稱為數組,則編譯器會假定程序員將(巧妙地)處理它。 請參閱以下錯誤示例:
const char* v()
{
char text[] = “Hello”;
return text;
}
在編譯期間,編譯器檢查,引用文本並將其保存在代碼中,以便在欠幅時間內填充生成的數組。 此外,它計算數組大小,在這種情況下再次為6。
在程序運行期間,使用open括號,在堆棧中創建具有6個元素的數組“text []”。 但沒有初始化。 當代碼找到(char text [] =“Hello”;)時,數組被初始化(使用編譯代碼中的文本)。 所以數組現在在堆棧上。 當編譯器找到(return text;)時,它返回數組“text”的起始地址。 當編譯器找到結束括號時,數組將從堆棧中消失。 因此無法通過返回指針引用它。
大多數標准庫函數仍然只使用char *(或const char *)參數。
標准C ++庫有一個強大的類,稱為字符串,用於處理文本。 字符串的內部數據結構是字符數組。 標准C ++字符串類旨在處理(並隱藏)以前C程序員所需的字符數組的所有低級操作。 請注意,std :: string是一個類:
C ++標准庫提供了一個std :: string類來管理和表示字符序列。 它封裝了內存管理,大部分時間都是作為C字符串實現的; 但這是一個實施細節。 它還為常見任務提供操作例程。
std :: string類型將始終是(它沒有char *的轉換運算符,這就是你有c_str()方法的原因),但它可以被C字符串初始化或分配(的char *)。
另一方面,如果你有一個函數將std :: string或const std :: string&作為參數,你可以將一個c-string(char *)傳遞給該函數,編譯器將構造一個std: :為你原生地字符串。 根據你提出的背景,這將是一個不同的解釋。
它應該盡可能多地意味着std::string
(或替代方法,如wxString
, QString
等,如果你使用的是提供這樣的框架。有時你沒有真正的選擇,只能使用NUL終止的字節序列,但你通常希望盡可能避免它。
最終,根本就沒有明確,明確的術語。 這就是人生。
要使用正確的措辭(如C ++語言標准中所示), 字符串是第21.3節“字符串類”(如C ++ 0x N3092中)中std :: basic_string(包括std :: string)的變種之一,而ifstream的構造函數的參數是NTBS (空終止的字節序列)
引用,C ++ 0x N3092 27.9.1.4/2。
basic_filebuf * open(const char * s,ios_base :: openmode mode);
...
如果可能,打開一個文件,其名稱為NTBS
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.