【C++初阶 ---- string类】文档介绍 | 容量操作 | 模拟实现

string介绍

  • 前言
  • 1. C语言中的字符串
  • 2. 标准库中的string类
    • 2.1string类对象的容量操作
    • 2.2string类对象的访问及遍历操作
      • 访问操作 [ ]和at
  • string底层模拟实现

前言

其实 string 就是一个管理字符数组的顺序表,因为字符数组的使用广泛,C++ 就专门给了一个 string 类,由于编码原因,它写的是一个模板。针对 string,一般情况它有三个成员 —— char* _str、size_t _size、size_t _capacity。

在这里插入图片描述

1. C语言中的字符串

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

2. 标准库中的string类

string类的文档介绍

  1. 字符串是表示字符序列的类
  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型
  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数
  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

总结:
7. string是表示字符串的字符串类
8. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作
9. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string;
10. 不能操作多字节或者变长字符的序列。在使用string类时,必须包含#include头文件以及using namespace std;

2.1string类对象的容量操作

#include<string>
#include<iostream>
using namespace std;
void test_string1()
{
	//1、size | length
	string s1("hello world");
	cout << s1.size() << endl;
	cout << s1.length() << endl;
	cout << "----------cut1----------" << endl;
	//2、max_size
	string s2;
	cout << s1.max_size() << endl;
	cout << s2.max_size() << endl;	
	cout << "----------cut2----------" << endl;
	//3、capacity
	cout << s1.capacity() << endl;
	cout << "----------cut3----------" << endl;
	//4、resize
	string s3("hello world");
	cout << s3.size() << endl;
	cout << s3 << endl;
	//s3.resize(20);//n大于当前的字符串的长度且没有指定c,所以hello world\0\0\0\0...   
	//s3.resize(5);//n小于当前的字符串的长度, 它会删除掉从n开始的这些字符
	s3.resize(20, 'x');//n大于当前的字符串的长度且指定c,所以hello worldxxxx...
	cout << s3.size() << endl;
	cout << s3 << endl;
	cout << "----------cut4----------" << endl;
	//5、reserve
	string s4("hello world");
	s4.reserve(20);
	cout << s4 << endl;
	cout << s4.size() << endl;
	cout << s4.capacity() << endl;
	s4.reserve(10);
	cout << s4 << endl;
	cout << s4.size() << endl;
	cout << s4.capacity() << endl;
	cout << "----------cut5----------" << endl;
	//6、clear | empty
	string s5("hello world");
	cout << s5 << endl;
	cout << s5.empty() << endl;;
	s5.clear();
	cout << s5 << endl;
	cout << s5.empty() << endl;
	cout << "----------cut6----------" << endl;
	//7、shrink_to_fit 暂且不演示
}   
void test_string2()
{
	string s;
	size_t sz = s.capacity();
	cout << "making s grow:\n" << sz << endl;
	for(int i = 0; i < 500; ++i)
	{
		s.push_back('c');
		if(sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed:" << sz << '\n';
		}
	}
	cout << "----------cut7----------" << endl;
}
int main()
{
	test_string1();
	test_string2();

	return 0;
}


在这里插入图片描述
📝说明

size || length
在这里插入图片描述
两者的功能相同,一般我们比较常用的是 size。

对于 string 是在 STL 这个规范前被设计出来的,因此在 Containers 下并没有 string:
在这里插入图片描述
早期说要算字符串字符的长度,所以早期提供的接口就叫 length,至于后面要加 size 的原因是后面增加了 map、set 这样的树,所以用 length 去表示它的数据个数就不合适了。

max_size

它也是早期设计比较早的,属于一个没用的接口 —— 从操作系统中获取最大的长度。本意是想告诉你这个字符串最大你能定义多长, 这个接口在设计的时候其实不好实现,它没有办法标准的去定义这个接口,因为它有很多不确定的因素。所以它这个地方是直接给你 232 ,也就是 4G。所以没什么价值,以后再遇到就直接跳过了。
在这里插入图片描述

capacity

对于 string 对象而言,如果 capacity 是 15,意味着它有 16 个字节的空间,因为有一个位置是 \0 的。对于 capacity 它会随着字符串的大小而增容,这里默认是 15。
在这里插入图片描述
resize

