2014-10-09 96 views
0

我正在通過爲嵌入式項目創建一個String類來學習C++,並且我的String類串聯存在問題。在C++中我的字符串串聯有什麼問題?

這是我的主要方法和輸出

#include <iostream> 
#include "string.hpp" 

using namespace std; 

int main() { 
    String s1("hello "), s2("world"); 
    String s3 = s1 + s2; 
    cout << "s1=" << s1 << endl; 
    cout << "s2=" << s2 << endl; 
    cout << "s3=" << s3 << endl; 
    return 0; 
} 

s1=hello 
s2=world 
s3=hello 

而不是打印出來的 「hello world」,它打印只是 「你好」

這裏是我的string.hpp類:

#pragma once 
#include <cstring> 
#include <iostream> 

class String { 
public: 
    String() : c_str(NULL), len(0) 
    { 

    } 

    String(const String& str) : c_str(new char[str.len]), len(str.len) 
    { 
     strncpy(c_str, str.c_str, len); 
     c_str[len] = '\0'; 
    } 

    String(const char* str) : String(str, strlen(str)) 
    { 
     strncpy(c_str, str, len); 
     c_str[len] = '\0'; 
    } 

    String(const char* str, const int n) : len(n), c_str(new char[n+1]) 
    { 
     strncpy(c_str, str, len); 
    } 

    ~String() 
    { 
     delete[] c_str; 
    } 

    const char* get_c_str() 
    { 
     return c_str; 
    } 

    bool contains(const String &cmd, const size_t pos) 
    { 
     return strncmp(c_str+pos, cmd.c_str, cmd.len) == 0; 
    } 

    size_t length() 
    { 
     return len; 
    } 

    friend std::ostream& operator<<(std::ostream& os, const String obj) 
    { 
     os << obj.c_str; 
     return os; 
    } 

    friend void swap(String& s1, String& s2) 
    { 
     using std::swap; 
     swap(s1.c_str, s2.c_str); 
     swap(s1.len, s2.len); 
    } 

    bool operator==(const String& str) 
    { 
     return strncmp(c_str, str.c_str, len) == 0; 
    } 

    char operator[](const size_t i) 
    { 
     return c_str[i]; 
    } 

    String& operator=(const String& src) 
    { 
     String tmp(src); 
     swap(*this, tmp); 
     return *this; 
    } 

    String operator+(const String& rhs) 
    { 
     const size_t new_len = len + rhs.len; 
     char* new_c_arr = new char[new_len+1]; 

     strcpy(new_c_arr, c_str); 
     strcat(new_c_arr, rhs.c_str); 
     printf("new_c_arr=%s\n", new_c_arr); 
     return String(new_c_arr, len); 
    } 

    String operator+(const char* rhs) 
    { 
     const size_t new_len = len + strlen(rhs) + 1; 
     char* new_c_arr = new char[new_len]; 
     strcpy(new_c_arr, c_str); 
     strcat(new_c_arr, rhs); 
     return String(new_c_arr, new_len); 
    } 

private: 
    char* c_str; 
    int len; 
}; 

我在閱讀有關SO上的「大3」時尋找類似的問題,並不確定是否因此而發生。

+2

'return String(new_c_arr,len);' - 錯誤的長度 – Mat 2014-10-09 13:21:59

+0

使用C字符串函數有什麼意義?或者使用'std :: string'或者自己編碼,如果是爲了訓練目的 – Geoffroy 2014-10-09 13:22:40

+1

你的代碼泄漏了內存!在'operator +'中,你扔掉舊內容並分配新內存。 – Klaus 2014-10-09 13:25:08

回答

0

此代碼在許多方面被打破。

#pragma once 

實際包括警衛比#pragma once更便攜。

String() : c_str(NULL), len(0) 
    { 

    } 

您的默認構造函數使得c_str爲空;你的其他功能從來不檢查這種情況。請記住,即使是空的C字符串也有一個字符。

