2013-03-02 72 views
4

因此,在嘗試學習如何在C++中使用C-Strings時,我遇到了內存分配問題。我應該如何爲c字符串char數組分配內存?

這裏的想法是創建了一個新的字符串格式(s1 + sep + s2) 我正在使用的文本提供了標題,所以我無法更改,但我遇到了問題試圖設置char str []的大小。我得到一個錯誤,指出sLength不是常量,因此不能用於設置數組的大小。我對C++比較陌生,所以這是一個兩部分問題。

  1. 這個策略實際上是爲新陣列分配內存嗎?

  2. 如果我無法使用strlen(char *)得到一個常量值,我該如何正確設置數組大小?

    char* concatStrings(char* s1, char* s2, char sep){ 
        int sLength = strlen(s1) + strlen(s2) + 3; 
        //+1 for char sep +2 for \0 at end of string 
        char *str = new char[sLength]; 
        strcpy (str, s1); 
        str [sLength(s1)] = sep; 
        strcat (str, s2); 
        return str; 
    } 
    

編輯製作,所以現在我越來越沒有編譯器錯誤,但...

給函數的調用是在這裏:

char* str = concatStrings("Here is String one", "Here is String two" , c); 
    cout<< str; 

我的輸出變爲:

Here is String onec ================== 22221/21/21/21/2/(etc.) /這裏是S tring two

+4

您必須動態分配它。如果你是C++新手,我建議在查看C字符串之前堅持使用'std :: string'一段時間。不要選擇使用'std :: string'的C字符串,因爲存在各種問題。 – chris 2013-03-02 22:12:23

+0

你會得到什麼編譯器錯誤? – 2013-03-02 22:13:45

+0

@chris一般來說,我同意在C字符串上使用'std :: string'的建議。然而,OP明確指出這是一個學習練習,這是一個完全有效的理由(IMO)使用C字符串。 – 2013-03-02 22:14:41

回答

8

錯誤是返回本地數組變量的地址str。它的範圍在您聲明的功能concatStrings()之內,並且一旦控制從該功能返回就不能被訪問。

要在外部訪問它,需要使用new運算符爲堆中的字符串動態分配內存。

char* concatStrings(char* s1, char* s2, char sep){ 
    int s1Length = strlen(s1); 
    int sLength = s1Length + strlen(s2) + 2; 
    // +1 for sep and +1 \0 at end of string 
    char* str = new char[sLength]; 
    strcpy (str, s1); 
    // Use strlen here instead of sizeof() 
    str [s1Length] = sep; 
    str [s1Length + 1] = '\0'; 
    strcat (str, s2); 
    return str; 
} 

而且程序正在使用從concatStrings返回的字符串完成後,應確保通過調用delete

char* str = concatStrings(s1, s2, sep); 

// Do something 

// Free up memory used by str 
delete str; 

來釋放內存,我還編輯了concatStrings()功能使用strlen代替sizeof

更新:感謝您指出我們只需要做+2而不是+3,並確保在之後需要添加'\ 0'和sep調用strcat

+0

好的答案,雖然'strlen(s1)'應該被緩存;畢竟它是'O(N)'...... – 2013-03-02 22:28:24

+0

@gnome:strcat()add \ 0它你自己,你不需要明確 – 2013-03-02 22:28:48

+0

@亞歷克斯 - 良好的捕獲。 – Tuxdude 2013-03-02 22:29:24

1

sizeof(s1)返回指針變量的大小,而不是它指向的數組的長度。既然您知道s1指向一個C字符串,您應該使用strlen()函數。

+0

謝謝你,我原本是用sizeof()來代替它,並且意味着改變它們,錯過了一個。 – 2013-03-02 22:14:17

+0

@KurtVonDaimondorf您的代碼還存在其他問題。在擴展我的答案之前,您能否使用編譯器錯誤編輯您的問題? – 2013-03-02 22:16:09

+0

昨天我編輯了兩個答案,你在這兩個表單上。 – 2013-03-03 07:27:40

3

之前,可以(對於多個C般的風格或malloc)分配產生的字符串存儲器動態(在運行時,在堆上),在C使用new[] ++:

char* concatStrings(const char* s1, const char* s2, char sep) // enforced const correctness 
{ 
    const size_t totalLength = strlen(s1) + strlen(s2) 
          + 2; // +1 for sep char, +1 for '\0' 

    // Dynamically allocate room for the new string (on the heap) 
    char* str = new char[totalLength];  

    strcpy(str, s1); 
    str[strlen(s1)] = sep; // note that you had a typo with sizeof(s1) here 
    strcat(str, s2); 
    return str; 
} 

請注意,如果使用delete[]分配了new[],或者使用malloc()分配了free(),則必須在代碼的某處釋放此內存。

這很複雜。

您將簡化代碼很多,如果你使用強大的C++字符串類std::string,以其方便構造函數來分配內存,析構函數自動釋放它,operator+operator+=重載連接字符串。看看你的代碼是使用std::string簡化:

#include <string> // for std::string 

std::string str = s1; 
str += sep; 
str += s2; 

(請注意,使用原始的C字符串也可以使你的代碼更容易受到安全問題,因爲你必須付出很多的注意適當大小的目標字符串,避免緩衝超過等等。這是另一個喜歡像std::string這樣的強健字符串類的另一個原因。)