2014-10-09 135 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