[英]Pointers and Strings C++
我在教自己C ++,我對指針有點困惑(特別是在下面的源代碼中)。 但首先,我繼續向你展示我所知道的內容(然后將代碼與此對比,因為我覺得好像存在一些矛盾)。
我知道的:
int Age = 30;
int* pointer = &Age;
cout << "The location of variable Age is: " << pointer << endl;
cout << "The value stored in this location is: " << *pointer << endl;
指針保存內存地址。 使用間接(取消引用)運算符(*),可以訪問存儲在指針的內存位置的內容。 在本書的代碼中,我無法理解......
cout << "Enter your name: ";
string name;
getline(cin, name); //gets full line up to NULL terminating character
int CharsToAllocate = name.length() + 1; //calculates length of string input
//adds one onto it to adjust for NULL character
char* CopyOfName = new char[CharsToAllocate];
// pointer to char's called CopyOfName, is given the memory address of the
//beginning of a block
//of memory enough to fit CharsToAllocate. Why we added 1? Because char's need a
//NULL terminating character (\0)
strcpy(CopyOfName, name.c_str()); //copies the string name, into a pointer?
cout << "Dynamically allocated buffer contains: " << CopyOfName << endl;
delete[] CopyOfName; //always delete a pointer assigned by new to prevent memory leaks
輸出:
Enter your name: Adam
Dynamically allocated buffer contains: Adam
上面代碼中的注釋是我的評論。 我的問題始於strcpy
。 為什么將name.c_str()
復制到指針CopyOfName
? 這是否意味着所有字符串都是必不可少的指針? 就像字符串測試=“Hello world”; 實際上是指向存儲“H”的存儲位置的指針嗎?
接下來,為什么它在使用CopyOfName
而不是*CopyOfName
的print out語句中? 指針有內存地址嗎? 使用*CopyOfName
將打印出內存位置的內容。 我在Code :: Blocks中嘗試了這個,如果輸入文本是“Hello World”。 在print out語句中使用*CopyOfName
只會給出一個“H”。 這是有道理的,因為當我聲明我需要一個帶有'new'的內存塊時,這實際上會返回一個指向動態分配的內存塊的第一部分的指針。
我可以調和它的唯一方法是字符串實際上是一個指針。
string testing = "Confused";
cout << testing << endl;
會打印出“困惑”這個詞
但是,如果我嘗試編譯
string testing = "Confused";
cout << *testing;
我收到一條錯誤消息。
基本上,總結一下我的問題,我試圖用strcpy
和cout
語句理解代碼。
看起來你理解C風格的字符串是什么,但總而言之,它們只是內存中的字符數組,按照慣例以nul字符\\0
結尾。 通常它們通過指向字符串中第一個字母的char*
引用。 當它們被打印時,通常從第一個開始打印字符串的字符,並且當到達\\0
終止符時打印(或復制等)停止。
std::string
是一個(通常)包裝C風格字符串的類。 這意味着std::string
對象(通常)具有用於實現其功能的私有C樣式字符串。 函數std::string::c_str()
返回指向此底層C樣式字符串的指針。
我們假設char *str;
指向C風格的字符串。 如果你試圖運行cout << *str << endl;
,你注意到只打印了第一個字符。 那是因為C ++的函數重載。 *str
的數據類型是char
,因此調用cout
的char
版本並忠實地打印單個字符*str
。 為了與C風格的字符串兼容,以char*
作為參數的cout
版本將指針視為用於打印目的的C風格字符串。 如果您cout
的int*
,例如,基礎int
不會被打印出來。
編輯:另一個評論:
您嘗試取消引用std::string
對象失敗的原因是,它實際上不是指針。 您可以取消引用std::string::c_str()
的返回值,然后返回std::string::c_str()
的第一個char
。
相關: 如何實現std :: string? 。
在C中,字符串只是字符數組。 當用作函數的參數時,數組會衰減為指針。
在C ++中, std::string
是一個類。 它包含一個C風格的字符數組,這就是c_str()
返回的內容。 但是字符串本身不是指針,所以你不能取消引用它; 你必須使用c_str()
方法來獲取指向字符串內容的指針。
就像
string testing = "Hello world";
實際上是指向存儲“H”的存儲位置的指針嗎?
不,上面你有一個名為string
對象。 char* testing = "Hello World"
。 如你所見,它甚至被聲明為指針,它指向字符串中的第一個字符 - H.
接下來,為什么在
CopyOfName
語句中CopyOfName
不是*CopyOfName
? 指針有內存地址嗎? 使用*CopyOfName
將打印出內存位置的內容。 我在代碼塊中嘗試了這個,如果輸入文本是“Hello World”。 在print out語句中使用*CopyOfName
只會給出一個“H”
cout將指針指向字符串的第一個字符,因此CopyOfName
是正確的。 在這種情況下,它將打印從H開始的每個字符,直到找到\\ 0(空字符)。 像“你好”這樣的字符串實際上有6個字符 - ' *CopyOfName
''''o''\\ 0'當您編寫*CopyOfName
您正在取消引用此指針而*CopyOfName
實際上只有一個字符
按順序提出問題:
“為什么name.c_str()被復制到指針CopyOfName?這是否意味着所有字符串都是必需的指針?所以像字符串測試=”Hello world“;實際上是指向存儲”H“存儲位置的指針嗎? “
正如Yu Hao在他/她的評論中指出的那樣,理解C ++風格的字符串和C風格的字符串之間的區別非常重要。 在第一種情況下,您正在處理“不透明”對象,而在后一種情況下,您基本上處理的是“數組”字符。
使用C ++字符串對象,您可以使用c_str()
方法獲取(指向a)C樣式字符數組。 在C中,使用指向數組開頭的指針表示數組,然后通過從該起始地址提供偏移量(索引到數組中)來實現引用。 所以這個包中最后一個問題的答案是“是”,指向C風格字符串的指針是指向第一個字符'H'的指針。
“接下來,為什么在打印聲明中,CopyOfName不是* CopyOfName?指針保存內存地址?”
因為運算符<<
被重載以處理C字符串。 這個方法的實現“知道如何處理”指針。
指針與數組不同。 字符串文字是不可變的,當你有一個指向字符串文字的指針時,你可以檢查它的內容,但修改它們是未定義的行為。 使用此語法時:
char arr[] = "hi there";
字符串文字被復制到數組中。 因為您沒有指定大小,編譯器會自動推導它。 NUL
終結器也會自動添加。 如果指定大小,則必須確保緩沖區可以容納NUL
終止符。 因此:
char arr[5] = "hello";
是一個錯誤。 如果使用大括號初始化器語法:
char arr[5] = { "h", "e", "l", "l", "o" };
這是一個錯誤,因為沒有NUL
終止符。 如果使用strcpy
,將為您添加NUL
終止符。
std::string
提供了兩種返回指向其底層內容的指針的方法: data
和c_str
。 Pre-C ++ 11,唯一的區別是data
不包括NUL
終結符。 在C ++ 11中,它現在可以,所以它們的行為是相同的。 因為指針很容易被無效,所以操縱那些指針是不安全的。 char * ptr = str.c_str();
也是不安全的char * ptr = str.c_str();
因為c_str
返回的數組的生命周期在分號處死掉。 您需要將其復制到緩沖區中。
您正在將正確的問題作為學習者。
回答:
string
是一個對象, c_str()
實際上返回一個指向字符串第一個字符的指針(C Style) string
對象cout
打印字符串。 此外,C ++足夠聰明,可以確定*testing
是非法的 為什么將name.c_str()復制到指針CopyOfName中?
“name”是一個STL字符串。 這是一個與c字符串不同的對象。 c-string是一個內存集合,它包含字符,並具有空終止。 因此,如果您正在使用STL字符串並希望將它們轉換為c字符串,則可以使用.c_str()來獲取c字符串。
CopyOfName包含足夠的內存來保存名稱,因為它被分配用於保存它。
cout有一些不同的東西你可以用<<。 看起來它可能需要char *(它是c-strings)或STL字符串。 看起來它不能指向STL字符串。
當你介紹“測試”時我有點困惑,但我認為你在c-strings(它們是char *)和STL字符串(它們是對象)之間感到困惑。 不要心疼,否則就放棄。 這個東西很棘手,需要一段時間才能得到。
我建議嘗試理解術語“c-string”,“char *”,“stl string”和“stl string”指針之間的差異。
在C中,C ++標准字符串不存在,char *就是所謂的“字符串”。 如您所述,它是一個以NULL字符結尾的字符數組。 幾乎所有采用C風格字符串的標准庫函數都會使用指向所述字符串的指針,原因有兩個:
我想你正在做什么,其他人請糾正我,如果我錯了,是你將你的字符串復制到動態字符數組中。 所以不,你沒有把它復制到指針。 指針涉及的原因是因為動態數組需要指針才能正確分配內存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.