簡體   English   中英

指針和字符串C ++

[英]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; 

我收到一條錯誤消息。

基本上,總結一下我的問題,我試圖用strcpycout語句理解代碼。

看起來你理解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 ,因此調用coutchar版本並忠實地打印單個字符*str 為了與C風格的字符串兼容,以char*作為參數的cout版本將指針視為用於打印目的的C風格字符串。 如果您coutint* ,例如,基礎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提供了兩種返回指向其底層內容的指針的方法: datac_str Pre-C ++ 11,唯一的區別是data不包括NUL終結符。 在C ++ 11中,它現在可以,所以它們的行為是相同的。 因為指針很容易被無效,所以操縱那些指針是不安全的。 char * ptr = str.c_str();也是不安全的char * ptr = str.c_str(); 因為c_str返回的數組的生命周期在分號處死掉。 您需要將其復制到緩沖區中。

您正在將正確的問題作為學習者。

回答:

  1. 在C ++中, string是一個對象, c_str()實際上返回一個指向字符串第一個字符的指針(C Style)
  2. 你對C中的字符串是正確的,變量實際上指向字符串的第一個字符
  3. C ++根據變量的類型做了很多事情。 當你傳遞一個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風格字符串的標准庫函數都會使用指向所述字符串的指針,原因有兩個:

  1. 與其他數組不同,將C樣式字符串視為一個整體而不是一堆字符更容易,因此使用指針保持這個想法
  2. 這是將數組作為函數參數來獲取指向第一個元素的指針的最簡單方法,特別是在C字符串的情況下,它們只能被讀取為NULL字符。

我想你正在做什么,其他人請糾正我,如果我錯了,是你將你的字符串復制到動態字符數組中。 所以不,你沒有把它復制到指針。 指針涉及的原因是因為動態數組需要指針才能正確分配內存。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM