【C++】string

string

  • 1. 简单了解string
  • 2. string的常用接口
  • 3. 简单模拟实现string
  • 4. 写时拷贝
  • 5. 练习


1. 简单了解string

  1. string是表示字符串的字符类,其底层是basic_string模板类的实例化,只能存储单字节的字符串,不能操作多字节和变长字符的序列。
  2. 在使用string类时,必须包含头文件< string >以及展开命名空间using namespace std。

2. string的常用接口

  1. 构造函数
    在这里插入图片描述

a. 用法
(1)默认构造,构造空字符串。(2)拷贝构造。(3)从str中取出子串放入string中。(4)用字符串来构造string的对象。(5)拷贝前n个字符到string对象。(6)将n个相同的字符填充到string对象中。(7)利用迭代器(类似于指针)将该范围内的字符拷贝到string的对象中。
注意
第3点len的缺省值是npos。npos是静态成员变量,表示整形的最大值。当你不传len时,默认从pos位置到字符串结束。

b. 例子
这里只讲四种常见的(用长方形框出来的)。
在这里插入图片描述

  1. 赋值
    在这里插入图片描述

例子
在这里插入图片描述
3. 访问
在这里插入图片描述

例子
在这里插入图片描述
在这里插入图片描述
例子
在这里插入图片描述

  1. 迭代器 在这里插入图片描述

先讲前两种
例子

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
注意
iterator是像指针一样的类型,有可能是指针,也有可能不是指针。但底层都是指针实现。string底层就是指针。
对比
在这里插入图片描述
相比operator[],迭代器好像更加复杂。但是言之过早,以下有更方便的范围for。
意义
(1)范围for不比operator[]方便?但这又和迭代器有什么关系?
在这里插入图片描述
通过查看范围for的反汇编代码,发现底层是迭代器。在这里插入图片描述
范围for底层就是迭代器,一个类支持迭代器,就支持范围for。
(2)任何容器都支持迭代器,且用法是类似的。
在这里插入图片描述
(3)算法可以配合迭代器处理容器内数据。
在这里插入图片描述
在这里插入图片描述

  1. 反向迭代器
    在这里插入图片描述

例子
在这里插入图片描述

在这里插入图片描述

  1. const修饰的迭代器
    在这里插入图片描述
    返回由const修饰的迭代器,只能读不能写。

例子在这里插入图片描述

  1. 容量
    在这里插入图片描述

(1)size()和length()返回字符串的长度(字节个数)。
(2)capacity()返回字符串所占空间的大小。
(3)clear()清理字符串的内容。
(4)empty()判断字符串是否是空串,是就返回真,不是就返回假。
在这里插入图片描述
(5)reserve:预定,保留(不同于reverse:逆置。)
在这里插入图片描述
在这里插入图片描述
(6)resize
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
缩容是有代价的,string的缩容很保守(就像free和delete不会单独释放空间的一部分),实际上的缩容是先开一片空间,按规定大小的空间拷贝过去,再释放旧空间,是以时间换空间的。
总结
想开空间同时初始化,用resize(),想先把空间开好,用reserve()。

(7)shrink_to_fit:收缩至合适
在这里插入图片描述
但是没必要缩容,以时间换空间,因为现代计算机的内存足够大。

  1. 追加
    在这里插入图片描述
    在这里插入图片描述

append与+=都有追加的作用,但是+=更实用,所以只讲+=。
例子
在这里插入图片描述

  1. 尾插和插入
    在这里插入图片描述
    在这里插入图片描述

例子
在这里插入图片描述
在这里插入图片描述

  1. 删除
    在这里插入图片描述

注意
(1)若len不传参,则用缺省值,将字符串从pos位置删除至结尾。
(2)迭代器区间一般都是左闭右开的,如[first,last)。
例子
在这里插入图片描述

  1. c_str得到字符数组的指针
    在这里插入图片描述

注意
得到的字符数组是该string对象的字符串。
例子
在这里插入图片描述

  1. find查找
    在这里插入图片描述
    注意
    找到后,返回的是找到字符串的首字符的下标。

例子
给一个网址,要求用协议、域名、资源名分割。