resize 的前者版本可以让字符串的长度变成 n;后者可以让字符串的 n 个长度变成 c。

如果 n 是小于当前的字符串的长度, 它就会缩减到 n 个字符,删除掉从 n 开始的这些字符。

如果 n 是大于当前的字符串的长度,通过在末尾插入尽可能多的内容来扩展当前内容,倘若指定了 c,则新元素被初始化为 c 的副本,否则它们就是值初始化字符 (空字符 \0)。

对于 s3.resize(20); s3[19] 是有效位置,因为对于 operator[] 里它会 assert(pos < _size)。
在这里插入图片描述
reserve ❗

请求 capacity。

注意这里不是你要多少 capacity 它就给多少 capacity,它在增容时还要对照不同编译器下自己的增容规则,最终容量不一定等于字符串长度,它可能是相等的,也可能是更大的。

如果 n 大于当前字符串的 capacity,那么它会去扩容。

如果 n 小于当前字符串的 capacity,这里跟不同的平台有关系。文档里是这样说的:其他情况下 (小于或等于),有可能它会缩容(开一块新空间,将数据拷贝,释放原有空间),也有可能不对当前空间进行影响,只是变换 capacity 的值。已证,VS 和 Linux 下不会缩容,STL 的标准也是这样规定的,这是实现 STL 的人决定的。

对于 s4.reserve(20); s4[19] 是无效位置,因为对于 operator[] 里它会 assert(pos < _size)。
在这里插入图片描述
可以看到 Windows VS 下初始容量是 15 ,除了第一次,其余的大概是以 1.5 倍增容。
在这里插入图片描述

g++ ???
在这里插入图片描述
可以看到在不同的编译器下增容规则也不同,Linux g++ 下初始容量是 0,其余是以 2 倍增容的。

clear | empty ❗

清理字符串 | 判空字符串
在这里插入图片描述
resize 和 reserve 有什么价值 ❓

对于 resize,既要开空间,还要对这些空间初始化,就可以用 resize —— s.resize(20, ‘x’);

对于 reserve,明确知道需要多大空间的情况,可以提前把空间开好,以减少增容所带来的代价 —— s.reserve(500);

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

访问操作 [ ]和at

在这里插入图片描述

  • 更常用的是[ ]
int main()
{
	string s1("hello world");
 
	cout << s1[4] << endl;
	cout << s1.at(4) << endl;
	return 0;
}

string底层模拟实现

#pragma once
#include<iostream>
using namespace std;
#include<string.h>
#include<assert.h>
namespace bit {
	class string {
	public:
		
		typedef char* iterator;
		typedef const char* const_iterator;
		const iterator begin() const
		{
			return _str;
		}
		const iterator end() const 
		{
			return _str + _size;
		}
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str+_size;
		}

