C++中的string类

ops/2024/10/31 14:10:09/

目录

一.C与C++的string比对

二.string类的使用

与构造相关的函数(copy control)

访问及遍历操作(access)

 容量操作(capacity)

修改操作(modify)

 非成员函数(non-member)

三.string类的模拟实现

string.h

string.cpp

test.cpp


一.C与C++的string比对

在C语言中,字符串是以' \0 '结尾的字符的集合,C标准库中提供了一系列的str库函数方便我们操作字符串,但是,这些库函数和字符串是分离的,不符合面向对象的思想。C++语言中,把字符串数据和方法封装到一个string类中,使得字符串的操作更加简洁方便。

二.string类的使用


在使用string类时,必须包含#include头文件以及using namespace std。

以下列举string类中的一些重点的函数及其功能:

与构造相关的函数(copy control)

string() : 构造空的string类对象,即空字符串


string(const char* s)  : 用C-string来构造string类对象


string(const string&s): 拷贝构造函数

访问及遍历操作(access)

char& operator[](size_t pos) :返回pos位置的字符,const string类对象调用


iterator begin() + iterator end()(正向迭代器):

begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器


reverse_iterator rbegin() + reverse_iterator rend()(反向迭代器):
begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器

范围for :C++11支持更简洁的范围for的新遍历方式(底层为迭代器)

 

 容量操作(capacity)

size_t size() const:返回字符串有效字符长度


size_t capacity() const: 返回空间总大小


bool empty() const:检测字符串释放为空串,是返回true,否则返回false


void clear(): 清空有效字符


void reserve(size_t n): 为字符串预留大小为n的空间


void resize(size_t n, char c):将有效字符的个数该成n个,多出的空间用字符c填充

 

修改操作(modify)

 void push_back(char c) :在字符串后尾插字符c


string& append(const char* str): 在字符串后追加一个字符串


string& operator+=(char c) / string& operator+=(const char* str):

在字符串后追加字符c或字符串str

//string& insert(size_t pos, const char* str):在指定位置pos插入一个字符串str

//string& erase(size_t pos = 0, size_ t len = npos):删除指定位置的len个字符

const char*  c_str() cosnt:返回C格式字符串


size_t find(char c, size_t pos = 0) const:

从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置


size_t rfind(char c, size_t pos = npos) const:
从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置


string substr(size_t pos = 0, size_t size = npos) const:

 在str中从pos位置开始,截取n个字符,然后将其返回

 

 非成员函数(non-member)

ostream& operator>>(ostream&  os, const string& s):输入运算符重载


istream& operator<<(istream& is, string& s): 输出运算符重载


istream& getline(istream& is, string& s):获取一行字符串

 

三.string类的模拟实现

通过对stirng类的模拟实现,可以加深我们对String类的理解 ,以下实现一些重点的功能。

string.h

我们把string类的声明放到自己的命名空间中,防止与全局的std::string产生冲突。

