经典面试题—string类的详细分析与实现

标签: 经典面试题 C++ string类的实现
16人阅读 评论(0) 收藏 举报
分类:
【摘要】在常见的面试场景中,如果面试官想要考察你对于C++的掌握程度
能够很完整的写出一个string类是很重要的。因为string类包含了C++的
很多知识,可以系统的将你的知识发挥出来。在这篇博客中,我将会详细地
说明string类的实现过程,方便你们理解。
   目录
          string类的成员分析
 
          想要完成的常见操作

          实现过程
 
          测试代码

          总结

1.要构建一个类,必须要具有基本的一些函数,比如构造函数和析构函数
       如果要进行赋值操作或者拷贝操作,那就还得有拷贝构造函数和赋值运算符重载为了方便,我把所有的函数都放在类的内部完成,这样可以最大限度的避免成员使用权限问题。但是,当工程量比较大时我并不建议这么做,这样很容易导致混淆。
2.分析string类的需求
 我们想要完成的string类,可以进行一些基本的增删查改操作,它是动态的存储,所以内存不够时还需要扩容。通过运算符的重载我们还可以完成一些字符串的+操作,比较大小操作,这些就是我们基本要完成的东西。
3.实现过程
1.既然是对字符串进行操作,那么我们就需要做第一个工作,完成字符串的构造函数还有字符串的拷贝构造函数和赋值操作符重载,有了构造函数,那么相对应的也就需要一个析构函数用于内存的动态释放
这只是第一步
2.如果内存大小不够继续进行操作时,还需要一个动态开辟内存的函数
3.要实现增删查改的第一步,尾部插入一个字符或者一个字符串,尾部删除一个字符,关于尾部删除一个字符串的操作也就是
删除一个字符的情况的变形,还有一种情况就是在任意位置插入一个字符或者字符串
4.第四步就是操作符的重载函数了。关于/+=(一个字符)/+=(一个字符串)/+(一个字符)/+(一个字符串)/
关于 />/</>=/<=/==/!=/这些基本上都只要复用函数的返回值就可以实现了,因此只需要实现两个函数即可
5.查找函数的实现,查找一个字符或者一个子串
6.替换函数:替换一个字符或者替换一个字符串

代码如下
#define _CRT_SECURE_NO_WARNINGS -1

#include <new.h>
#include <iostream>
using namespace std;

class String
{
public:
    //构造函数
    String(const char* str = "")
        :_str(new char[strlen(str) + 1])
    {
        strcpy(_str, str);
        _size = strlen(str);
        _capacity = _size;
    }

    ////拷贝构造函数
    //String(const String& s)//传统写法
    //  :_str(new char[s._capacity])
    //{
    //  strcpy(_str, s._str);
    //  _size = s._size;
    //  _capacity = s._capacity;
    //}

    ////赋值操作符重载
    //String& operator=(String s)//传统写法
    //{
    //  if (this != &s)
    //  {
    //      char* tmp = new char[strlen(s._str) + 1];
    //      delete[] _str;
    //      strcpy(_str, s._str);
    //      _size = s._size;
    //      _capacity = s._capacity;
    //  }

    //  return *this;
    //}

    // s1.Swap(s2); 
    void Swap(String& s)
    {
        char* tmp = _str;
        _str = s._str;
        s._str = tmp;
    }
    // 拷贝构造函数
    // String s2(s1) 
    String(const String& s)//现代写法
        :_str(NULL)
    {
        String tmp(s._str);
        this->Swap(tmp);
        _size = s._size;
        _capacity = s._capacity;
    }
    //赋值操作符重载
    // s1 = s2 
    String& operator=(String s)//现代写法
    {
        if (this != &s)
        {
            String tmp(s._str);
            this->Swap(s);
            _size = s._size;
            _capacity = s._capacity;
        }
        return *this;   
    }
    //析构函数
    ~String()
    {
        if (_str != NULL)
        {
            delete[] _str;
            _str = NULL;
            _size = 0;
            _capacity = 0;
        }
    }
    //获取类中的字符串成员变量
    const char* c_str()
    {
        return _str;
    }

    //扩容
    void Expand(size_t n)
    {
        if (n > _capacity)
        {
            char* tmp = new char[n + 1];
            strcpy(tmp, _str);
            delete[] _str;
            _str = tmp;
            _capacity = n;
        }
    }
    //尾插一个字符
    void PushBack(char ch)
    {
        if (_size >= _capacity)
        {
            Expand(_capacity * 2);
        }
        _str[_size++] = ch;
        _str[_size] = '\0';
    }
    //尾插一个字符串
    void PushBack(const char* str)
    {
        if (str == NULL)
        {
            return;
        }
        int len = strlen(str);
        if (_size + len > _capacity)
        {
            Expand(_size + len);
        }
        strcpy(_str + _size, str);
        _size += len;
    }
    //+操作符重载,+一个字符
    String operator+(char ch)
    {
        String tmp(*this);
        tmp.PushBack(ch);
        return tmp;
    }
    //+=操作符重载,+=一个字符
    String& operator+=(char ch)
    {
        //this->PushBack(ch);
        PushBack(ch);
        return *this;
    }

