Я занимаюсь C++.
Я реализую класс String в двух версиях. в первой версии текст сохраняется в массиве. во второй версии текст сохраняется в динамической памяти распределения. вторая версия наследует первую.
первая версия работает нормально. во второй версии, в первой строке функции concat, я получаю исключение для плохого выделения.
это код:
#include<iostream>
#include<string>
using namespace std;
class String{
protected:
enum{SIZE=256};
void setLen(const int length)
{
m_len = length;
}
private:
int m_len;
char m_text [SIZE];
public:
String()
{
m_len = 0;
strcpy_s (m_text, 1, "");
}
String(const char* text)
{
m_len = strlen(text);
strcpy_s (m_text, strlen(text) + 1, text);
}
const char* get() const
{
return m_text;
}
virtual void set(char* text)
{
strcpy_s (m_text, strlen(text) + 1, text);
}
int getLen() const
{
return m_len;
}
virtual void concat(const String &s)
{
strcat_s(m_text, strlen(m_text) + strlen(s.get()) + 1, s.m_text);
}
bool equal(const String &s)const
{
return strcmp(s.m_text, m_text);
}
bool operator ==(const String &s)const
{
return strcmp(s.m_text, m_text);
}
virtual void print()const
{
cout<<m_text;
}
};
class PointString :public String {
char* m_text;
public:
PointString()
{
setLen(0);
m_text = new char[1];
strcpy_s(m_text, 1,"");
}
PointString(const char* text)
{
setLen(strlen(text));
m_text = new char[strlen(text)+1];
strcpy_s(m_text, strlen(text)+1 ,text);
}
void set(char* text)
{
delete [] m_text;
setLen(strlen(text));
m_text = new char[strlen(text)+1];
}
void concat(const String &s)
{
char *temp = new char[strlen(m_text) + strlen(s.get())];
strcpy_s(temp, SIZE, m_text);
strcat_s(m_text,strlen(m_text) + strlen(s.get()) + 1, s.get());
delete [] m_text;
m_text = temp;
}
void print()const
{
cout<<m_text<<endl;
}
};
void main()
{
PointString str("1234");
str.print();
str.concat("8901");
str.print();
system("pause");
}
Вопрос в том, это в concat
вызова:
char *temp = new char[strlen(m_text) + strlen(s.get())]; // 1
strcpy_s(temp, SIZE, m_text);
strcat_s(m_text, strlen(m_text) + strlen(s.get()) + 1, s.get()); // 2
delete[] m_text;
m_text = temp;
Для issue //1
вы не выделили достаточно места для строки. Вы забыли завершающую запись NULL.
Для проблемы //2
вы объединяетесь в m_text
прежде чем он будет правильно m_text
.
Использование стандартных строковых функций приводит к следующим изменениям:
char *temp = new char[strlen(m_text) + strlen(s.get()) + 1];
strcpy(temp, m_text);
strcat(temp, s.get());
delete[] m_text;
m_text = temp;
Используя безопасные строковые функции Microsoft, вы должны сохранить длину новой строки в переменной и использовать ее в каждом вызове. Указание SIZE
не кажется правильным. Вот что работает для меня:
void concat(const String &s)
{
size_t sz = strlen(m_text) + strlen(s.get()) + 1;
char *temp = new char[sz];
strcpy_s(temp, sz, m_text);
strcat_s(temp, sz, s.get());
delete[] m_text;
m_text = temp;
}
Существуют и другие проблемы с вашим кодом. Один из них - отсутствие деструктора, поэтому у вас есть утечки памяти всякий раз, когда вы создаете PointString
. Другая проблема заключается в том, что копирование и назначение PointString
другой PointString
будет работать некорректно из-за отсутствия пользовательского конструктора копирования и оператора присваивания.
Пожалуйста, ознакомьтесь с приведенными выше темами, поскольку класс строк, который не может создавать собственные копии, практически не стоит использовать (если вы собираетесь его использовать), помимо того, что он вообще не используется, из-за присутствия утечек памяти (без деструктора).
Если вы удаляете себя с этапа "домашней работы", класс std::string
выполняет всю работу, которую вы сейчас выполняете, за исключением более безопасной и эффективной.
m_text
дляnew char[]
, но не обязательно помещаете'\0'
в массив (в зависимости от того, какой конструктор используется). Если нет нулевого терминатора, поведениеstrlen
не определено.PointerString
в том, чтобыPointerString
наследовал символьный массив изString
.