#pragma once
#include <iostream>
using namespace std;namespace chocolate
{class string{public:typedef char* iterator;typedef const char* const_iterator;public://构造/拷贝构造/赋值/析构(copy control)void swap(string& s);string(const char* str = "");string(const string& s);string& operator=(const string& s);~string();//访问及遍历操作(access)char& operator[](size_t index);const char& operator[](size_t index) const;iterator begin();iterator end();const_iterator begin() const;const_iterator end() const;//容量操作(capacity)size_t size() const;size_t capacity() const;void clear();bool empty() const;void reserve(size_t n);void resize(size_t n, char ch = '\0');//修改操作(modify)void push_back(char ch);string& operator+=(char ch);string& append(const char* str);string& operator+=(const char* str);string& insert(size_t pos, char ch);string& insert(size_t pos, const char* str);void erase(size_t pos = 0, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private:char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;static const size_t npos = -1;};//非成员函数ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}

 

string.cpp

 成员函数的声明与定义分离时,别忘记在函数名之前指定类域。函数中有缺省值的,只能在声明处指定缺省值,定义时不能带缺省值。

#define _CRT_SECURE_NO_WARNINGS
#include "string.h"//指定命名空间,否则编译器认为是全局函数
namespace chocolate
{//构造/拷贝构造/赋值/析构(copy control)void string::swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}string::string(const char* str){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}string::string(const string& s){//传统写法/*_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;*///现代写法string tmp(s._str);swap(tmp);}string& string::operator=(const string& s){//传统写法/*delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;*///现代写法string tmp(s._str);swap(tmp);return *this;}string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}//访问及遍历操作(access)char& string::operator[](size_t index){return _str[index];}const char& string::operator[](size_t index) const{return _str[index];}string::iterator string::begin(){return _str;}string::iterator string::end(){return _str + _size;}string::const_iterator string::begin() const{return _str;}string::const_iterator string::end() const{return _str + _size;}//容量操作(capacity)size_t string::size() const{return _size;}size_t string::capacity() const{return _capacity;}void string::clear(){_size = 0;_str[_size] = '\0';}bool string::empty() const{return  _size == 0;}void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void string::resize(size_t n, char ch){if (n > _capacity){//扩容reserve(n);//fill chfor (size_t i = _size; i < n; i++){_str[i] = ch;}}//修改size,追加'\0'_size = n;//_str[_size] = '\0';}//修改操作(modify)void string::push_back(char ch){//扩容if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}//插入数据_str[_size++] = ch;_str[_size] = '\0';}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::append(const char* str){//扩容size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//插入数据strcat(_str, str);_size += len;return *this;}string& string::operator+=(const char* str){append(str);return *this;}string& string::insert(size_t pos, char ch){assert(pos <= _size);//扩容if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}//挪动数据for (size_t i = _size + 1; i > pos; i--){_str[i] = _str[i - 1];}//插入数据_str[pos] = ch;_size++;return *this;}string& string::insert(size_t pos, const char* str){assert(pos <= _size);//扩容size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//挪动数据for (size_t i = _size + len; i > pos + len - 1; i--){_str[i] = _str[i - len];}//插入数据for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;return *this;}void string::erase(size_t pos, size_t len){assert(pos < _size);if (len > _size - pos){_str[pos] = '\0';_size = pos;}else{//挪动数据for (size_t i = pos + len; i <= _size; i++){_str[i - len] = _str[i];}_size -= len;}}size_t string::find(char ch, size_t pos){for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}size_t string::find(const char* str, size_t pos){char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}string string::substr(size_t pos, size_t len){assert(pos < _size);if (len > _size - pos){len = _size - pos;}string res;reserve(len);for (size_t i = 0; i<len; i++){res += _str[pos + i];}return res;}//非成员函数(non-member)ostream& operator<<(ostream& out, const string& s){for (auto ch : s){cout << ch;}return out;}istream& operator>>(istream& in, string& s){//清除s.clear();//缓冲区const int N = 256;char buf[N];int i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\n'){buf[i++] = ch;if (i == N - 1){buf[i] = '\0';s += buf;i = 0;}ch = in.get();}if (i > 0){buf[i] = '\0';s += buf;}return in;}
}

 

test.cpp

 

#define _CRT_SECURE_NO_WARNINGS
#include "string.h"namespace chocolate
{//copy control测试用例void test_copy_control(){cout << "copy control测试用例:" << endl;string s1;             // 构造空的string类对象s1string s2("hello world");// 用C格式字符串构造string类对象s2string s3(s2);         // 拷贝构造s3s1 = s2;cout << s1 << endl << s2 << endl << s3 << endl;cout << endl;}//access测试用例void test_access(){cout << "access测试用例:" << endl;string s("hello world");//for+[]for (size_t i = 0; i < s.size(); i++){cout << s[i] << " ";}cout << endl;//迭代器string::iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;//范围for(底层为迭代器)for (auto ch : s){cout << ch << " ";}cout << endl;cout << endl;}//capacity测试用例void test_capacity(){cout << "capacity测试用例:" << endl;string s1("hello world");s1.reserve(111);cout << "capacity:" << s1.capacity() << endl;s1.resize(256, '*');cout << s1 << endl;s1.resize(11);cout << s1 << endl;cout << endl;}//modify测试用例void test_modify(){cout << "modify测试用例:" << endl;string s("hello world");s += '#';s += '*';cout << s << endl;s += "hello everyone!!!";cout << s << endl;s.insert(0, '$');s.insert(0, "start:");cout << s << endl;size_t pos = s.find('*', 0);cout << s.substr(pos) << endl;pos = s.find("everyone", 0);cout << s.substr(pos) << endl;s.erase(6, 1);cout << s << endl;s.erase(17);cout << s << endl;s.erase();cout << endl;}//non-member测试用例void test_non_member(){cout << "non-member测试用例" << endl;string s("hello world");cout << "请输入:";cin >> s;cout << s;cout << endl;}
}int main()
{chocolate::test_copy_control(); chocolate::test_access();chocolate::test_capacity();chocolate::test_modify();chocolate::test_non_member();
}

运行截图:

 

今天的内容就到这里,希望大家多多支持鼓励,谢谢大家!


http://www.ppmy.cn/ops/129883.html

相关文章

工厂模式:简单工厂模式、工厂方法模式、抽象工厂模式

目录 工厂模式的类型 工厂模式的优点 工厂模式的缺点 适用场景 1. 简单工厂模式示例 2. 工厂方法模式示例 3. 抽象工厂模式示例 总结 工厂模式&#xff08;Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种在不指定具体类的情况下创建对象的方…

Java面试经典 150 题.P274. H 指数(011)

本题来自&#xff1a;力扣-面试经典 150 题 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台https://leetcode.cn/studyplan/top-interview-150/ 题解&#xff1a; class Solution {public int hIndex(int[] citations) {int…

如何编写一个高效的Java工具类

在Java开发中&#xff0c;工具类的编写是提高代码复用性和可维护性的重要手段。特别是在使用Spring Boot框架时&#xff0c;工具类的合理应用可以极大地提升开发效率。本文将深入探讨如何编写一个高效的Java工具类&#xff0c;并结合Spring Boot与IRIS数据库的集成&#xff0c;…

前端笔面试查漏补缺

面试笔试的知识总结&#xff0c;查漏补缺 一、CSS样式隔离 CSS样式隔离用于确保组件或元素的样式不会与其他组件或元素的样式发生冲突。 1.scoped css -- <style scoped> 构建工具&#xff08;vue-loader&#xff09;会在编译阶段对css特殊处理&#xff0c;给当前组…

openpnp - 在openpnp中单独测试相机

文章目录 openpnp - 在openpnp中单独测试相机概述笔记END openpnp - 在openpnp中单独测试相机 概述 底部相机的位置不合适, 重新做了零件&#xff0c;准备先确定一下相机和吸嘴的距离是多少才合适。 如果在设备上直接实验&#xff0c;那么拆装调整相机挺麻烦的。 准备直接在电…

ffmpeg 提取mp4文件中的音频文件并保存

要从一个 MP4 文件中提取音频并保存为单独的音频文件&#xff0c;可以使用 ffmpeg 工具。以下是一个简单的命令示例&#xff1a; 命令格式 ffmpeg -i input.mp4 -vn -acodec copy output.mp3 参数解释 -i input.mp4: 指定输入文件为 input.mp4。 -vn: 禁用视频流&#xff0…

(11)(2.1.6) Hobbywing DroneCAN ESC(一)

文章目录 前言 1 连接和配置 2 参数说明 前言 具有 CAN 接口&#xff08;including these&#xff09;的业余 ESC 支持 DroneCAN&#xff0c;它允许自动驾驶仪通过 CAN 控制 ESC /电机&#xff0c;并检索单个转速、电压、电流和温度。 具有 CAN 接口&#xff08;including …

React前端框架 – 全面了解与应用

React前端框架 – 全面了解与应用 引言 你是否曾在构建前端应用时感到迷茫&#xff1f;面对众多框架&#xff0c;有没有想过哪个最适合你的项目&#xff1f;今天&#xff0c;我们将深入探讨React&#xff0c;一个现今最流行的前端框架之一。通过了解它的起源、基本概念、强大…