    //+操作符重载,+一个字符串
    String operator+(const char* str)
    {
        String tmp(*this);
        tmp.PushBack(str);
        return tmp;
    }
    //+=操作符重载,+=一个字符串
    String& operator+=(const char* str)
    {
        //this->PushBack(str);
        PushBack(str);
        return *this;
    }
    //尾删一个字符
    void PopBack()
    {
        _str[_size] = '\0';
        _size--;
    }
    //指定位置插入一个字符
    void Insert(size_t pos, char ch)
    {
        if (pos > _size)//插入位置不合法
        {
            return;
        }
        if (_size >= _capacity)//扩容
        {
            Expand(_capacity * 2);
        }
        if (pos == _size)
        {
            _str[_size++] = ch;
        }
        else
        {
            char* tmp = new char[_size - pos + 1];
            strcpy(tmp, _str + pos);
            _str[pos] = ch;
            strcpy(_str + pos + 1, tmp);
            _size++;
            delete[] tmp;
        }
    }
    //指定位置插入一个字符串
    void Insert(size_t pos, const char* str)
    {
        if (pos > _size || str == NULL)
        {
            return;
        }
        int len = strlen(str);
        if (_size + len > _capacity)//扩容
        {
            Expand(_size + len);
        }
        if (pos == _size)
        {
            strcat(_str, str);
        }
        else
        {
            char* tmp = new char[_size - pos + 1];
            strcpy(tmp, _str + pos);
            strcpy(_str + pos,str);
            strcpy(_str + pos + len, tmp);
            ////或直接使用strcat
            //strcat(_str, tmp);
            delete[] tmp;
        }
    }
    //删除pos下标开始往后n个元素
    void Erase(size_t pos, size_t n = 1)
    {
        if (pos > _size)
        {
            return;
        }
        char* str = _str + pos;
        while (*str != '\0' && n > 0)
        {
            *str = '\0';
            str++;
            n--;
            _size--;
        }
        strcpy(_str + pos, str);
    }
    //查找字符串中的某个字符
    size_t Find(char ch)
    {
        char* str = _str;
        while (*str != '\0')
        {
            if (*str == ch)
            {
                return (int)(str - _str);
            }
            str++;
        }
        return -1;
    }
    //查找第一个子串的的位置
    size_t Find(const char* str)
    {
        if (str == NULL)
        {
            return -1;
        }
        char* tmp = strstr(_str, str);
        if (tmp != NULL)
        {
            return (size_t)(tmp - _str);
        }
        return -1;
    }
    //更改字符串中的某个字符
    void Replace(char ch1, char ch2)
    {
        char* str = _str;
        while (*str != '\0')
        {
            if (*str == ch1)
            {
                *str = ch2;
            }
            str++;
        }
    }
    //替换字符串中的某个字串
    void Replace(const char* sub1, const char* sub2)
    {
        if (sub1 == NULL || sub2 == NULL || strcmp(sub1, sub2) == 0)
        {
            return;
        }
        size_t pos = Find(sub1);
        if (pos != -1)
        {
            char* str = _str;
            int len = strlen(_str);
            int len1 = strlen(sub1);
            int len2 = strlen(sub2);

            if (len1 == len2)
            {
                while (pos != -1)
                {
                    _str = _str + pos;
                    int i = 0;
                    while (i < len1)
                    {
                        _str[i] = sub2[i];
                        i++;
                    }
                    pos = Find(sub1);
                }
                _str = str;
            }
            else
            {
                int count = 0;
                char** arr = new char*[len];
                memset(arr, 0, sizeof(char*)*len);
                while (pos != -1)
                {
                    _str =_str + pos + 1;
                    arr[count] = _str - 1;
                    count++;
                    pos = Find(sub1);
                }
                _str = str;
                int capacity = len + count*(len2 - len1);
                char* newStr = new char[capacity + 1];
                memset(newStr, 0, capacity + 1);
                count = 0;
                char* cur = newStr;
                while (*_str != '\0')
                {
                    if (_str == arr[count])
                    {
                        for (int i = 0; i < len2; i++)
                        {
                            cur[i] = sub2[i];
                        }
                        _str += len1;
                        cur += len2;
                        count++;
                    }
                    else
                    {
                        *cur++ = *_str++;
                    }   
                }
                _str = newStr;
                _size = capacity;
                _capacity = capacity;
                newStr = str;
                delete[] newStr;
            }
        }
        else
        {
            return;
        }
    }

