[C++初阶]string类

news2024/10/6 1:45:15

1. 为什么要学习string

1.1 C语言中的字符串

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP(面向对象)的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。

2. 标准库中的string

2.1 string类的了解

string类的文档介绍
1. 字符串是表示字符序列的类
2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。
总结:
1. string是表示字符串的字符串类
2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作
3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
4. 不能操作多字节或者变长字符的序列。
使用string类时,必须包含#include头文件以及using namespace std;

2.2 string类的常用接口说明

我们看string类的文档可以发现

有以下几种接口:

内容选自:string::string - C++ Reference (cplusplus.com)

2.2.1 string()  ---- 无参构造函数

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s;
	cout << s <<endl;

	return 0;
}

运行结果:


2.2.2 string (const string& str)-----复制构造函数

代码:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("Iamchineseprson");
	string s1(s);
	cout << s << endl;
	cout << s1 << endl;

	return 0;
}

运行结果:

2.2.3 string(const string& str, size_t pos, size_t len = npos);----复制从字符位置 pos 开始并跨越 len 字符的 str 部分(如果任一 str 太短或 len 为 string::npos,则复制 str 的末尾)

代码示例:

运行结果:

2.2.4 string(const char*)---- 用char*构造函数

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("Iamchineseperson");
	cout << s << endl;

	return 0;
}

2.3 string对象的容量操作

2.3.1size函数

代码示例:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("Iamchineseprson");

	cout << s.size() << endl;

	return 0;
}

运行结果:

2.3.2 length函数

返回字符串有效字符长度 size() 与 length() 方法底层实现原理完全相同, 引入 size() 的原因是为了与其他容器的接口保持一致, 一般情况下基本都是用 size()。

代码示例:

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string s("Iamchineseprson");

	cout << s.length() << endl;

	return 0;
}

2.3.3 capacity函数

代码示例:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("Iamchineseprson");

	cout << s.capacity() << endl;

	return 0;
}

运行结果:

2.3.4 empty函数

检测字符串释放为空串,是返回true,否则返回false

代码示例:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s1("Iamchineseprson");
	string s2;
	cout << s1.empty() << endl;
	cout << s2.empty() << endl;

	return 0;
}

运行结果:

2.3.5 clear函数

clear()清空有效字符

clear()只是将string中有效字符清空,不改变底层空间大小。

代码示例:

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string s("Iamchineseprson");

	cout << s.length() << endl;

	s.clear();

	cout << s.length() << endl;

	return 0;
}

运行结果:

2.3.6 reserve函数

作用:为字符串预留空间
写法:reserve(size_t res_arg=0):
特点:为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量小。

代码示例:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("Iamchineseprson");
	cout << s.capacity() << endl;
	s.reserve(30);
	cout << s.capacity() << endl;
	return 0;
}

运行结果:

2.3.7 resize函数

resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用 '\0' 来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。
注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("Iamchineseprson");
	cout << s << endl;
	s.resize(30,'L');
	cout << s << endl;
	return 0;
}

运行结果:

2.4 string对象的访问及遍历接口

//迭代器
string::iterator being();//返回第一个位置的迭代器
string::iterator end();//返回结束位置下一个位置的迭代器
reverse_iterator rbeign();//返回结束位置的迭代器
reverse_iterator rend();//返回开始的前一个位置的迭代器

//at访问位置的值
char& at (size_t pos);	//返回pos位置的值
const char& at (size_t pos) const;	//返回const修饰的pos位置的位置的值

//重载 [] 
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const; 

2.4.1 operator[]

作用:返回pos位置的字符,const string对象调用

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("Iamchineseprson");
	for (int i = 0; i < s.size(); i++)
	{
		printf("[%d] : %c\n", i, s[i]);
	}
	cout << endl;
	return 0;
}

运行结果:

2.4.2 迭代器 begin 、end

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("Iamchineseprson");
	string::iterator it = s.begin();
	while (it < s.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	return 0;
}

运行结果:

2.4.3 迭代器 rbegin 、rend

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("iamchineseprson");

	string::reverse_iterator it = s.rbegin();
	while (it != s.rend())
	{
		cout << *it << ' ';
		it++;
	}

	cout << endl;

	return 0;
}

