2013-01-17 120 views
13

以下是3個函數。 main()按預期打印出來。 現在,在mycharstack()字符串存儲在堆棧我猜,所以「ch」超出範圍,它不應該能夠返回字符串。它如何正確工作? 我猜存儲在mychar()中的字符串也在堆棧中。它應該正常工作嗎? 我想代碼和內存泄漏還有其他錯誤,請告訴我是否有任何錯誤。使用std :: string我可以更輕鬆地完成這些清潔工作&。但我想了解char *發生了什麼。從函數返回char *

#include <iostream> 
using namespace std; 

char* mychar() 
{ 
    return "Hello"; 
} 

char* mycharstack() 
{ 
    char* ch = "Hello Stack"; 
    return ch; 
} 

char* mycharheap() 
{ 
    char* ch = new char; 
    ch = "Hello Heap"; 
    return ch; 
} 

int main() 
{ 
    cout << "mychar() = " << mychar() << endl; 
    cout << "mycharstack() = " << mycharstack() << endl; 
    cout << "mycharheap() = " << mycharheap() << endl; 

    system("PAUSE"); 
    return 0; 
} 

回答

15

在C++中,字符串處理與例如pascal不同。

char* mycharheap() 
{ 
    char* ch = new char; 
    ch = "Hello Heap"; 
    return ch; 
} 

但這下列:

  1. char* ch = new char;一個字符創建存儲器,並將其分配給變量ch
  2. ch = "Hello Heap";分配給變量ch指針只讀存儲器,其包含字節"Hello Heap\0"。另外,變量ch的原始內容丟失,導致內存泄漏。
  3. return ch;將指針存儲到變量ch

你可能想要的是

char* mycharheap() 
{ 
    char* ch = new char[11] /* 11 = len of Hello Heap + 1 char for \0*/; 
    strcpy(ch, "Hello Heap"); 
    return ch; 
} 

strcpy - >您已經有了在ch內存,有空間,11個字符,並且系統會通過字符串從只讀部分加油吧的記憶。

在這種情況下會出現泄漏。您將需要寫入後刪除存儲,如:

char* tempFromHeap = mycharheap(); 
cout << "mycharheap() = " << tempFromHeap << endl; 
delete[] tempFromHeap; 

不過,我高度不建議這樣做(在被叫分配內存和調用者刪除)。對於這種情況,例如,有STL std::string,另一種常見和更合理的方法是在調用者中分配,傳遞給被調用者,這會將結果「填充」到內存中,並再次在調用者中解除分配。

將導致未定義的行爲什麼是以下:

char* mycharstack() 
{ 
    char[] ch = "Hello Heap"; /* this is a shortcut for char[11] ch; ch[0] = 'H', ch[1] = 'e', ...... */ 
    return ch; 
} 

這將創建上堆疊陣列與字節"Hello Heap\0",然後嘗試指針返回到該陣列的第一個字節(它可以,在調用功能,指向任何東西)

+0

If我剛剛用我在代碼中提到的那個替換了mycharheap(),但仍然會泄漏......對吧?在main()中沒有人釋放分配的內存。 – ontherocks

+0

是的。看到我更新的答案。 – nothrow

+0

因此,對於像mycharheap()這樣的函數,不建議將其直接用作其他函數中的參數,這些函數以char *作爲輸入參數。例如,說有一個函數print(char * char_in);''我不應該像'print(mycharheap());'那樣做。這會導致內存泄漏。我對嗎? – ontherocks

0

功能mycharheap()泄漏:你讓你的指針指向在堆上分配一個char長度的存儲區域,然後修改指針指向一個字符串文字存儲在只讀只有記憶。分配的內存不會被釋放。

+0

如何釋放分配的內存?我的意思是,在上面的代碼中,我在哪裏調用delete? – ontherocks

+0

@ontherocks:這個問題是錯誤的;-)你不應該重新分配指針。如果你想在堆上分配字符串「hello world」,然後分配足夠長度的緩衝區('new char [size]'),然後將該字符串複製到該緩衝區中。一旦你將指針返回給調用者,調用者有責任將其刪除(通過將結果賦給char *指針並在 –

+0

之後調用該指針上的delete),因此在上面的代碼中沒有辦法釋放分配的內存? – ontherocks