    // >操作符重载,比较字符串大小
    bool operator>(const String& s)
    {
        if (this == &s || strcmp(_str, s._str) > 0)
        {
            return true;
        }
        return false;
    }
    // =操作符重载,判断字符串是否相等
    bool operator==(const String& s)
    {
        if (this == &s || strcmp(_str, s._str) == 0)
        {
            return true;
        }
        return false;
    }
    bool operator>=(const String& s)
    {
        if (*this > s && *this == s)
        {
            return true;
        }
        return false;
    }
    bool operator<(const String& s)
    {
        if (!(*this >= s))
        {
            return true;
        }
        return false;
    }
    bool operator<=(const String& s)
    {
        if (!(*this > s))
        {
            return true;
        }
        return false;
    }
    bool operator!=(const String& s)
    {
        if (!(*this == s))
        {
            return true;
        }
        return false;
    }

private:
    //char _buffer[16];
    char* _str;
    size_t _size;
    size_t _capacity;
};

int main()
{   
    //String s1("abc");
    //String s2(s1);
    //String s3("123abc");
    //s3 = s1;
    //cout << (s3 + 'd').c_str() << endl;
    //cout << (s3 + 'e').c_str() << endl;
    //cout << (s3 + 'f').c_str() << endl;
    //cout << (s3 + 'g').c_str() << endl;
    //cout << (s3 + 'h').c_str() << endl;
    //s3 += "123456";
    //s3.Insert(1, 'x');
    //s3.Insert(2, 'y');
    //s3.Insert(3, 'z');
    //s3.Insert(1, '0');
    //s3.Insert(0, "789");
    //cout << s3.Find('a') << endl;
    //s3.Replace('a', '1');
    //cout << s3.Find('a') << endl;
    //s3.Erase(0, 3);
    ////string s="abc123abc";
    ////s = s.replace("abc", "xx");
    //cout << s3.Find('b') << endl;
    //cout << s3.Find('w') << endl;

    String s("abc123");
    s.Replace("xyz", "asd");
    s.Replace("a", "ddd");
    s.Replace("123", "f");
    s.Replace("dbc", "666");
    s.Replace("666", "6");
    cout << s.c_str() << endl;
    system("pause");
    return 0;
}

测试用例结果


查看评论

C++面试题(二)——自己实现一个String类

实现一个自己的String类是一道考验C++基础知识的好题。 至少要能实现以下:构造函数,析构函数,拷贝构造函数(copy constructor),重载赋值操作符(copy assignment o...
  • worldwindjp
  • worldwindjp
  • 2013-10-23 12:13:57
  • 9294

类 String理解和经典面试题,

类 String public final class String ; String 类代表字符串。 Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现...
  • uotail
  • uotail
  • 2017-05-05 21:54:55
  • 1405

C++面试中经常会让手写String类的实现

主要是完成String类的构造函数、拷贝构造函数、赋值构造函数和析构函数。这个类中包括了指针类成员变量m_data,当类中包括指针类成员变量时,一定要重载构造函数、赋值函数、析构函数; 下面是具体的...
  • lplp90908
  • lplp90908
  • 2017-09-07 09:21:36
  • 434

Java 几道常见String面试题

本篇谈谈几个常见的java关于 String的面试题。 (1)String s1="abc"; String s2="abc"; System.out.println(s1==s2); System...
  • Sqirt
  • Sqirt
  • 2017-05-26 11:36:42
  • 2554

Java-String类常见面试题

Java-String类常见面试题
  • zsx157326
  • zsx157326
  • 2016-12-30 15:39:27
  • 484

[经典面试题][百度]c++实现STL中的string类

题目请用c++ 实现stl中的string类,实现构造,拷贝构造,析构,赋值,比较,字符串相加,获取长度及子串等功能。代码/*-------------------------------------...
  • SunnyYoona
  • SunnyYoona
  • 2015-03-31 22:41:43
  • 2429

String常见面试题——(一)

1、一个中文汉字能保存在一个char里吗? byte呢?请看下面的例子: public class ChineseTest { public static void main(String...
  • u011118321
  • u011118321
  • 2017-03-29 22:30:02
  • 431

C++笔试题之String类的实现

这个在面试或笔试的时候常问到或考到。 已知类String的原型为: class String { public: String(const char *str = NULL);// 普通...
  • caoshangpa
  • caoshangpa
  • 2016-05-29 09:12:17
  • 6549

String字符串处理常见的面试题总结

首先,我们要先了解常量池的概念,常量池在java中用于保存在编译期已确定的,存在于已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = “...
  • nwpu_geeker
  • nwpu_geeker
  • 2017-12-03 14:06:53
  • 1012

Java String常见面试题汇总

String类型的面试题 1.       String是最基本的数据类型吗? 基本数据类型包括byte,int,char,long,float,double,boolean,sh...
  • zhangliangzi
  • zhangliangzi
  • 2016-03-26 11:41:28
  • 1422
    个人资料
    持之以恒
    等级:
    访问量: 1814
    积分: 444
    排名: 11万+
    最新评论