运行结果:

2.4.4 at

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("iamchineseprson");
	for (int i = 0; i < s.size(); i++)
	{
		cout << s.at(i) << " ";
	}
	cout << endl;
	cout << endl;

	return 0;
}

运行结果:

2.4.5 范围for

这里是遍历,自然我们也能用前面学习的范围for

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("iamchineseperson");

	for (const char ch : s)
	{
		cout << ch << ' ';
	}

	cout << endl;

	return 0;
}

运行结果:

但这里ch的类型是char,我们可能吃不准,所以,很多时候我们都会选择用auto类型

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("iamchineseperson");

	for (auto ch : s)
	{
		cout << ch << ' ';
	}

	cout << endl;

	return 0;
}

2.5 string的增删查改

1.增

1.连接

(1)函数原型:

//重载 +=
string& operator+= (const string& str);	//在结尾处连接字符串str
string& operator+= (const char* s);		//在结尾处连接字符串s
string& operator+= (char c);			//在结尾处连接字符c

//append 在字符串结尾连接	
string& append (const string& str);	//在结尾处连接字符串str
string& append (const char* s);	//在结尾处连接字符串s
//连接从迭代器first 到 last 这个区间到结尾 左闭右开
template <class InputIterator>	
string& append (InputIterator first, InputIterator last);


#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("iamchineseperson");

	s += '1';
	cout << s << endl;

	s += "666666";
	cout << s << endl;

	string ss("2333");

	s += ss;
	cout << s << endl;
	return 0;
}

 运行结果:

2.尾插

push_back 函数

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("iamchineseprson");

	s.push_back('1');
	cout << s << endl;

	s.push_back('2');
	cout << s << endl;

	s.push_back('3');
	cout << s << endl;

	return 0;
}

运行结果:

3.append函数
#include <iostream>
#include <string>

using namespace std;
int main()
{
	string s("iamchineseperson");

	// 追加n个字符
	s.append(1, '1');
	cout << s << endl;

	// 追加一个字符串
	s.append("12345");
	cout << s << endl;

	// 追加一个字符串的前n个
	s.append("12345678", 3);

	cout << s << endl;
	return 0;
}

运行结果:

4.insert 函数

string& insert (size_t pos, const string& str);
//insert函数能够在字符串任意位置插入一个string容器内的字符串

string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);
//insert函数能够在字符串任意位置插入一个string对象内的字符串的一段字符串

string& insert (size_t pos, const char* s);
//insert函数能够在字符串一段字符串

string& insert (size_t pos, const char* s, size_t n);
//insert 函数还能够在字符串任意位置插入字符串的前 n 个

string& insert (size_t pos, size_t n, char c);
//insert 函数还能够在字符串任意位置插入n个字符
//插入
int main()
{
	string s1("iamchineseperson");
	string s2("hello");

	//在pos位置插入string
	s1.insert(0, s2);
	cout << s1 << endl;

	//在pos位置插入char*
	s1.insert(0, "hehe");
	cout << s1 << endl;

	// 在最后插入string的一部分
	s1.insert(s1.size(), s2, 0, 2);
	cout << s1 << endl;


	// 在第一个位置插入string
	s1.insert(0, "sadasdxzczasd");
	cout << s1 << endl;

	return 0;
}

至于其他情况这里我就不多展示了。

2.删

//清空
clear()

//尾删
pop_back();

//erase 删除
//删除从pos位置开始删除len个
string& erase (size_t pos = 0, size_t len = npos);
//删除迭代器p位置	
iterator erase (iterator p);
//删除迭代器区间左闭右开
iterator erase (iterator first, iterator last);

1. erase 函数
string& erase (size_t pos = 0, size_t len = npos);

erase 函数能够删除第 n 个位置后面长度为 len 的字符串

如果没有传 len 或是 第 n 个位置后面的字符数小于 len ,则n后面的字符全部删除

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("iamaperson");

	s.erase(3, 2);
	cout << s << endl;

	s.erase(1);
	cout << s << endl;

	return 0;
}

运行结果:

2.尾删

pop_back()

#include <iostream>
#include <string>

