C 字符串实现错误

C++ string implementation error

本文关键字:错误 实现 字符串      更新时间:2023-10-16

我正在尝试在C 中实现基本的string类。但是,我被卡在append()功能上。它希望它是Hello World,但结果为Hello ÍWorlýýýý««««««««þ

#define __START namespace lib{
#define __END }
__START
class string
{
public:
    string(const char* s)
    {
        _str = s;
    }
    const char operator[](int position)
    {
        return _str[position];
    }
    void operator=(string s)
    {
        _str = s.c_str();
    }
    void append(string s)
    {
        size_t nlength = (length() + s.length());
        char* nstr = new char[nlength];
        for (int i = 0; i < length(); ++i)
        {
            nstr[i] = _str[i];
        }
        for (int i = length() + 1; i < nlength; ++i)
        {
            nstr[i] = s[(i - length() - 1)];
        }
        _str = const_cast<const char*>(nstr);
    }
    void operator+=(string s)
    {
        append(s);
    }
    const char* c_str()
    {
        return _str;
    }
    size_t length()
    {
        return strlen(_str);
    }
    std::string str()
    {
        return _str;
    }
private:
    const char* _str;
};
__END

int main()
{
    lib::string s = "Hello ";
    s.append("World"); // s += "World";
    std::cout << s.c_str();
    getchar();
}

有很多错误,不仅有附录

string(const char* s)
{
    _str = s;
}

构造函数是错误的,您应该制作s的副本,以便以后将其释放,这样:

~string()
{
    delete[] _str; // or free(_str) in case you use malloc/realloc, thanks Fred!
}

私人成员变量:

private:
    const char* _str;

内部字符串不应是const,您应该能够在以后进行调整

const char operator[](int position)
{
    return _str[position];
}

您缺少检查:length() > position

void operator=(string s)
{
    _str = s.c_str();
}

您没有修改s,应该是const string& s您也不复制s.c_str(),这意味着现在sthis共享相同的内部缓冲区

void append(string s) // s should be a const reference too
{
    size_t nlength = (length() + s.length());
    char* nstr = new char[nlength];
    for (int i = 0; i < length(); ++i)
    {
        nstr[i] = _str[i];
    }
    for (int i = length() + 1; i < nlength; ++i)
    {
        nstr[i] = s[(i - length() - 1)];
    }
    _str = const_cast<const char*>(nstr);
}

应该更容易用realloc

编写
void append(string s)
{
    int start = length();
    _str = realloc(_str, length() + s.length());
    for (int i = 0; i < s.length(); i++) {
        _str[start+i] = s[i];
    }
}

如果要坚持使用new,则必须在将其分配给新的_str之前。

以下操作员应为const:

const char* c_str() const;
size_t length() const;
std::string str();

更新:构造函数的选项:

// option one (use delete[] to cleanup _str)
string(const char* s) {
    int n = strlen(s);
    _str = new char[n+1];
    memcpy(_str, s, n+1); // s is NULL terminated
}
// option two (use free() to cleanup _str)
string(const char* s) {
    int n = strlen(s);
    _str = (char*)malloc(n+1);
    memcpy(_str, s, n+1); // s is NULL terminated
}
// option 3: rely on append taking a char* argument
string(const char *s) : _str(NULL) {
    append(s, strlen(s));
}
..
void append(const string& s) {
    append(s.c_str(), s.length())
}
void append(const char *s, int len) {
  int start = _str ? length() : 0;
  _str = realloc(_str, start + len);
  for (int i = 0; i < len; i++) {
      _str[start+i] = s[i];
  }
}

更新2 :最好使用size_tunsigned int而不是平原int,因为大小总是大于或等于零。

与您的代码有有很多问题,让我们逐步进行此操作。

首先,您不需要命名空间的预处理器魔术,而只是基本的namespace mynamespace{}

其次,创建basic_string类是理想的选择,以便可以与不同的字符类型一起使用。char/wchar_t,E.T.C。

您的课程问题:

1)private: const char *_str;。指针将进行修改,因此const是没有用的。

2)没有typedef s。如果您试图重新实现STL类,则需要它们。(示例中解释)

3)使用allocator。这样,您可以constructdestroy元素,allocatedeallocate内存。您将确定以这种方式保持记忆力更安全。

4)字符串必须终止。这意味着最后一个额外的'',这意味着您必须为此分配额外的字节。字符串被终止终止,因为这是告诉代码停止读取字符串的一种方式。

5)您将分配给尚未分配的字符串。_str = s.c_str();可能会根据您的编译器很容易崩溃,因为您正在写入未分配的内存。

6)使用const引用,而不是用于参数的普通类型(string = const string &)。您还需要您的复制构造函数basic_string(const _Myt &)

我仍然没有突出显示问题的全部

示例basic_string class