1

代碼中沒有錯誤只是泄露了char。但這很奇怪。

char* mycharheap() 
{ 
    char* ch = new char; //creates a pointer that points to a new char in the heap 
    ch = "Hello Heap"; //overwrites the pointer with const char - but this cast is legal. 
         //note: pointer to the previous char is lost 
    return ch;   //return the pointer to the constant area where "Hello heap" is stored. 
         //no, "Hello heap" is not on the heap. 
} 

對於「你想什麼:」部分,尤索林比我更快。

+0

所以這個也沒有任何錯誤的代碼也是類似的,如果不相同的話char * mycharheap() char * ch = new char []; ch =「Hello heap「; return ch; }' – ontherocks

+0

是的,幾乎是相同的,他們有同樣的問題 - 堆棧上沒有'Hello Heap''看看@Yossarian的答案,看看如何實現你想要的東西 – Csq

1

首先,如果您使用的是C++,請使用std::string來表示字符串。

現在你的問題。 char*是指向char(或char的數組)的指針。字符串文字(用引號引起來的東西)是數組類型爲char的只讀對象,存儲在某種只讀存儲器(堆棧或堆中)中。

由於char*是一個指針,指定它將改變指針。因此,mychar()mycharstack()都返回一個指向存儲在只讀存儲器中的字符串文字的指針。

mycharheap()只是泄漏。您使用new char在堆上分配一個char,然後忘記其地址並返回一個指向字符串文字的指針。我猜你的意思是這樣的:

char* mycharheap() { 
    char* ch = new char[strlen("Hello Heap") + 1]; 
    strcpy(ch, "Hello Heap"); 
    return ch; 
} 

然而,再次重申,不C使用char*字符串++。使用std::string

+0

如果我們有下列情況會怎麼樣:SET_ERROR_MESSAGE(false,(returnErrorCppString()。c_str()));大寫字母表示採用可變參數的宏。 – Zingam

+0

@Zingam嗯,什麼?這與問題或我的回答有什麼關係?你能詳細說明嗎? – Angew

+0

那麼,SET_ERROR_MESSAGE接受const char *的,但根據你的建議我會使用一個函數返回一個std :: string,那麼我需要將它轉換爲const char *才能使用它。 SET_ERROR_MESSAGE由第三方庫定義。 – Zingam

2

mycharstack()字符串存儲在堆棧中我猜,所以「ch」超出範圍,它不應該能夠返回字符串。它如何正確工作?

字符串文字是指存在於靜態內存中的數組。我希望你知道三個內存區域:自動內存(又名堆棧),自由存儲(又名堆)和靜態內存。堆棧中的東西只是一個指針變量,你可以通過值返回指針的值(它存儲的地址)。所以一切都很好,除非事實上你應該使用const char*作爲指針類型,因爲你不允許修改字符串文字引用的數組。

我猜存儲在mychar()中的字符串也在棧上。

字符串(字符數組)存儲在靜態內存中。 char*只是一個可以用來傳遞地址的指針類型。 const也缺失。

我猜還有其他代碼和內存泄漏錯誤,請讓我知道如果有的話。

泄漏在您的第三個功能。您只爲堆中的一個字符分配內存,並將其地址存儲到名爲ch的變量中。通過以下分配,您可以用字符串文字的地址覆蓋此地址。所以,你在泄漏記憶。

你似乎想到char*作爲字符串變量的類型。但事實並非如此。這是指向字符或字符序列的指針的類型。指針和它可能指向的字符串是兩個獨立的東西。你可能應該使用的是std :: string。

0

以下示例是我試圖從函數調用中獲取信息時出現的問題。

#include <iostream> 
#include <cstring> 
using namespace std; 

char* Xout(char* message); 

int main() 
{ 
const int LEN = 64; 
char message[LEN], *x; 

cin>>message; 

x=Xout(message); 
cout<<x; 
return 0; 
} 

char* Xout(char* message) 
{ 
int length=strlen(message); 
for(int i = 0; i < length; i++) 
{ 
    message[i] = 'X'; 
} 
return message; 
}