完成MyString
类的实现,使程序正确运行
裁判测试程序样例:
#include <iostream>
#include <cstring>
using namespace std;
class MyString {
public:
// 无参构造函数
// 空字符串可以考虑使用new char[1],并设置字符串结束符
MyString();
// 构造函数,传入一个C语言风格字符串
MyString(const char *s);
// 拷贝构造函数
MyString(const MyString &s);
// 析构函数
~MyString();
// 返回子串 [pos, pos+count)
// 若请求的子串越过字符串的结尾,即count大于size() - pos,则返回的子串为[pos, size())
// 若pos不在字符串的下标范围内,返回空的MyString对象
// 若count == -1,返回子串[pos, size())
// 可以考虑使用strncpy
MyString substr(int pos = 0, int count = -1);
// 返回下标为pos的字符的引用
char& at(int pos);
// 字符串的长度
int size();
// 返回C语言风格的字符串
const char* c_str();
private:
char *m_buf;
int m_size;
};
// 请将答案填写在这里
int main() {
char s[101];
cin.getline(s, 101);
int pos, count;
cin >> pos >> count;
// 创建、拷贝、空字符串
MyString s1(s), s2(s1), s3;
s1.at(0) = 'x';
s2.at(0) = 'X';
cout << "s1: " << s1.c_str() << endl;
cout << "s2: " << s2.c_str() << endl;
cout << "s3: " << s3.c_str() << endl;
// 取子串
cout << "substr: " << s2.substr(pos, count).c_str() << endl;
// 以后还可以直接使用<<输出一个MyString对象哦 TODO
// cout << s1 << endl;
return 0;
}
输入样例:
第一行:输入字符串,长度最大为100
第二行:取子串时的下标和长度
abcdefg
0 3
输出样例:
在这里给出相应的输出。例如:
s1: xbcdefg
s2: Xbcdefg
s3:
substr: Xbc
前言 :
今天写的题目虽然不是很难但很考验基本语法,由于是基本语法,所以我会讲的比较细,题目要求补全类内成员函数的定义,使得满足输入和输出要求。说实话,写的有点折磨,主要是c语言风格的字符串char* 太久没用了,忘了挺多,这道题相当于复习一遍语法知识吧,我会从上往下一个一个讲解函数定义,废话不多说,开始讲解。
正文:
首先讲第一点,类外定义类内的成员函数,需要不同于常规函数的格式,格式如下
返回值类型 类名::成员函数名(声明时里面是什么,照着写就行)
{
}
需要注意的是,带默认参数的缺省函数,声明和定义只能存在一个默认参数,也就是说,如果你声明时函数里面带默认参数,定义时函数就不能携带默认参数。
构造函数和析构函数的使用自己去查吧,网上有很多讲的很全面的,这里就不过多赘述了
第一个函数:
无参构造函数,按题意可以先动态分配一个char类型
设置字符结束串,我的理解是让第一个元素初始化就是'\0'
最后不要忘记设置长度为0,维护长度很重要。
第二个函数:
传入的是一个c语言风格的字符串,由于是const类型,无法直接让m_buf = s,正确的做法应该是动态开辟一段内存给m_buf,长度就是传进来的字符串的长度加一,加一是为了存放'\0'。再之后用拷贝函数将s的值拷贝到m_buf中。
第三个函数:
传进来的是一个类的对象,做法也一样是开辟内存然后用函数拷贝过来。这里的this是显式的指名m_size是这个类里的一个属性成员,如果属性成员和形参同名,那么使用this就会指名它是属性成员,而不是形参。
第四个函数:
析构函数会在被创建的对象销毁时自动调用,所以是处理末尾的,这时候把动态分配的内存给手动释放掉,避免内存泄漏。
第五个函数:
MyString MyString::substr(int pos, int count )
{
MyString q;
//检查pos有效性
if (pos < 0 || pos >= m_size) return q;
//总长是m_size,起始是pos,如果count无效
//那么长度就是m_size - pos,m_size用了函数
if (count == -1 || count > m_size - pos)
{
//重新分配q的内存
delete []q.m_buf;
q.m_buf = new char[m_size - pos + 1];
//这一段,把m_buf的内容拷贝到q的m_buf中
//m_buf要加上pos,因为位置是从这里开始的
//最后拷贝的长度就是题目要求的
strncpy(q.m_buf, m_buf + pos, m_size - pos);
//字符数组最后要赋值'\0'
q.m_buf[m_size - pos] = '\0';
//更新长度
q.m_size = m_size - pos;
}
else //长度就是count了
{
delete []q.m_buf;
q.m_buf = new char[count + 1];
strncpy(q.m_buf, m_buf + pos, count);
q.m_buf[count] = '\0';
q.m_size = count;
}
return q;
}
这个函数应该是最让我头痛的,比较考验c语言风格字符串的基本功。
1.首先返回的是MyString类型的函数,所以函数体内肯定会先声明一个MyString的对象
2.按照要求,这里先写简单的pos合规的判断,字符串最长长度也就是m_size了,pos代表的是下标,所以m_size不能取到,判断要用>= (多提一嘴免得有些人忘记为什么直接返回q就是空的MyString对象了,因为前面我们定义了一个默认无参的构造函数,在声明的时候就会自动调用这个函数,而函数里面已经做了初始化)
3.将count == -1 和count超过总长合在一起判断,因为它们返回的子串是一样的。第一步就是重新分配内存,因为初始化时已经分配过一次了,现在需要一个长度能接收m_size的内存,那就先销毁再分配,最后用一个拷贝函数从pos开始的位置返回m_size - pos个长度的子串。别忘了在字符数组的最后添上'\0',同时还要维护长度。
4.剩下最后一个要求就是返回子串 [pos, pos+count),按要求写就行了。
(多提一嘴strncpy,第一个参数是要接收拷贝的,第二个参数是拷贝开始的位置,第三个参数则是从这个位置开始要拷贝多长)。
第六个函数:
这个很简单,直接用数组表示法返回就行了
第七个函数:
第八个函数:
m_buf的类型就是char *,这就是c语言风格的字符串,直接返回就行了
完整代码如下:
MyString::MyString()
{
m_buf = new char[1];
m_buf[0] = '\0';
m_size = 0;
}
MyString::MyString(const char *s)
{
m_size = strlen(s);
m_buf = new char[m_size + 1];
strcpy(m_buf, s);
}
MyString::~MyString()
{
delete []m_buf;
}
MyString::MyString(const MyString &s)
{
m_size = s.m_size;
m_buf = new char[m_size + 1];
strcpy(m_buf, s.m_buf);
}
MyString MyString::substr(int pos, int count )
{
MyString q;
//检查pos有效性
if (pos < 0 || pos >= m_size) return q;
//总长是m_size,起始是pos,如果count无效
//那么长度就是m_size - pos,m_size用了函数
if (count == -1 || count > m_size - pos)
{
//重新分配q的内存
delete []q.m_buf;
q.m_buf = new char[m_size - pos + 1];
//这一段,把m_buf的内容拷贝到q的m_buf中
//m_buf要加上pos,因为位置是从这里开始的
//最后拷贝的长度就是题目要求的
strncpy(q.m_buf, m_buf + pos, m_size - pos);
//字符数组最后要赋值'\0'
q.m_buf[m_size - pos] = '\0';
//更新长度
q.m_size = m_size - pos;
}
else //长度就是count了
{
delete []q.m_buf;
q.m_buf = new char[count + 1];
strncpy(q.m_buf, m_buf + pos, count);
q.m_buf[count] = '\0';
q.m_size = count;
}
return q;
}
char& MyString::at(int pos)
{
return this->m_buf[pos];
}
int MyString::size()
{
return m_size;
}
const char* MyString::c_str()
{
return m_buf;
}