template < typename _Elem, typename _Traits = std::char_traits<_Elem>, typename _Alloc = std::allocator<_Elem> > class basic_string
{
public:
    typedef basic_string<_Elem, _Traits, _Alloc> _Myt;
    typedef _Elem value_type;
    typedef _Traits traits_type;
    typedef _Alloc  allocator_type;
    typedef value_type *pointer;
    typedef const value_type *const_pointer;
    typedef value_type *iterator;
    typedef const value_type *const_iterator;
    typedef value_type &reference;
    typedef const value_type &const_reference;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    basic_string()
    {
        __data = _Alloc().allocate(1);
        _Alloc().construct(&__data[0], '');
    }
    basic_string(const_pointer _Init)
    {
        int count = 0;
        __data = _Alloc().allocate(_Traits::length(_Init) + 1);
        for (const_iterator i = &_Init[0]; i != &_Init[_Traits::length(_Init)]; ++i, ++count)
        {
            _Alloc().construct(&__data[count], *i);
        }
        _Alloc().construct(&__data[_Traits::length(_Init)], '');
    }
    basic_string(const _Myt &_Init)
    {
        if (this != &_Init)
        {
            int count = 0;
            __data = _Alloc().allocate(_Traits::length(_Init.__data) + 1);
            for (const_iterator i = &_Init.__data[0]; i != &_Init.__data[_Traits::length(_Init.__data)]; ++i, ++count)
            {
                _Alloc().construct(&__data[count], *i);
            }
            _Alloc().construct(&__data[_Traits::length(_Init.__data)], '');
        }
        else
        {
            __data = _Alloc().allocate(1);
            _Alloc().construct(&__data[0], '');
        }
    }
    ~basic_string()
    {
        if (__data)
        {
            size_type tmp = size();
            for (iterator i = begin(); i != end(); ++i)
            {
                _Alloc().destroy(i);
            }
            _Alloc().deallocate(__data, tmp);
        }
    }
    _Myt &assign(const_pointer _Rhs)
    {
        int count = 0;
        reserve(_Traits::length(_Rhs) + 1);
        for (const_iterator i = &_Rhs[0]; i != &_Rhs[_Traits::length(_Rhs)]; ++i, ++count)
        {
            _Alloc().construct(&__data[count], *i);
        }
        _Alloc().construct(&__data[_Traits::length(_Rhs)], '');
        return *this;
    }
    _Myt &operator=(const_pointer _Rhs)
    {
        return assign(_Rhs);
    }
    _Myt &append(const_pointer _Rhs)
    {
        int count = size();
        reserve(size() + _Traits::length(_Rhs) + 1);
        for (const_iterator i = &_Rhs[0]; i != &_Rhs[_Traits::length(_Rhs)]; ++i, ++count)
        {
            _Alloc().construct(&__data[count], *i);
        }
        _Alloc().construct(&__data[count], '');
        return *this;
    }
    _Myt &operator+=(const_pointer _Rhs)
    {
        return append(_Rhs);
    }
            iterator begin()
    {
        return &__data[0];
    }
    iterator end()
    {
        return &__data[size()];
    }
    size_type size()
    {
        return _Traits::length(__data);
    }
    _Myt &swap(basic_string<_Elem> &_Rhs)
    {
        std::swap(__data, _Rhs.__data);
        return *this;
    }
    void reserve(size_type _Size)
    {
        int count = 0;
        if (_Size < size())
        {
            return;
        }
        pointer buf = _Alloc().allocate(_Size);
        for (iterator i = begin(); i != end(); ++i, ++count)
        {
            _Alloc().construct(&buf[count], *i);
        }
        std::swap(__data, buf);
        for (iterator i = &buf[0]; i != &buf[_Traits::length(buf)]; ++i)
        {
            _Alloc().destroy(i);
        }
        _Alloc().deallocate(buf, _Traits::length(buf));
    }
    operator const_pointer()
    {
        return __data;
    }
    operator pointer()
    {
        return __data;
    }
    template < typename _Traits1, typename _Alloc1 > friend std::basic_ostream<_Elem> &operator<<(std::basic_ostream<_Elem> &_Stream, basic_string<_Elem, _Traits1, _Alloc1> &_Str)
    {
        return _Stream << _Str.c_str();
    }
    const_pointer data() const
    {
        return __data;
    }
    const_pointer c_str() const
    {
        return __data;
    }
private:
    pointer __data;
};
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;

当然,仍然有些缺少,但是我敢肯定您可以在线帮助。

首先,您最关键的问题是在char* nstr = new char[nlength];中。

您必须将其更改为char* nstr = new char[nlength+1];

然后,在功能append中,在两个for循环之后,设置nstr[nlength] = 0;

第二,要获得更好的性能(以及正确的编码),您可能需要在以下功能中将string s更改为const string& s

void operator=(string s)
void append(string s)
void operator+=(string s)

您在第二个循环中有一个逐一错误;第一个末尾之后,第二个字符串需要复制到length()

for (int i = length(); i < nlength; ++i)
{
    nstr[i] = s[i - length()];
}

您还需要再分配一个字节才能在末尾放置一个空终结器。

请注意,您不需要那种令人恐惧的演员即可将const添加到指针中,因为这是一件非常安全的事情。const_cast仅需要删除预选赛。您可能还需要修复内存泄漏,并且要奖励点,请缓存长度,因此您不必每次都要读取整个字符串。

for (int i = length() + 1; i < nlength; ++i)
{
    nstr[i] = s[(i - length() - 1)];
}

您首先将字符复制到Length() - 1,然后以lenthe() 1重新启动,因此您跳过一个char,分配后可能会有任何东西(除非您事先进行MEMSET)。P>

然后,您需要使用null字符( 0)终止字符串,以便在str()方法上构造的std::string返回返回何时停止阅读chars。