news 2026/7/21 6:31:50

从零学STL:string类常用接口一篇吃透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零学STL:string类常用接口一篇吃透

目录

1、STL的介绍

(1)容器(存数据)就是各种装东西的盒子

(2)迭代器(遍历)

(3)算法(功能函数)

2、string类

(1)auto和范围for

(2)string类的相关接口(最常见的接口)

1.string常见的构造函数

2.string类对象的容器操作函数

3.string类对象的访问及遍历操作

4.string类对象的修改操作

5.string 类非成员函数


1、STL的介绍

STL=C++标准模板库。就是官方提前写好的一大堆现成容器+算法,你直接拿来用,不用自己手写

STL分为三个部分

(1)容器(存数据)就是各种装东西的盒子

string 字符串、vector 动态数组(最常用)、list 链表、stack 栈、queue 队列、map键值对。

(2)迭代器(遍历)

就是容器的通用指针,统一遍历所有的容器

(3)算法(功能函数)

排序、查找、去重、交换等,其中sort排序,find查找都属于STL

一句话:以前需要我们自己造轮子去实现数组的增删查改,现在我们学习了STL之后直接用现成的,一行代码就搞定。

C语言:自己造轮子,C++:现成的轮子全套配齐。

2、string类

为啥要学习string类呢?

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

(1)auto和范围for

一、前言
在现代C++11及以后语法中, auto 类型推导与范围for循环是日常开发、STL遍历、代码精简最常用两大语法。
不管是遍历 string 、 vector 还是其他容器,熟练使用这两个语法能极大简化代码,也是校招笔试、日常写业务必备知识点。


二、auto 关键字详解
1. 什么是auto?
auto 是自动类型推导关键字,编译器根据右边赋值内容,自动推导出变量真实类型,无需手动写冗长类型。

2.基础用法

#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<iostream> #include<string> using namespace std; int main() { //auto的使用,自动推到类型 auto a1= 10;//自动识别a1是int类型 auto a2 = 10.0;//自动识别a2是double类型 return 0; }

(2)搭配STL中的迭代器

STL迭代器中的类型极长,直接用auto简化

//传统的迭代器 string::iterator it=s.begin(); //auto推导 auto it=s.begin();

auto使用注意:定义必须初始化,不给值无法推到类型。不能作为函数形参。

三、范围for循环

1、作用:自动遍历整个容器,无需下标,无需迭代器,极简遍历string,vector等容器所有STL。

2、标准语法格式