int main ()
{
  std::string str ("hello world!");
  str.pop_back();
  std::cout << str << '\n';
  return 0;
}

运行结果:

3.clear()
// string::clear
#include <iostream>
#include <string>

int main ()
{
  char c;
  std::string str;
  std::cout << "Please type some lines of text. Enter a dot (.) to finish:\n";
  do {
    c = std::cin.get();
    str += c;
    if (c=='\n')
    {
       std::cout << str;
       str.clear();
    }
  } while (c!='.');
  return 0;
}

该程序重复用户引入的每一行,直到一行包含一个点 ('.')。每个换行符 ('\n') 都会触发行的重复和当前字符串内容的清除。

这里我就不运行了

3.查

//find从pos位置向后查找  找到返回下标位置,找不到返回npos
//查找字符串str
size_t find (const string& str, size_t pos = 0) const;
//查找字符串s
size_t find (const char* s, size_t pos = 0) const;
//查找字符c
size_t find (char c, size_t pos = 0) const;

//rfind 从pos位置向前找 找到返回下标位置,找不到返回npos
size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;	
size_t rfind (char c, size_t pos = npos) const;
1.find()
#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("i am  a studentt");
	string str("student");

	// 查找 str --> 找得到
	int pos = s.find(str, 0);
	cout << "str pos : " << pos << endl;

	// 查找字符串 --> 找得到
	pos = s.find("a", 0);
	cout << "a pos : " << pos << endl;

	// 查找字符串 --> 找不到
	pos = s.find("A", 0);
	cout << "A pos : " << pos << endl;

	// 查找字符 --> 找得到
	pos = s.find('s', 0);
	cout << "s pos : " << pos << endl;

	// 查找字符 --> 找不到
	pos = s.find('I', 0);
	cout << "I pos : " << pos << endl;

	return 0;
}

运行结果:

2.rfind()
//rfind 从pos位置向前找 找到返回下标位置,找不到返回npos
size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;	
size_t rfind (char c, size_t pos = npos) const;
#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("i am  a studentt");
	string str("student");

	// 查找 str --> 找得到
	int pos = s.rfind(str);
	cout << "str pos : " << pos << endl;

	// 查找字符串 --> 找得到
	pos = s.rfind("a");
	cout << "a pos : " << pos << endl;

	// 查找字符串 --> 找不到
	pos = s.rfind("a", 0);
	cout << "A pos : " << pos << endl;

	// 查找字符 --> 找得到
	pos = s.rfind('s',8);
	cout << "s pos : " << pos << endl;

	// 查找字符 --> 找不到
	pos = s.rfind('s', 5);
	cout << "I pos : " << pos << endl;

	return 0;
}

4.改

//assign 全部替换
//用字符串str替换原来的内容
string& assign (const string& str);
//用字符串s替换原来的内容
string& assign (const char* s);	
//迭代器first到迭代器last这个区间替换原来的内容 左闭右开
template <class InputIterator>
   string& assign (InputIterator first, InputIterator last);

//replace替换一部分
//将pos到len位置替换成str
string& replace (size_t pos,  size_t len,  const string& str);
//将迭代器i1到i2替换成str
string& replace (iterator i1, iterator i2, const string& str);
 //将pos到len位置替换成s
string& replace (size_t pos,  size_t len,  const char* s);
//将迭代器i1到i2替换成s 左闭右开
string& replace (iterator i1, iterator i2, const char* s);

1.assign()
int main()
{
	string s1("i am  a studentt");
	string s2("student");

	//修改stirng
	s1.assign(s2);
	cout << s1 << endl;
	//修改char *
	s1.assign("he");
	cout << s1 << endl;

	//迭代器
	s1.assign(s2.begin(), s2.end());
	cout << s1 << endl;

	return 0;
}

运行结果:

2.replace()

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s1("i am  a student");
	string s2("person");
	//将pos到len位置替换string
	s1.replace(8, 15, s2);
	cout << s1 << endl;

	//将pos到len位置替换char*
	s1.replace(0, 0, "asdsd");
	cout << s1 << endl;
	return 0;
}

运行结果:

2.6 一些小东西的介绍

1. npos