//https://legacy.cplusplus.com/reference/string/string/
find
int main()
{
	string s1 = "https://legacy.cplusplus.com/reference/string/string/";
	string protocol;//协议
	string domain;//域名
	string uri;//资源
	
	//找协议
	size_t pos1 = s1.find("://");
	if (pos1 != string::npos)
	{
		//找到了,取子串
		protocol = s1.substr(0, pos1);//pos1恰好是协议的长度
	}


	//找域名
	size_t pos2 = s1.find('/', pos1 + 3);//从pos+3的位置开始找
	if (pos2 != string::npos)
	{
		//找到了
		domain = s1.substr(pos1 + 3, pos2 - (pos1 + 3));
	}

	//找资源
	uri = s1.substr(pos2 + 1);//直接从pos2+1位置开始取到结束
	
	cout << protocol << endl;
	cout << domain << endl;
	cout << uri << endl;
	cout<<s1<<endl;
	return 0;
}

运行结果
在这里插入图片描述

  1. rfind与find功能相同,但是是从后往前找。
    在这里插入图片描述

注意
(1)pos不传参,用缺省值npos,表示从最后一个字符往前找。
(2)从pos位置开始找,是包括pos位置的。

例子
字符串最后一个字符的长度

#include <iostream>
using namespace std;
#include<string>
int main()
{
    //从后面开始找,有两种情况:1.找到空格;2.没找到空格
    string str;
    //读取字符串
    getline(cin,str);
    size_t pos = str.rfind(' ');
    //找到了
    if(pos!=string::npos)
    {
        cout<<str.size()-(pos+1)<<endl;
    }
    else
    {
        cout<<str.size()<<endl;
    }
    return 0 ;
}

问题
为什么不直接用cin而是用getline?cin遇到空格和读取就结束,不读取空格。比如当你输入abc abc时,只输入abc到str,所以用getline。

  1. getline
    在这里插入图片描述

  2. to_string
    在这里插入图片描述

例子
在这里插入图片描述
不管是float还是double都默认打印到小数点后六位。


3. 简单模拟实现string

#include<assert.h>
using namespace std;
namespace zn
{
	class string
	{
	private:
		size_t _size;
		size_t _capacity;
		char* _str;
		static size_t npos;
	public:
		//构造函数
		//注意:初始化列表按照成员的声明顺序初始化
		string(const char*s = "")
			:_size(strlen(s))
			,_capacity(_size)
			,_str(new char[_capacity+1])
		{
			memcpy(_str, s, _size+1);
		}
		//拷贝构造
		string(const string& s)
		{
			_str = new char[s._capacity+1];
			for (size_t i = 0; i < s._size; i++)
			{
				push_back(s[i]);
			}
			_str[_size] = '\0';
		}
		//法二
		/*string(const string& s)
		{
			_str = new char[s._capacity + 1];
			memcpy(_str, s._str, s._size + 1);
			_size = s._size;
			_capacity = s._capacity;
		}*/

