6-16 我自己写字符串类(基础版)(PTA)

完成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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值