String(const String& str) : c_str(new char[str.len]), len(str.len) 
    { 
     strncpy(c_str, str.c_str, len); 
     c_str[len] = '\0'; 
    } 

你只分配str.len字符c_str,但你正在訪問c_str[len]

String(const char* str) : String(str, strlen(str)) 
    { 
     strncpy(c_str, str, len); 
     c_str[len] = '\0'; 
    } 

您委派的構造函數已經執行了副本。你爲什麼再次打電話strncpy

String(const char* str, const int n) : len(n), c_str(new char[n+1]) 
    { 
     strncpy(c_str, str, len); 
    } 

在這裏你不確定你的字符串是以null結尾的。

const char* get_c_str() 
    { 
     return c_str; 
    } 

應該標記const

bool contains(const String &cmd, const size_t pos) 
    { 
     return strncmp(c_str+pos, cmd.c_str, cmd.len) == 0; 
    } 

同上。而且你沒有檢查pos是否在範圍內。

size_t length() 
    { 
     return len; 
    } 

const

friend std::ostream& operator<<(std::ostream& os, const String obj) 
    { 
     os << obj.c_str; 
     return os; 
    } 

obj應該通過const引用傳遞,而不是通過值。

bool operator==(const String& str) 
    { 
     return strncmp(c_str, str.c_str, len) == 0; 
    } 

const再次,並且邏輯甚至不正確。通過這個邏輯,"something" == "something else"因爲你只是比較第一個len個字符。

char operator[](const size_t i) 
    { 
     return c_str[i]; 
    } 

如果您要返回副本,則應該是const。如果你想允許用戶修改存儲在字符串中的字符,那麼它應該返回char &。 (更妙的是,有兩個單獨的過載,一個const和一個非const

String operator+(const String& rhs) 
    { 
     const size_t new_len = len + rhs.len; 
     char* new_c_arr = new char[new_len+1]; 

     strcpy(new_c_arr, c_str); 
     strcat(new_c_arr, rhs.c_str); 
     printf("new_c_arr=%s\n", new_c_arr); 
     return String(new_c_arr, len); 
    } 

您正在構建新的字符串長度錯誤,也漏水new_c_arr。這個函數應該是const(並且實際上應該按照您沒有的operator+=來實現)。

String operator+(const char* rhs) 
    { 
     const size_t new_len = len + strlen(rhs) + 1; 
     char* new_c_arr = new char[new_len]; 
     strcpy(new_c_arr, c_str); 
     strcat(new_c_arr, rhs); 
     return String(new_c_arr, new_len); 
    } 

再次漏出new_c_arr;此外,此處包含空終止符new_len,而其他operator+中的版本不包含。您的構造函數採用長度不包含空終止符作爲長度的一部分。

+0

現在,這是徹底的。我想知道OP是否知道'const'的功能。 – 2014-10-09 13:49:52

+0

並非如此,我認爲這只是爲了不再繼承子類。 – jimjampez 2014-10-10 10:08:54

0

這是問題的方法String operator+(const String& rhs)行:

return String(new_c_arr, len); 

您需要改變爲這樣:

return String(new_c_arr, new_len+1); 

要初始化具有長度返回字符串等於第一部分只要。不是整個連接的字符串。

看到另一個運營商是好的。

順便說一下,您在operator+constructor中創建了很多新的char[]

operator+你在每次調用創建一個新的char[]並傳遞到字符串(後不刪除)的構造函數,並在構造函數創建一個新的char[]存儲是在刪除字符串的情況下, destructor,在operators中創建的新char[]被泄露。

+0

回答之前請先看看其他答案。然後你可能會發現你爲什麼錯了。 – gsamaras 2014-10-09 13:27:18

+0

我沒有看到其他答案之前我發佈我的,在這種情況下,我不會張貼,因爲幾乎相同。這裏真的很慢互聯網連接 – NetVipeC 2014-10-09 13:29:18

+0

是的,這發生了。至少你看到我的一個錯誤。但是,現在你有內存泄漏(而且OP的代碼也有更多問題)。 – gsamaras 2014-10-09 13:31:20