		//赋值
		string& operator=(const string& s)
		{
			//法1
			if (this != &s)
			{
				char* tmp = new char[s._capacity + 1];
				memcpy(tmp, _str, _size + 1);
				delete[] _str;
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}
		//法2
		//传值传参,调用拷贝,s出来作用域会销毁
		//交换后,s指向旧空间,不用自己销毁,出了作用域会自动销毁
		//string& operator=(string s)
		//{
		//	if (this != &s)
		//	{
		//		//不能直接交换this和&s,因为swap用到赋值,会引起无穷递归
		//		std::swap(_str, s._str);
		//		std::swap(_size, s._size);
		//		std::swap(_capacity, s._capacity);
		//	}
		//	return *this;
		//}
		//法3
		//将交换this和&s封装成函数
		/*void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size,s._size);
			std::swap(_capacity,s._capacity);
		}
		string& operator=(string s)
		{
			swap(s);
			return *this;
		}*/

		//析构函数
		~string()
		{
			delete[]_str;
			_str = nullptr;
			_size = _capacity = 0;
		}
		//c_str
		const char* c_str()const
		{
			return _str;
		}
		//size
		size_t size()const
		{
			return _size;
		}
		//operator[]
		char& operator[](size_t pos)
		{
			//检查
			assert(pos < _size);
			return _str[pos];
		}
		const char& operator[](size_t pos)const
		{
			assert(pos < _size);
			return _str[pos];
		}
		//普通迭代器
		//注意:迭代器区间是左闭右开[begin(),end())
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		//const迭代器
		typedef const char* const_iterator;
		const_iterator begin()const
		{
			return _str;
		}
		const_iterator end()const
		{
			return _str + _size;
		}
		//容量
		size_t capacity()
		{
			return _capacity;
		}
		//扩容
		void reserve(size_t n)
		{
			if (n > capacity())
			{
				char* tmp = new char[n+1];
				memcpy(tmp, _str, _size + 1);
				delete [] _str;
				_str = tmp;
				_capacity = n;
			}
		}
		//扩容+初始化
		void resize(size_t n,char ch = '\0')
		{
			if (n <= _size)
			{
				_str[n] = '\0';
			}
			else if(n<=_capacity)
			{
				for (size_t i = _size; i < n; i++)
				{
					_str[i] = ch;
				}
				_str[n] = '\0';
			}
			else if (n > _capacity)
			{
				reserve(n);
				for (size_t i = _size; i < n; i++)
				{
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}

		//增删查改
		//尾插
		void push_back(char ch)
		{
			//考虑扩容
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4:_capacity*2);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}
		//追加
		void append(const char* str)
		{
			int len = strlen(str);
			if(_size+len>_capacity)
			{
				reserve(_size + len);
			}
			memcpy(_str + _size, str, len + 1);
			_size+=len;
		}
		//operator+=
		string& operator+=(const char ch)
		{
			push_back(ch);
			return *this;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		//插入(默认在pos位置前插入)
		void insert(size_t pos, size_t n, char ch)
		{
			assert(pos <= _size);
			//考虑扩容
			if (_size + n > _capacity)
			{
				reserve(_size + n);
			}
			size_t end = _size;
			//当pos为0时,end减少到0后,再--,end会变成最大值(无符号整形)
			//npos是静态成员变量,npos是最大值
			while (end >= pos && end != npos)
			{
				_str[end + n] = _str[end];
				--end;
			}
			for (size_t i = 0; i < n; i++)
			{
				_str[pos+i] = ch;
			}
			_size += n;
		}
		void insert(size_t pos ,const char* str)
		{
			assert(pos <= _size);
			int len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			size_t end = _size;
			while (end >= pos && end != npos)
			{
				_str[end + len] = _str[end];
				--end;
			}
			memcpy(_str + pos, str, len);
		}
		//删除
		//如果len为npos,直接从pos删至结尾
		void erase(size_t pos, size_t len = npos)
		{
			assert(pos<_size);
			if (pos + len >= _size)
			{
				_size = pos;
				_str[_size] = '\0';
			}
			else
			{
				for (size_t i = 0 ; i <= _size-(pos+len); i++)
				{
					_str[pos+i] = _str[pos+len+i];
				}
				
			}
		}
		//查找
		size_t find(char ch, size_t pos = 0)
		{
			assert(pos < _size);
			for (size_t i = pos; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}
		size_t find(const char* str, size_t pos = 0)
		{
			assert(pos < _size);
			//strstr在_str中寻找str,找到就返回str在_str中首字符的地址
			const char* cc = strstr(_str, str);
			if (cc)
			{
				return cc - _str;
			}
			else
			{
				return npos;
			}
		}
		//取子串
		string substr(size_t pos = 0, size_t len = npos)
		{
			assert(pos < _size);

			size_t n = len;
			if (len == npos || pos + len > _size)
			{
				n = _size - pos;
			}

			string tmp;
			tmp.reserve(n);
			for (size_t i = pos; i < pos + n; i++)
			{
				tmp += _str[i];
			}

			return tmp;
		}
		//清理
		void clear()
		{
			//不同于析构函数
			//只清理数据
			_str[0] = '\0';
			_size = 0;
		}
		//比较大小
		bool operator<(const string& str)
		{
			//法1
			size_t i1 = 0, i2 = 0;
			while (i1 < _size && i2 < str._size)
			{
				if (_str[i1] < str._str[i2])
				{
					return true;
				}
				else if (_str[i1] > str._str[i2])
				{
					return false;
				}
				else
				{
					++i1;
					++i2;
				}
			}
			if (i1 == _size && i2 != str._size)
			{
				return true;
			}
			else
			{
				return false;
			}
			//法2
			//int ret = memcmp(_str, str._str, _size < str._size ? _size : str._size);
			//return ret == 0 ? _size < str._size : ret < 0;
		}
		bool operator==(const string& str)
		{
			return _size == str._size && memcmp(_str, str._str, _size) == 0;
		}
		bool operator!=(const string& str)
		{
			return !(*this == str);
		}
		bool operator<=(const string& str)
		{
			return (*this < str) || (*this == str);
		}
		bool operator>(const string& str)
		{
			return !(*this <= str);
		}
		bool operator>=(const string& str)
		{
			return !(*this <= str);
		}
		//operator<<和operator>>
		friend ostream& operator<<(ostream& out, const string& s);
		friend istream& operator>>(istream in, string& s);
	};
	
	// ---------------------------------------------------

	//静态成员变量
	size_t string::npos = -1;
	//友元函数
	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto e : s)
		{
			out << e;
		}
		return out;
	}
	//cout<<s与cout<<s.c_str()有什么区别?
	//c_str返回const char*,识别到'\0'就停止打印。
	//例子
	// string s("hello");s+="world";s+='\0';s+="xxxxx";
	// cout<<s.c_str()<<endl;cout<<s<<endl;
	// 总结:c的字符数组,以'\0'为终止算长度,string不看'\0',以size为终止算长度
	istream& operator>>(istream& in, string& s)
	{
		//注意:>>不会读取空格,但istream的get()每次读取一个字符,可以解决问题
		s.clear();
		//清理缓冲区的空格和换行
		char ch = in.get();
		while (ch == ' ' || ch == '\n')
		{
			ch = in.get();
		}
		//将读取的字符放到数组,可以防止频繁尾插
		char buff[128];
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		//当读取结束,检查数组是否还有字符
		if (i != 0)
		{
			s += buff;
		}
		return in;
	}
}

4. 写时拷贝

浅拷贝是指多个对象共享同一份资源,但这就回引发两个问题:(1)多次析构。如何对象管理资源,最终调用析构函数,会导致多次析构;(2)一个对象修改数据,会影响另一个对象的数据。
这时就有深拷贝,深拷贝是指每个对象都有一份属于自己的资源。

在这里插入图片描述
但是如果不同对象对独立的资源只读不写,深拷贝有点浪费资源。所以有更好的方法:写时拷贝。写时拷贝是在浅拷贝的基础上引入了引用计数的概念来实现的。引用计数表示有多少个对象指向同一片空间。当要释放空间时,考虑引用计数是否为1,不为1就不释放空间,为1就释放空间。
在这里插入图片描述
以上可以用来应付拷贝但不修改的情况,防止浪费空间。但如果要修改数据怎么办?修改的时候如果引用计数不为1,则进行深拷贝,再修改数据。在这里插入图片描述


5. 练习