for(auto 类型 :容器) { //逻辑代码; }

比如我们想要遍历一个字符串

我们可以看到这里我们没有写任何下标,就用了一个auto和范围for循环遍历就能很好的将这个字符串一个个的打印出来。

四、范围for的底层就是迭代器遍历的语法糖,编译器底层自动转换成

auto it=s.begin(); while(it !=s.end()) { cout<<(*it)<<" "; it++; }

(2)string类的相关接口(最常见的接口)

1.string常见的构造函数

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

string s1();//无参构造

string(const char *s) 用c_str来构造string类

string s2("xx");//带参数构造

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

string s3(s2);//拷贝构造

扩充:

1.对于拷贝构造函数来说,还有一些接口是从第几个字符开始拷贝

格式:

string(const string & str,size_t pos,size_t len=npos);

我们直接上例子

这两种写法一样,当我们不写后面的拷贝字符串的长度时,它会自动拷贝后面所有的字符。

2.拷贝字符串的前几个字符

string(const char* str,size_t n);

3.把字符串的前几个字符初始化

string(size_t n,char c);

2.string类对象的容器操作函数

(1)size 和 length 返回字符串的有效长度,不包括\0

string s1="hello world"; cout<<s1.size()<<endl; //打印出的结果是11 cout<<s1.length<<endl; //打印出的结果也是11

(2)capacity 返回空间的总大小

string s1 = "hello world"; cout << s1.capacity() << endl; //输出的结果是15

为啥是15呢?capacity()里面不包括\0,它只能表示最多能存放多少个有效字符,实际上应该是16,多出来的一个位置存放\0.

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

string s1(""); cout << s1.empty() << endl; //字符串为空,true,输出1 string s2("hello world"); cout << s2.empty() << endl; //字符串不为空,false,输出0

(4)clear 清空有效字符

string s1("hello world"); cout << s1.size() << endl;//11 cout << s1.capacity() << endl;//15 cout << s1.empty() << endl;//0 s1.clear(); cout << endl; cout << s1.size() << endl;//0 cout << s1.capacity() << endl;//15 cout << s1.empty() << endl;//1

我们可以清晰的看到clear清除的是字符串的有效长度,它的字符串的容量并没有改变。

(5)reserve 为字符串预留空间

string s1("hello world"); s1.reserve(50); cout << s1.capacity() << endl; //输出的结果是63

为啥是63呢?这是标准库为了性能做的内存对齐/按块分配优化:我们所写的reserve(50)会触发分配,标准库会直接分配一大块、对齐更友好的内存块,比如64字节(其中一个字节用来存放\0)所以会显示63。

(6)resize 将有效字符的个数改成n个,多出来的空间用字符c填充

string s1 = "hello world"; cout << s1.size() << endl;//输出11 s1.resize(15); cout << endl; cout << s1 << endl;//hello world,当我们没有填充字符时,编译器默认补充\0,ASCII为0 cout << s1.size() << endl;//输出15

我们也可以添加几个字符,比如我们想把原来的11个有效字符改成15个,那么多出来的4个字符就要用字符填充,下面的我们用字符x进行填充。

string s1 = "hello world"; cout << s1.size() << endl;//11 s1.resize(15,'x'); cout << endl; cout << s1 << endl;//hello worldxxxx cout << s1.size() << endl;//15

3.string类对象的访问及遍历操作

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

这个简单来说就是和数组的访问是一样的,我们也同样做一个例子

string s1 = "hello world"; cout << s1[0] << endl;//输出h cout << s1[1] << endl;//输出e cout << s1[2] << endl;//输出l

不应该是operator[]吗?operator[]是个运算符的名字,而s1[]是它的实际调用,s1[0]是s1.operator[](0)的语法糖,所以它们是完全等价的。

(2)begin+end begin获取的是字符串的第一个字符,end获取的是最后一个字符的下一个位置的迭代器,也就是\0的位置。

s我们直接举一个遍历字符串的例子来直观看一下这个用法

string s1 = "hello world"; string ::iterator it = s1.begin(); while (it != s1.end()) { cout << *it << " "; it++; } //输出h e l l o w o r l d

我们在写这个迭代器的通用的指针类型的时候,我们会好奇为啥要写这个::类作用域的,这是因为这个迭代器指针适用于所有的容器类型,所以我们使用时需要标明这个指针是哪个类型的,比如我们有的时候是vector中的迭代器,有时候是list当中的迭代器,所以我们使用的需要表明这个迭代器的出处。

(3)rbegin和rend 这个和begin和rend恰恰相反,rbegin指向的最后一个字符,rend指的是第一个字符的前一个位置

这个我们也可以用遍历来实现,这个就是把这个字符串倒过来遍历一遍,这个和正向遍历有所不同的是这个是反向遍历,这里是反向迭代器需要使用reverse_iterator来实现遍历

string s1 = "hello world"; string::reverse_iterator it = s1.rbegin(); while (it != s1.rend()) { cout << *it << " "; it++; } //输出结果:d l r o w o l l e h

4.string类对象的修改操作

(1)push_back 在字符串后面尾插字符c

string s1("hello world"); s1.push_back('x'); cout << s1 << endl; //打印出hello worldx

(2)append 在字符串后面追加一个字符串

写法一:在s1后面追加字符串s2

string s1 = "hello"; string s2 = "world"; cout << s1.append(s2) << endl; //输出:helloworld

写法二:从s2下标是5后面的字符追加到s1的后面

string s1 = "hello world"; string s2 = "abcdefg"; cout << s1.append(s2, 5) << endl; //输出结果:hello worldfg

写法三:在字符串后面追加一个字符串

string s1("hello world"); cout << s1.append("jiayou") << endl; //输出:hello worldjiayou

写法四:创建一个对象,取一字符串的前三个追加到这个创建的对象当中

string s2; cout << s2.append("jiayou",3) << endl; //输出:jia

写法五:在字符串后面添加五个字符

string s1("hello world"); cout << s1.append(5, 'x'); /输出:hello worldxxxxx

(3)operator+= 在字符串后面追加字符串str,必须有一个是string类类型

例子1:

string s1 = "hello"; string s2 = "world"; s1 += s2; cout << s1 << endl; //输出:helloworld

例子2:

string s1 = "hello"; s1 += "nihao"; cout << s1 << endl; //输出:hellonihao

例子3;

string s1("hello"); s1 += 'x'; cout << s1 << endl; //输出:hellox

(4)c_str 返回C语言风格的字符串

为啥需要引用c_str呢?我们可以直接上一个例子来对比一下,就知道了。因为在C语言当中,输出的结果只认const char*,而string是类类型,需要转换为C语言的风格,所以需要转换一下。

string s1("hello world"); //错误写法 printf("%s", s1); cout << endl; //正确写法 printf("%s", s1.c_str()); //输出: ?訅? hello world

(5)find+npos 从字符串pos的位置开始往后找字符c,返回该字符在字符串当中的下标位置

例子1:在已知的字符串当中找另一个字符串,有两种写法

string s1 = "hello world"; string s2 = "world"; cout << s1.find(s2) << endl;//输出6
string s1 = "hello world"; cout << s1.find("llo") << endl;//输出2 cout << s1.find("lo") << endl;//输出3

例子2:从s1的下标为3开始找wo出现的位置

string s1="helloworld"; cout << s1.find("world",3,2) << endl;//输出5

例子3:找一个字符

string s1 = "helloworld"; cout << s1.find('l') << endl; //输出2

npos:本质是当在C++当中没找到所在位置的下标,就会返回-1

static const size_t npos=-1;

(6)rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串所在的位置。

例子1:已知两个字符串,在一个字符串找另一个字符串出现的位置。

写法1:

string s1("hello world"); string s2("llo"); int key = s1.rfind(s2); cout << key << endl; //输出2

写法2:

string s1("hello world"); int key = s1.rfind("llo"); cout << key << endl; //输出2

例子二:在已知字符串当中找某个字符

string s1("hello world"); int key = s1.rfind("w"); cout << key << endl; //输出6

例子三:在已知的字符串第pos个位置开始找某个字符串的n个子字符串,下面这个就是我们要找的字符串是llo,从s1的下标为3的位置开始找,也就是倒着的下标为3,也就是o,找目标字符串的前两个字符串ll。

string s1("hello world"); int key = s1.rfind("llo",3,2); cout << key << endl; //输出2

(7)substr 从str的pos位置开始,截取n个字符,让后将其返回

string s1("hello world"); string s2 = s1.substr(5); cout << s2 << endl; //输出:空格world //从空格开始往后打印,这里没有写打印几个字符,编译器默认打印到最后 string s3 = s1.substr(5, 3); cout << s3 << endl; //输出:空格wo

5.string 类非成员函数

(1) operator >> 输入运算符重载

string name; cout << "Please, enter your name: "; cin >> name; cout << "Hello, " << name << "!\n";

我们可以在这里输入我们的名字,比如我输入张三它就会输出 hello 张三 !

(2) operator<< 输出运算符重载

string str = "Hello world!"; cout << str << '\n'; //输出:hello world!

(3) getline 获取一行字符串

string str; getline(cin, str); cout << str << endl; //当我们输入hello world //它就是输出hello world

为啥我们不直接用上面的operator>>运算符重载呢?

我们可以将上面的getline这段代码替换成cin>>str;看看会发生什么

string str; cin >> str; cout << str << endl; //当我们输入hello world //它会输出hello

为啥后面的world为啥没有打印出来呢?下面我把两种的结束条件都说明一下

getline(cin,str)和cin>>的区别

1.getline(cin,str) :

结束条件:遇到换行符\n就停止读取。

空格处理:会读取并保留所有的空格,只有换行符会被丢弃。

缓冲区残留:会把结束用的换行符从缓冲区读走并丢弃。

适用场景:读取整行文本,带空格的句子。

2.cin>>:

结束条件:当读取字符串时,只要遇到空格,换行符,制表符这些空白字符,就会立刻停止读取。

空格处理:不会读取空格,会把空格当成结束标记。

缓冲区残留:结束标记(空格/缓冲区)会留在缓冲区

适用场景:读取单个单词,无空格的输入

(4) relational operator 大小比较

比较字符串之间的大小,需要注意的是,比较的两个对象之间,必须有一个是类类型。因为这里的操作符是类类型的运算符重载。

我们可以简单的举几个类型

1.string 和string之间的比较

string s1 = "hello world"; string s2 = "hello xorld"; cout << (s1 < s2) << endl; //这里应该是返回的是真,返回1,这里前6个字符都相等,第7个比较的是ASCII值,x在w的后面,比较大

2.string 和char之间的比较

string s1 = "hello world"; cout << (s1 < "hello abcd") << endl; //这里同样是前6个字符都相等,s1的第7个字符比下面要比较的字符串要大,所以应该是s1>s2,所以是假,返回0

3.char和string之间的比较

string s1 = "hello world"; cout << ("hello abcd"<s1) << endl; //这里同样是前6个字符都相等,s1的第7个字符比下面要比较的字符串要大,所以应该是s1>s2,所以是真,返回1

上面就是我们在日常常用的接口以及算法题的常用接口,我们只掌握如何适用就可以了,当然了,当我们在面试过程当中,面试官总是让我们手撕这些接口的底层逻辑,我们也是需要掌握的,那么我们在下次博客当中也会手写一下string的模拟实现。

3、string类的模拟实现

(1)string.h头文件

#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<iostream> #include<string> #include<assert.h> using namespace std; namespace myself { class string { public: //这里是迭代器版本,相当于把char*指针换了个名字 typedef char* iterator; iterator begin() { return _str; } iterator end() { return _str + _size; } /*string() :_str(new char[1]{'\0'}) ,_size(0) ,_capacity(0) {}*/ // 短小频繁调用的函数,可以直接定义到类里面,默认是inline string(const char* str = "") { _size = strlen(str); // _capacity不包含\0 _capacity = _size; _str = new char[_capacity + 1]; strcpy(_str, str); } // 深拷贝问题 // // s2(s1) string(const string& s) { _str = new char[s._capacity + 1]; strcpy(_str, s._str); _size = s._size; _capacity = s._capacity; } // s2 = s1 // s1 = s1 string& operator=(const string& s) { if (this != &s) { delete[] _str; _str = new char[s._capacity + 1]; strcpy(_str, s._str); _size = s._size; _capacity = s._capacity; } return *this; } ~string() { delete[] _str; _str = nullptr; _size = _capacity = 0; } const char* c_str() const { return _str; } void clear() { _str[0] = '\0'; _size = 0; } size_t size() const { return _size; } size_t capacity() const { return _capacity; } char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; } const char& operator[](size_t pos) const { assert(pos < _size); return _str[pos]; } //保留空间大小 void reserve(size_t n); //尾插字符 void push_back(char ch); //追加字符串 void append(const char* str); string& operator+=(char ch); string& operator+=(const char* str); //在字符串后面+一个字符 void insert(size_t pos, char ch); //在字符串后面+一个字符串 void insert(size_t pos, const char* str); //从pos位置开始删除字符 void erase(size_t pos, 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; size_t _size; size_t _capacity; static const size_t npos; }; bool operator<(const string& s1, const string& s2); bool operator<=(const string& s1, const string& s2); bool operator>(const string& s1, const string& s2); bool operator>=(const string& s1, const string& s2); bool operator==(const string& s1, const string& s2); bool operator!=(const string& s1, const string& s2); ostream& operator<<(ostream& out, const string& s); istream& operator>>(istream& in, string& s); }

(2)string.cpp文件

#include"string.h" namespace myself { const size_t string::npos = -1; void string::reserve(size_t n) { if (n > _capacity) { //cout << "reserve:" << n << endl; char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } void string::push_back(char ch) { if (_size == _capacity) { reserve(_capacity == 0 ? 4 : _capacity * 2); } _str[_size] = ch; ++_size; _str[_size] = '\0'; } string& string::operator+=(char ch) { push_back(ch); return *this; } void string::append(const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { // 大于2倍,需要多少开多少,小于2倍按2倍扩 reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity); } strcpy(_str + _size, str); _size += len; } string& string::operator+=(const char* str) { append(str); return *this; } void string::insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { reserve(_capacity == 0 ? 4 : _capacity * 2); } // 挪动数据 size_t end = _size + 1; while (end > pos) { _str[end] = _str[end - 1]; --end; } _str[pos] = ch; ++_size; } void string::insert(size_t pos, const char* s) { assert(pos <= _size); size_t len = strlen(s); if (_size + len > _capacity) { // 大于2倍,需要多少开多少,小于2倍按2倍扩 reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity); } size_t end = _size + len; while (end > pos + len - 1) { _str[end] = _str[end - len]; --end; } for (size_t i = 0; i < len; i++) { _str[pos + i] = s[i]; } _size += len; } 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) { assert(pos < _size); 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) { assert(pos < _size); const 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); // len大于剩余字符长度,更新一下len if (len > _size - pos) { len = _size - pos; } string sub; sub.reserve(len); for (size_t i = 0; i < len; i++) { sub += _str[pos + i]; } return sub; } bool operator<(const string& s1, const string& s2) { return strcmp(s1.c_str(), s2.c_str()) < 0; } bool operator<=(const string& s1, const string& s2) { return s1 < s2 || s1 == s2; } bool operator>(const string& s1, const string& s2) { return !(s1 <= s2); } bool operator>=(const string& s1, const string& s2) { return !(s1 < s2); } bool operator==(const string& s1, const string& s2) { return strcmp(s1.c_str(), s2.c_str()) == 0; } bool operator!=(const string& s1, const string& s2) { return !(s1 == s2); } ostream& operator<<(ostream& out, const string& s) { for (auto ch : s) { out << ch; } return out; } istream& operator>>(istream& in, string& s) { s.clear(); const int N = 256; char buff[N]; int i = 0; char ch; //in >> ch; ch = in.get(); while (ch != ' ' && ch != '\n') { buff[i++] = ch; if (i == N - 1) { buff[i] = '\0'; s += buff; i = 0; } //in >> ch; ch = in.get(); } if (i > 0) { buff[i] = '\0'; s += buff; } return in; } }

(3)test.cpp文件

namespace myself { void test_string1() { string s1; string s2("hello world"); cout << s1.c_str() << endl; cout << s2.c_str() << endl; for (size_t i = 0; i < s2.size(); i++) { s2[i] += 2; } cout << s2.c_str() << endl; for (auto e : s2) { cout << e << " "; } cout << endl; string::iterator it = s2.begin(); while (it != s2.end()) { //*it += 2; cout << *it << " "; ++it; } cout << endl; } void test_string2() { string s1("hello world"); s1 += 'x'; s1 += '#'; cout << s1.c_str() << endl; s1 += "hello bit"; cout << s1.c_str() << endl; s1.insert(5, '$'); cout << s1.c_str() << endl; s1.insert(0, '$'); cout << s1.c_str() << endl; string s2("hello world"); cout << s2.c_str() << endl; s2.insert(5, "$$$"); cout << s2.c_str() << endl; s2.insert(0, "$$$&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); cout << s2.c_str() << endl; } void test_string3() { string s1("hello world"); s1.erase(6, 100); cout << s1.c_str() << endl; string s2("hello world"); s2.erase(6); cout << s2.c_str() << endl; string s3("hello world"); s3.erase(6, 3); cout << s3.c_str() << endl; } void test_string4() { string s("test.cpp.zip"); size_t pos = s.find('.'); string suffix = s.substr(pos); cout << suffix.c_str() << endl; string copy(s); cout << copy.c_str() << endl; s = suffix; cout << suffix.c_str() << endl; cout << s.c_str() << endl; s = s; cout << s.c_str() << endl; } void test_string5() { string s1("hello world"); string s2("hello world"); cout << (s1 < s2) << endl; cout << (s1 == s2) << endl; cout << ("hello world" < s2) << endl; cout << (s1 == "hello world") << endl; //cout << ("hello world" == "hello world") << endl; cout << s1 << s2 << endl; string s0; cin >> s0; cout << s0 << endl; } } int main() { myself::test_string5(); char str[] = "牛马"; cout << strlen(str) << endl; str[1]++; cout << str << endl; str[3]--; cout << str << endl; str[1]++; cout << str << endl; str[3]--; cout << str << endl; return 0; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/21 6:29:42

RoPE旋转位置编码:原理、实现与大模型长度外推实践

1. 项目概述&#xff1a;为什么RoPE是当前大模型位置编码的“顶流”&#xff1f; 如果你最近在关注大语言模型的技术进展&#xff0c;无论是Llama、GPT还是国内的各种开源模型&#xff0c;有一个技术名词出现的频率越来越高—— 旋转位置编码 。它不像Transformer架构那样广为…

作者头像 李华
网站建设 2026/7/21 6:29:06

C2000 eCAP模块实战:从信号捕获到多路同步PWM生成

1. 项目概述与eCAP模块核心价值 在嵌入式系统&#xff0c;尤其是电机控制、数字电源和精密测量领域&#xff0c;我们常常面临两个看似矛盾的核心需求&#xff1a;一是需要以极高的精度和实时性去“感知”外部世界的变化&#xff0c;比如测量一个PWM信号的频率、占空比&#xff…

作者头像 李华
网站建设 2026/7/21 6:28:40

南京站 meetup 下周六开启!赶快报名吧!

深耕 PG 生态&#xff0c;聚焦内核与实践&#xff0c;一场属于数据库技术人的深度技术交流即将落地南京。 在国产化与开源数据库加速落地的当下&#xff0c;PostgreSQL 凭借稳定、开放、可扩展的生态优势&#xff0c;已成为企业级数据库的重要选择。而基于 PostgreSQL 深度演进…

作者头像 李华
网站建设 2026/7/21 6:28:10

委员访谈筹备与传播策略全解析

1. 年度会议前的委员访谈&#xff1a;核心价值与操作实务 每年重大会议召开前&#xff0c;委员访谈都是公众了解政策动向的重要窗口。作为连续十年跟踪报道的媒体从业者&#xff0c;我深刻体会到这类访谈不仅是简单的信息采集&#xff0c;更是连接政策制定与民生关切的桥梁。从…

作者头像 李华
网站建设 2026/7/21 6:25:36

PotPlayer百度翻译插件完整教程:三步实现视频字幕实时翻译

PotPlayer百度翻译插件完整教程&#xff1a;三步实现视频字幕实时翻译 【免费下载链接】PotPlayer_Subtitle_Translate_Baidu PotPlayer 字幕在线翻译插件 - 百度平台 项目地址: https://gitcode.com/gh_mirrors/po/PotPlayer_Subtitle_Translate_Baidu 还在为外语视频的…

作者头像 李华
网站建设 2026/7/21 6:22:22

Mac CPU使用率优化指南:诊断与解决方案

1. 理解Mac CPU使用率的基本概念 Mac电脑的CPU使用率反映了处理器当前的工作负载情况。与Windows任务管理器类似&#xff0c;macOS提供了"活动监视器"工具来监控和管理系统资源。CPU使用率通常以百分比形式显示&#xff0c;100%表示所有CPU核心都在满负荷运行。 在活…

作者头像 李华