C 字符串实现错误
C++ string implementation error
我正在尝试在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()
,这意味着现在s
和this
共享相同的内部缓冲区
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_t
或unsigned int
而不是平原int
,因为大小总是大于或等于零。
与您的代码有有很多问题,让我们逐步进行此操作。
首先,您不需要命名空间的预处理器魔术,而只是基本的namespace mynamespace{}
。
其次,创建basic_string
类是理想的选择,以便可以与不同的字符类型一起使用。char
/wchar_t
,E.T.C。
您的课程问题:
1)private: const char *_str;
。指针将进行修改,因此const
是没有用的。
2)没有typedef
s。如果您试图重新实现STL类,则需要它们。(示例中解释)
3)使用allocator
。这样,您可以construct
和destroy
元素,allocate
和deallocate
内存。您将确定以这种方式保持记忆力更安全。
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。
- 在c++中实现LinkedList时,应出现未处理的错误
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 在 c++ 中实现 Trie 时出现分段错误
- C++ 实现模板单例类时出现链接错误
- 内存错误低于在C++年实现埃拉托色尼筛分时的预期
- C++数组队列实现方法错误
- 实现 DFS 在较短的输入下工作正常,但在较大的输入下会抛出分段错误
- 分段 排序函数实现中的错误
- 尝试从头开始实现Leetcode的FizzBuzz多线程问题。收到"libc++abi.dylib: terminating"错误
- 使用 std::forward_list 返回错误的队列实现
- 在我的trie实现中出现分段错误
- 在 c++ 中实现链表时出现分段错误
- 比较迭代器会使程序崩溃,而不会在自定义气泡排序实现中出现错误
- 如何知道C2259 VS 2017错误未实现哪种方法?
- 筛子的埃拉托色尼错误实现
- BAD_ALLOC错误实现向量调整大小函数时
- 头文件中包含.cpp重新定义错误-实现通用堆栈
- 程序没有给出期望的输出.FIFO的错误实现
- 这是卡达内算法的错误实现吗?
- 双链表错误实现Deque