  1. LeetCode917:反转字符串
//思路:从左右两边同时开始进行交换
class Solution {
public:
    string reverseOnlyLetters(string s) {
        int left = 0;
        int right = s.size()-1;
        while(left<right)
        {
            if(isalpha(s[left])&&isalpha(s[right]))
            {
                swap(s[left],s[right]);
                ++left;
                --right;
            }
            else if(isalpha(s[left]))
            {
                --right;
            }
            else if(isalpha(s[right]))
            {
                ++left;
            }
            else
            {
                ++left;
                --right;
            }
        }
        return s;
    }
};
  1. LeetCode415:字符串相加
//思路:从每个数的最后一位开始相加,取其个位尾插到要返回的string对象中,
//     取其十位数作为进位,最后逆置string对象返回。
class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1 = num1.size() - 1;
        int end2 = num2.size() - 1;
        string ret;
        //用来记录进位
        int carry = 0;
        //从最低位开始+
        while(end1>=0 || end2>=0)
        {
            int val1 = end1>=0?num1[end1] - '0':0;
            int val2 = end2>=0?num2[end2] - '0':0;
            int Add = val1 + val2 + carry;
            carry = Add / 10;
            ret += Add % 10 + '0';
            --end1;
            --end2;
        }
        if(carry!=0)
        {
            ret += carry+'0';
        }
        reverse(ret.begin(),ret.end());
        return ret;
    }
};
  1. LeetCode125:验证回文串