		//无参构造
		/*string() 
			:_str(nullptr)
			,_size(0)
			,_capacity(0)
		{}*/
		//常量字符串带参构造
		/*string(const char* str)
			:_str(new char[strlen(str)+1])
			,size(strlen(str))
			,capacity(strlen(str))
		{
		}*/
		                     //注意缺省值为'\0'不行
		string(const char* str="")
			: _size(strlen(str))
		{
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
		const char* c_str() const
		{
			return _str;
		}
		//遍历
		size_t size() const 
		{
			return _size;
		}

		char& operator[](size_t pos) 
		{
			assert(pos);
			return _str[pos];
		}

		const char& operator[](size_t pos) const
		{
			assert(pos);
			return _str[pos];
		}

		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n+1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
			}
			_capacity = n;
		}

		void push_back(char ch)
		{
			//扩容
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}
		void append(const char* str)
		{
			/*size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			strcpy(_str + _size, str);
			_size += len;*/
			insert(_size, str);
		}
		void insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			size_t end = _size+1;
			while (end > pos)
			{
				_str[end] = _str[end-1];
				end--;
			}
			_str[pos] = ch;
			++_size;
		}
		void resize(size_t n, char ch = '\0')
		{
			if (n <= _size)
			{
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				reserve(n);
				for (size_t i = _size; i < n; i++)
				{
					_str[i] = ch;
				}
				_str[n] = '\0';
				_size = n;
			}
		}
		//可以解决浅拷贝带来的问题
		//拷贝构造
		//s1(s2)
	/*	string(const string& s)
		{
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}*/
		string(const string& s)
		{
			string tmp(s._str);
			swap(tmp);
		}
		//s1=s2
		string& operator=(const string& s)
		{
			char* tmp = new char[s._capacity + 1];
			strcpy(tmp, s._str);
			delete[] _str;
			_str = tmp;
			_size = s._size;
			_capacity = s._capacity;
			return *this;
		}

		//检查6.10--在pos位置插入字符串str
		void insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			//扩容
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			size_t end = _size + len;
			while (end > pos+len-1)
			{
				_str[end] = _str[end - 1];
				end--;
			}
			strncpy(_str + pos, str,len);
			_size += len;
		}

		void erase(size_t pos, size_t len = npos)
		{
			//全部删除的情况
			if (len == npos || pos  > _size-len)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
		}

		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		//找到返回下标,找不到就返回npos		
		size_t find(char ch,size_t pos=0) const
		{
			assert(pos <= _size);
			for (size_t i = pos; i < _size; i++)
			{
				if (_str[i] == ch)
					return i;
			}
			return npos;
		}
		//找子串
		size_t find(const char* sub, size_t pos = 0) const
		{
			//strstr未匹配会返回一个空指针
			const char* p=strstr(_str, sub);
			if (p)
			{
				return p - _str;
			}
			else
			{
				return npos;
			}
		}
		//取子串
		string& substr(size_t pos=0, size_t len = npos)
		{
			string sub;
			if (len == npos||len>_size-pos)
			{
				for (size_t i = pos; i < _size; i++)
				{
					sub += _str[i];
				}
			}
			else
			{
				for (size_t i = pos; i < pos+len; i++)
				{
					sub += _str[i];
				}
			}
			return sub;
		}
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

		void clear()
		{
			_size = 0;
			_str[_size] = '\0';
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	public:
		static const int npos;
	};

	const int string::npos = -1;

	//具体函数,和库里的swap模板同名时,优先调用此函数
	void swap(string& x, string& y)
	{
		x.swap(y);
	}
	bool operator==(const string& s1,const string& s2)
	{
		int ret = strcmp(s1.c_str(), s2.c_str());
		return ret == 0;
	}
	bool operator<(const string& s1, const string& s2)
	{
		int ret = strcmp(s1.c_str(), s2.c_str());
		return ret < 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 !(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();
		char ch;
		ch = in.get();
		char buff[128];
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[127] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}

	istream& getline(istream& in, string& s)
	{
		s.clear();
		char ch;
		ch = in.get();
		char buff[128];
		size_t i = 0;
		while ( ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[127] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}

	void test_string1() 
	{
		string s1("hello world");
		//cout << s1 << endl;
		for (int i = 0; i < s1.size(); i++)
		{
			 s1[i]++;
		}
		for (int i = 0; i < s1.size(); i++)
		{
			cout << s1[i] <<" ";
		}
	}


	void test_string2()
	{
		string s1("hello wrold");
		string::iterator it1 = s1.begin();
		while (it1 != s1.end())
		{
			//*it1 -= 3;
			cout << *it1 << " ";
			++it1;
		}
		cout << endl;
		for (auto ch : s1)
		{
			cout << ch << " ";
		}
		cout << endl;
		string s2("x x x x");
		for (auto ch : s2)
		{
			cout << ch << " ";
		}
		cout << endl;
	}
	void test_string3()
	{
		string s3("hello world");
		s3.push_back('1');
		s3.push_back('2');
		cout << s3.c_str() << endl;
		s3 += '4';
		cout << s3.c_str() << endl;
		s3 += "333";
		cout << s3.c_str() << endl;
		s3.insert(3, "xxxxxx");
		cout << s3.c_str() << endl;
		s3.erase(6, 3);
		cout << s3.c_str() << endl;
		s3.resize(5);
		cout << s3.c_str() << endl;
		s3.resize(20, 'x');
		cout << s3.c_str() << endl;
	}
	void test_string4()
	{
		string s4("hello world");
		s4.insert(6, "xxxxxx");
		string s5("shijiaqing");
		cout << s4.c_str() << endl;
		cout << s5.c_str() << endl;
		//库里的swap:代价三次拷贝+一次析构,不推荐
		swap(s4, s5);
		//代价更小
		//s4.swap(s5);
		cout << s4.c_str() << endl;
		cout << s5.c_str() << endl;
	}
	void test_string5()
	{
		string s1("hello");
		string s2("hello");
		cout << (s1 == s2) << endl;
		cout << ("hello" == s2) << endl;
		cout << (s1 == "hello") << endl;
		//cin >> s1 >> s2;
		cout << s1 << endl;
		cout << s2 << endl;
		string s3;
		getline(cin, s3); 
		cout << s3 << endl;
	}
	void test_string6()
	{
		string s1("hello wrold");
		string s2(s1);
		cout << s1 << endl;
		cout << s2 << endl;
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mac系统docker默认不支持host主机网络模式

环境描述&#xff1a;在mac系统上安装docker及docker-compose服务&#xff0c;并且打算搭建一个redis集群 问题描述&#xff1a;mac默认不支持host网络模式&#xff0c;导致集群无法通过外部主机访问 具体验证步骤&#xff1a; docker-compose.yml如下&#xff1a; version…

山东省著名烈士孙善师孙善帅故居布展喜添新篇

人海信息网山东讯&#xff08;张春兄、冯爱云&#xff09; “……他们以钢铁般的意志&#xff0c;坚守共产党员的使命&#xff0c;他们就是泺口九烈士的孙善师孙善帅兄弟&#xff01;”6月28日&#xff0c;对于山东省著名烈士孙善师孙善帅故居来说&#xff0c;又是一个不平凡的…

二、安装虚拟机

本篇来源&#xff1a;山海同行 本篇地址&#xff1a;https://shanhaigo.cn/courseDetail/1805875642621952000 本篇资源&#xff1a;以整理到-山海同行 一、官网下载centos7 1. 进入CentOS 官方网站 官方网站&#xff1a;https://www.centos.org/download/ 2. 选择iso 点击下…

基于Delphi编写PC上位机串口通信工具

1&#xff09;Delphi入门级小知识&#xff0c;分享给将要学习或者正在学习Delphi上位机开发的同学。 2&#xff09;内容属于原创&#xff0c;若转载&#xff0c;请说明出处。 3&#xff09;提供相关问题有偿答疑和支持。 Delphi&#xff0c;是Windows平台下著名的快速应用程…

python(基础语法,pandas,numpy,正则表达式,数据预处理)

python学习推荐网址&#xff1a; 白月黑羽 一、语法基础 目标&#xff1a; • list、tuple、set、dict的基本用法 • 内置函数 len&#xff08;&#xff09;&#xff0c; eval&#xff08;&#xff09;&#xff0c;range&#xff08;&#xff09;&#xff0c;sort&#xff08;…

weiyang**4.合约

通过合约开发&#xff0c;合约编译&#xff0c;SDK配置与业务开发构建了一个基于FISCO BCOS联盟区块链的应用。 官网&#xff1a;开发第一个区块链应用 — FISCO BCOS 2.0 v2.11.0 文档 (fisco-bcos-documentation.readthedocs.io) CSDN&#xff1a;FISCO BCOS开发第一个区块链…

教师资格证(教资)笔试如何备考?含备考资料

教师资格证&#xff08;教资&#xff09;笔试如何备考&#xff1f;含备考资料 前言 教师&#xff0c;一直以来的热门职业&#xff0c;而要成为一名教师&#xff0c;考取教师资格证则是基本条件&#xff0c;那么教资笔试如何备考呢&#xff1f;&#xff0c;这里准备笔试备考攻…

基于单片机光纤测距系统的设计与实现

摘要 &#xff1a; 光纤由于其频带宽 、 损耗低及抗干扰能力强等优点已被广泛地应用在通信 、 电子及电力方面 &#xff0c; 是我们生产生活中必不可少的媒介。 在实际的光纤实验 、 安装 、 运营和维护工作中 &#xff0c; 一种精准 、 轻便和易操作的光纤测距系统显得尤为重…

PingCastle 3.2.0.1 - Active Directory 安全检测和评估

PingCastle 3.2.0.1 - Active Directory 安全检测和评估 活动目录域安全分析工具 请访问原文链接&#xff1a;https://sysin.org/blog/pingcastle/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 在 20% 的时间内获得 80% 的…

LitelDE安装---附带每一步截图以及测试

LiteIDE LiteIDE 是一款专为Go语言开发而设计的开源、跨平台、轻量级集成开发环境&#xff08;IDE&#xff09;&#xff0c;基于 Qt 开发&#xff08;一个跨平台的 C 框架&#xff09;&#xff0c;支持 Windows、Linux 和 Mac OS X 平台。LiteIDE 的第一个版本发布于 2011 年 …

[小试牛刀-习题练]《计算机组成原理》之数据信息的表示、运算方法与运算器

【数据信息的表示运算方法与运算器】 1、【机器码转换】X-0.11111111&#xff0c;X的补码是 1.00000001 。 最高位符号位为负值&#xff1a; 反码法——绝对值按位取反末位加一&#xff0c;1.000000000.000000011.00000001扫描法——从右往左找到第一个为1的&#xff…

SpringBoot的自动配置核心原理及拓展点

Spring Boot 的核心原理几个关键点 约定优于配置&#xff1a; Spring Boot 遵循约定优于配置的理念&#xff0c;通过预定义的约定&#xff0c;大大简化了 Spring 应用程序的配置和部署。例如&#xff0c;它自动配置了许多常见的开发任务&#xff08;如数据库连接、Web 服务器配…

PHP校园论坛-计算机毕业设计源码08586

摘 要 本项目旨在基于PHP技术设计与实现一个校园论坛系统&#xff0c;以提供一个功能丰富、用户友好的交流平台。该论坛系统将包括用户注册与登录、帖子发布与回复、个人信息管理等基本功能&#xff0c;并结合社交化特点&#xff0c;增强用户之间的互动性。通过利用PHP语言及其…

核方法总结(四)——高斯过程回归学习笔记

一、定义 基于核方法的线性回归模型和传统线性回归一样&#xff0c;可以用未知数据进行预测&#xff0c;但不能确定 预测的可信度。在参考书第二章中可知&#xff0c;基于贝叶斯方法可以实现对未知数据依概率预测&#xff0c;进而可得到预测的可信度。这一方法中&#xff0c;通…

试用笔记之-收钱吧安卓版演示源代码,收钱吧手机版感受

首先下载&#xff1a; https://download.csdn.net/download/tjsoft/89499105 安卓手机安装 如果有收钱吧帐号输入收钱吧帐号和密码。 如果没有收钱吧帐号点我的注册 登录收钱吧帐号后就可以把手机当成收钱吧POS机用了&#xff0c;还可以扫客服的付款码哦 源代码技术交流QQ:42…

数据架构深度解析

写在前面 在信息化高度发达的今天&#xff0c;数据已成为企业最宝贵的资产之一。如何有效地管理和利用这些数据&#xff0c;以支持企业的决策和业务运营&#xff0c;成为企业面临的重要挑战。数据架构作为数据管理的基础&#xff0c;其设计合理与否直接关系到数据的质量和价值。…

Vue3实现点击按钮实现文字变色

1.动态样式实现 1.1核心代码解释&#xff1a; class"power-station-perspective-item-text"&#xff1a; 为这个 span 元素添加了一个 CSS 类&#xff0c;以便对其样式进行定义。 click"clickItem(item.id)"&#xff1a; 这是一个 Vue 事件绑定。当用户点…

算法金 | 协方差、方差、标准差、协方差矩阵

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 抱个拳&#xff0c;送个礼 1. 方差 方差是统计学中用来度量一组数据分散程度的重要指标。它反映了数据点与其均值之间的偏离程度。在…

【LINUX】内核源码文件系统调用相关摸索

首先&#xff0c;先看看想测试那个系统调用&#xff0c;在应用层&#xff0c;如果使用C语言编程一般我们一来就是open函数&#xff0c;实际在测试的时候&#xff0c;直接用touch xxx.txt然后 echo "xxx" >> xxx.txt&#xff0c;这样就完成了文件创建和写文件的…

idea 用久了代码提示变慢卡顿优化

idea 用久了代码提示变慢卡顿优化 修改虚拟机配置 修改编译构建堆内存