我正在通过为嵌入式项目创建一个String类来学习C ++,而我的String类有一个问题'串联。
这是我的主要方法和输出
#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
而不是打印出&#34; hello world&#34;,它只打印&#34;你好&#34;
这是我的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;
};
我读到了#3;大3&#34;在SO上寻找类似的问题而不确定是否因为这个问题。
答案 0 :(得分:0)
这是方法String operator+(const String& rhs)
中的问题:
return String(new_c_arr, len);
您需要更改为:
return String(new_c_arr, new_len+1);
您正在初始化返回的String,其长度仅等于第一部分。不是整个串联的字符串。
看到另一个操作员没问题。
顺便说一下,您在char[]
和operator+
中创建了大量新constructor
。
在operator+
的情况下,您在每次调用中创建一个新的char[]
并传递给string的构造函数(而不是删除之后),并且在构造函数中创建一个新的char[]
要存储destructor
中删除的字符串,char[]
中创建的新operators
会泄露。
答案 1 :(得分:0)
此代码以多种方式被破坏。
#pragma once
实际包含警卫比#pragma once
更便携。
String() : c_str(NULL), len(0)
{
}
您的默认构造函数使c_str
为null;你的其他功能永远不会检查这种情况。请记住,即使是空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+
中的版本则不包括空终止符。获取长度的构造函数似乎不包含null终止符作为长度的一部分。