class Solution {
public:
    bool isPalindrome(string s) {
        //思路:遍历一遍,将大写字符转换成小写的,
        //将非字母数字字符移除,再判断是否是回文
        for(int i = 0 ; i < s.size();i++ )
        {
            if(isupper(s[i]))
            {
                //如果是大写字母就转换成小写
                s[i] = tolower(s[i]);
            }
            else if(!isalnum(s[i]))
            {
                //如果不是字母或者数字,就移除
                s.erase(i,1);
                i--;
            }
        }
        //判断是否是回文
        int begin = 0;
        int end = s.size()-1;
        while(begin<end)
        {
            if(s[begin]!=s[end])
            {
                return false;
            }
            ++begin;
            --end;
        }
        return true;
    }
};

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

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

相关文章

LLM微调 | Adapter: Parameter-Efficient Transfer Learning for NLP

目的&#xff1a;大模型预训练微调范式&#xff0c;微调成本高。adapter只只微调新增的小部分参数【但adapter增加了模型层数&#xff0c;引入了额外的推理延迟。】 Adapters最初来源于CV领域的《Learning multiple visual domains with residual adapters》一文&#xff0c;其…

Android 13(T) - Media框架(1)- 总览

从事Android Media开发工作三年有余&#xff0c;刚从萌新变成菜鸟&#xff0c;一路上跌跌撞撞学习&#xff0c;看了很多零零碎碎的知识&#xff0c;为了加深对Android Media框架的理解&#xff0c;决定在这里记录下学习过程中想到的一些问题以及一些思考&#xff0c;也希望对初…

更好搭建负载测试环境的六个技巧

如果你如我昨天谈到的客户一样&#xff0c;花费了24到48个小时用于每个负载测试环境的搭建&#xff0c;那你的测试及构建部署能力绝对是受限的。 搭建一个仿真测试环境对于做好负载测试非常重要&#xff0c;同时它也是一个非常具有挑战性的任务&#xff0c;需要考虑技术解决、…

【CSS】手写 Tooltip 提示组件