npos的值通常是一个很大的正数,等于-1(当作为无符号数解释时或等于string::size_type的最大可能值。

2.c_str 函数

作用:返回C格式字符串

C++中,printf 是一个C语言函数,它不支持直接打印std::string类型的内容。这是因为 printf 是一个可变参数函数,而 std::string 不是基本数据类型,因此需要转换为C风格字符串才能由 printf 输出。

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s("Hello world");

	printf("%s\n", s);
	printf("%s\n", s.c_str());

	return 0;
}

运行结果:

3.substr()

string substr (size_t pos = 0, size_t len = npos) const;

在字符串中从第pos个位置开始截取len个字符返回

// string::substr
#include <iostream>
#include <string>

int main ()
{
  std::string str="We think in generalities, but we live in details.";
                                           // (quoting Alfred N. Whitehead)

  std::string str2 = str.substr (3,5);     // "think"

  std::size_t pos = str.find("live");      // position of "live" in str

  std::string str3 = str.substr (pos);     // get from "live" to the end

  std::cout << str2 << ' ' << str3 << '\n';

  return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1643531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA中的lambda表达式(无废话)

Lambda表达式是Java SE 8中一个重要的新特性。 它是一种语法形式&#xff0c;可以代码书写更加精炼。 用人话说就是把原来的代码变得很短。 这部分的内容是非常简单的。 一、函数式接口 想要理解lambda表达式&#xff0c;首先要了解函数式接口。 关于接口的知识请查阅&am…

浏览器中不能使用ES6的扩展语法...报错

浏览器大多数已经支持ES6&#xff08;ECMAScript 2015&#xff09;的扩展语法&#xff08;...&#xff09;&#xff0c;包括Chrome、Firefox、Safari和Edge等。然而&#xff0c;如果你在某些浏览器中遇到无法使用扩展语法的问题&#xff0c;可能是由以下原因导致的&#xff1a;…

ngrinder项目-本地调试遇到的坑

前提-maven mirrors配置 <mirrors><!--阿里公有仓库--><mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</ur…

每周打靶VulnHub靶机-DOUBLETROUBLE_ 1

doubletrouble: 1靶机传送门 get flags 靶机名为 双重麻烦&#xff0c;可能会繁琐一点 1.信息搜集 使用nmap进行域内存活主机扫描继续扫描其开放端口开放了22(ssh)、80(http)端口使用浏览器访问其80端口是一个登录页面&#xff0c;继续扫描其 敏感目录dirsearch -u [http://19…

通过helm在k8s上安装minio

1 helm安装minio 1.1 下载minio 添加仓库 helm repo add bitnami https://charts.bitnami.com/bitnami 将minio拉取下来 helm pull bitnami/minio --version 版本号 解压到本地开始编辑配置文件 tar -zxf minio-xxx.tgz [rootk8s-master01 minio]# vi values.yaml 1.2…

拼多多多多搜索推广技巧

拼多多多多搜索推广技巧主要包括以下几个方面&#xff1a; 拼多多推广可以使用3an推客。3an推客&#xff08;CPS模式&#xff09;给商家提供的营销工具&#xff0c;由商家自主设置佣金比例&#xff0c;激励推广者去帮助商家推广商品链接&#xff0c;按最终有效交易金额支付佣金…

Docker新建容器 修改运行容器端口

目录 一、修改容器的映射端口 二、解决方案 三、方案 一、修改容器的映射端口 项目需求修改容器的映射端口 二、解决方案 停止需要修改的容器 修改hostconfig.json文件 重启docker 服务 启动修改容器 三、方案 目前正在运行的容器 宿主机的3000 端口 映射 容器…

重要!!!方法的进阶使用------回调函数

参考资料&#xff1a; 参考视频 下面所有举的例子都在参考demo中 概述&#xff1a; 回调函数很简单&#xff0c;就是对普通方法参数的类型的拓展&#xff0c;其实是对普通方法的深层应用&#xff1b;回调函数其实就是将含有执行方法类的实例&#xff0c;以参数的形式传入到方…

集成学习算法:AdaBoost详解以及代码实现

本文尽量从一个机器学习小白或是只对机器学习算法有一个大体浅显的视角入手&#xff0c;尽量通俗易懂的介绍清楚AdaBoost算法&#xff01; 一、AdaBoost简介 AdaBoost&#xff0c;是英文"Adaptive Boosting"&#xff08;自适应增强&#xff09;的缩写&#xff0c;由…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

运行时数据区-基础

运行时数据区-基础 为什么学习运行时数据区Java内存区域&#xff08;运行时数据区域&#xff09;和内存模型&#xff08;JMM&#xff09; 区别组成部分&#xff08;jdk1.7 / jdk1.8&#xff09;从线程隔离性分类与类加载的关系每个区域的功能参考文章 为什么学习运行时数据区 …

【云原生】Docker 的网络通信

Docker 的网络通信 1.Docker 容器网络通信的基本原理1.1 查看 Docker 容器网络1.2 宿主机与 Docker 容器建立网络通信的过程 2.使用命令查看 Docker 的网络配置信息3.Docker 的 4 种网络通信模式3.1 bridge 模式3.2 host 模式3.3 container 模式3.4 none 模式 4.容器间的通信4.…

【翻译】REST API

自动伸缩 API 创建或更新自动伸缩策略 API 此特性设计用于 Elasticsearch Service、Elastic Cloud Enterprise 和 Kubernetes 上的 Elastic Cloud 的间接使用。不支持直接用户使用。 创建或更新一个自动伸缩策略。 请求 PUT /_autoscaling/policy/<name> {"rol…

c语言:打印任意行数的菱形

例如&#xff1a;以下图片形式 #include <stdio.h> int main() {int line 0;scanf_s("%d", &line);int i 0;//打印上半部分for (i 0; i < line; i){//打印空格数int j 0;for (j 0; j < line - 1 - i; j){printf(" ");}//打印*数量for…

vue3(实现上下无限来往滚动)

一、问题描述 一般在大屏项目中&#xff0c;很常见的效果&#xff0c;就是容器中的内容缓慢地向下移动&#xff0c;直到底部停止&#xff0c;然后快速滚动回顶部&#xff0c;然后接着缓慢滚动到底部。并且在特定的情况下&#xff0c;还需要进行一些小交互&#xff0c;那就还得让…

【Linux 进程】 自定义shell

目录 关于shell 1.打印提示符&&获取用户命令字符​编辑 2.分割字符串 3.检查是否为内建命令 cd命令 export命令 echo命令 1.输出最后一个执行的命令的状态退出码&#xff08;返回码&#xff09; 2.输出指定环境变量 4.执行外部命令 关于shell Shell 是计算机操…

【精】hadoop、HIVE大数据从0到1部署及应用实战

目录 基本概念 Hadoop生态 HIVE hdfs(hadoop成员) yarn(hadoop成员) MapReduce(hadoop成员) spark flink storm HBase kafka ES 实战 安装并配置hadoop 环境准备 准备虚拟机 安装ssh并设置免密登录 安装jdk 安装、配置并启动hadoop 添加hadoop环境变量&…

翻译《The Old New Thing》 - Why does the CreateProcess function do autocorrection?

Why does the CreateProcess function do autocorrection? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20050623-03/?p35213 Raymond Chen 在 2005 年 6 月 23 日 为什么 CreateProcess 函数会进行自动更正&#xff1f; 译注&#xff…

智能工业相机哪家好?

一、什么是智能工业相机 在工业自动化的浪潮中&#xff0c;智能工业相机扮演着至关重要的角色。它们如同工业领域的“眼睛”&#xff0c;为生产过程提供精准的视觉监测和数据采集。然而&#xff0c;面对众多的智能工业相机品牌&#xff0c;如何选择一款真正适合的产品成为了众多…

Python面试十问

一、深浅拷贝的区别&#xff1f; 浅拷⻉&#xff1a; 拷⻉的是对象的引⽤&#xff0c;如果原对象改变&#xff0c;相应的拷⻉对象也会发⽣改变。 深拷⻉&#xff1a; 拷⻉对象中的每个元素&#xff0c;拷⻉对象和原有对象不在有关系&#xff0c;两个是独⽴的对象。 浅拷⻉(c…