文章目录 效果示例代码实现 效果示例 代码实现 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>一颗不甘坠落的流星</title><style>body {padding: 120px;}.tooltip {position: relative;display: inline-blo…

【Linux取经路】进度条小程序

文章目录 一、预备知识1.1 回车换行1.2 缓冲区 二、倒计时2.1 注意事项 三、进度条3.1 源代码3.2 代码分析3.2 实际使用场景 一、预备知识 1.1 回车换行 一般意义上的回车换行是两个独立的独立的动作&#xff0c;而C语言中的\n则同时完成了回车和换行的工作。回车是将光标移动…

【EI/SCOPUS会议征稿】2023年第四届新能源与电气科技国际学术研讨会 (ISNEET 2023)

作为全球科技创新大趋势的引领者&#xff0c;中国一直在为科技创新创造越来越开放的环境&#xff0c;提高学术合作的深度和广度&#xff0c;构建惠及全民的创新共同体。这些努力为全球化和创建共享未来的共同体做出了新的贡献。 为交流近年来国内外在新能源和电气技术领域的最新…

谈谈网络端口的概念、分类,以及常见的端口号

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、网络端口的概念 二、网络端口的分类 1、公认端口 2、注册端口 3、动态和私有端口 三、网络端口的作用 四、常见的端口号 1、…

C/C++多线程操作

文章目录 多线程C创建线程join 和detachthis_thread线程操作锁lock_guardunique_lock 条件变量 condition_variablewaitwaitfor C语言线程创建线程同步 参考 多线程 传统的C&#xff08;C11标准之前&#xff09;中并没有引入线程这个概念&#xff0c;在C11出来之前&#xff0c…

分布式ID性能评测:CosId VS 美团 Leaf

环境 MacBook Pro (M1)JDK 17JMH 1.36运行在本机 Docker 内的 mariadb:10.6.4 运行 CosId SegmentChainId 模式&#xff0c;基准测试代码&#xff1a; Benchmarkpublic long generate() {return segmentChainId.generate();}Leaf 基准测试代码&#xff1a; Benchmarkpublic l…

nsq整体架构及各个部件作用详解

文章目录 前言 nsq的整体架构图 部件&#xff1a;nsqd 部件&#xff1a;nsqlookupd 部件&#xff1a;nsq连接库 部件&#xff1a;nsqadmin 前言 上两篇博客 centos环境搭建nsq单点_YZF_Kevin的博客-CSDN博客 linux环境搭建nsq集群_YZF_Kevin的博客-CSDN博客 我们讲了nsq是…

《MySQL 实战 45 讲》课程学习笔记(一)

基础架构&#xff1a;一条 SQL 查询语句是如何执行的&#xff1f; MySQL 的基本架构 MySQL 可以分为 Server 层和存储引擎层两部分。 Server 层 包括连接器、查询缓存、分析器、优化器、执行器&#xff1b;涵盖 MySQL 的大多数核心服务功能&#xff0c;以及所有的内置函数&…

华为数通HCIP-VPN技术-mpls vpn

VPN&#xff08;虚拟专线网络&#xff09; 作用&#xff1a;实现广域互联&#xff08;不同地域局域网之间跨越公网进行互通&#xff09;&#xff1b; VPN&#xff08;Virtual Private Network&#xff0c;虚拟专用网络&#xff09;指的是在一个公共网络中实现虚拟的专用网络&…

python速成之循环分支结构学习

循环结构 应用场景 我们在写程序的时候&#xff0c;一定会遇到需要重复执行某条或某些指令的场景。例如用程序控制机器人踢足球&#xff0c;如果机器人持球而且还没有进入射门范围&#xff0c;那么我们就要一直发出让机器人向球门方向移动的指令。在这个场景中&#xff0c;让…

无涯教程-jQuery - serialize( )方法函数

serialize()方法将一组输入元素序列化为数据字符串。 serialize( ) - 语法 $.serialize( ) serialize( ) - 示例 假设无涯教程在serialize.php文件中具有以下PHP内容- <?php if( $_REQUEST["name"] ) {$name$_REQUEST[name];echo "Welcome ". $na…

【Unity2D】Order in Layer 与Layer的区别

Order in Layer 是Unity 图形渲染的顺序&#xff0c;通过设置Order in Layer &#xff0c;可以设置同层(Layer)的物体出现顺序&#xff0c;可以默认使一种物体出现在另一种物体前方 设置一物体默认在其他物体之上不被遮挡 Layer是Unity中物体的层级&#xff0c;不同物体可以位…

SOLIDWORKS Utilities应用

在实际的生产设计制造中&#xff0c;经常会遇到同一个零件多个版本&#xff0c;有可能再次调用零件的时间已经是很长时间之后&#xff0c;对于版本之间的区别就不会那么清楚&#xff0c;碰到简单明显的零件还可以轻松的找到区别&#xff0c;但是复杂的零件区别的查找可能会造成…

word显示书签并给书签添加颜色

CTRg 定位书签 在 Word 的用户界面中&#xff0c;没有直接的选项可以批量为所有书签设置颜色。但你可以使用 VBA 宏或者编写自定义的功能来实现这个需求。这里给出一个简单的 VBA 宏&#xff0c;它可以设置当前文档中所有书签内文本的颜色&#xff1a;vba Sub ColorAllBookmark…

C++程序获取python脚本控制台输出的一种方法

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 最近要使用C程序调用python脚本&#xff0c;调用方法是通过启动python进程来调用&#xff0c;其中遇到的一个问题是在C程序中需要获取python脚本的控制台…

数组的使用(逆序、冒泡)

内存连续数据类型相同从0开始索引 找出数组中的最大值 #include <iostream> #include <stdlib.h> //随机数所在文件 using namespace std;int main() {int arr[5]{104,134,145,129,89};//初始化没有填的为0 int max0;for(int i0;i<5;i){if(arr[i]>max){ma…

Android AIDL 使用

工程目录图 请点击下面工程名称&#xff0c;跳转到代码的仓库页面&#xff0c;将工程 下载下来 Demo Code 里有详细的注释 代码&#xff1a;LearnAIDL代码&#xff1a;AIDLClient. 参考文献 安卓开发学习之AIDL的使用android进阶-AIDL的基本使用Android AIDL 使用使用 AIDL …