关于标准库中的string类 - c++

目录

关于string类

string类的常用接口

string类常用接口的简单模拟实现


关于string类

string类在cplusplus.com的文档介绍

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

string类的常用接口

 string 类对象的常见构造/析构
void Teststring()
{string s1; // 构造空的string类对象s1string s2("hello world"); // 用C格式字符串构造string类对象s2string s3(s2); // 拷贝构造s3
}

string 类对象的容量操作
#include <iostream>
using namespace std;#include <string>//-----------------------------------------------------------------------
//测试string容量相关接口 
//size / capacity / clear / resizevoid Teststring()
{//注意:string类对象支持直接用cin和cout进行输入和输出string s1("hello world");cout << s1.size() << endl;cout << s1.length() << endl;cout << s1.capacity() << endl;cout << s1 << endl;//将s1中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小s1.clear();cout << s1.size() << endl;cout << s1.capacity() << endl;//将s1中的有效字符个数增加到6个,并且使用'*'来进行填充s1.resize(6, '*');cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1 << endl;// 将s1中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充// 注意此时s中有效字符个数已经增加到15个s1.resize(15);cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1 << endl;//另外,resize也有删除有效字符的功能,但是不会改变底层空间的大小s1.resize(1);cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1 << endl;
}//-----------------------------------------------------------------------
//测试reserve
//1.是否改变string类中间的有效元素个数
//2.当reserve参数小于string底层空间时,是否会将空间缩小void TestReserve()
{string s1;s1.reserve(100);cout << s1.size() << endl;cout << s1.capacity() << endl;s1.reserve(10);cout << s1.size() << endl;cout << s1.capacity() << endl;
}int main()
{Teststring();TestReserve();return 0;
}

注意:
  • 1. size()length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()
  • 2. clear()只是将string中有效字符清空,不改变底层空间大小。
  • 3. resize(size_t n) resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  • 4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
string 类对象的访问及遍历操作
#include <iostream>
using namespace std;#include <string>//---------------------------------------------------------------------
// string的遍历及访问
// 1.迭代器:begin()+end() / rbegin()+ rend() ...
// 2.for+operator[]  
// 3.范围for:底层实现是使用迭代器,实际上是迭代器的封装 (范围forC++11后才支持)void Teststring()
{string s1("hello world");//1.string::iterator it = s1.begin();while (it != s1.end()){cout << *it;++it;}cout << endl;//2.for (size_t i = 0; i < s1.size(); ++i){cout << s1[i];}cout << endl;//3.for (auto ch : s1){cout << ch;}cout << endl;
}int main()
{Teststring();return 0;
}

string 类对象的修改操作
#include <iostream>
using namespace std;#include <string>//---------------------------------------------------------------------
//string的测试与修改
//1.插入(拼接)方式:push_back / append / operator+=
//2.任意位置插入:insert
//3.查找 / 反向查找:find / rfind
//4.替换字符:replace 
//5.截取子串 :substr
//6.读取字符:geline
//7.删除:erase
//8.返回c形式字符串 : c_strvoid TestString()
{string s1("hello world");//插入一个字符s1.push_back(' ');s1.push_back('i');  cout << s1 << endl;//插入一串字符s1.append(" ");s1.append("love");cout << s1 << endl;//c++更喜欢使用+=s1 += ' ';s1 += "you";cout << s1 << endl;
}void TestInsert()
{string s1("hello");//任意位置插入s1.insert(5, 1, ' ');s1.insert(6, "world");cout << s1 << endl;//使用迭代器s1.insert(s1.begin(), '!');s1.insert(s1.begin()+1, ' ');cout << s1 << endl;
}void TestFind_Replace()
{//笔试题:将下列所有空格都改成 %20//思路1.string str("hello world i love you");size_t pos = str.find(' ');while (pos != string::npos){str.replace(pos, 1, "%20");pos = str.find(' ');}cout << str << endl;//====================================//优化://string str("hello world i love you");1.提前开空间,减少扩容消耗的效率//size_t num = 0;//for (auto ch : str)//{//	if (ch == ' ')//	{//		num++;//	}//}//str.reserve(str.size() + 2 * num);//size_t pos = str.find(' ');//while (pos != string::npos)//{//	str.replace(pos, 1, "%20");//	//2.避免重复访问数据,提高效率//	pos = str.find(' ', pos+3);//}//cout << str << endl;//==================================//思路2.//string str("hello world i love you");//string newStr;//size_t num = 0;//for (auto ch : str)//{//	if (ch == ' ')//	{//		num++;//	}//}//newStr.reserve(newStr.size() + 2 * num);//for (auto ch : str)//{//	if (ch != ' ')//	{//		newStr += ch;//	}//	else//	{//		newStr += "%20";//	}//}//cout << newStr << endl;}void TestFind_Substr()
{//笔试题:获取ulr中的域名string url("http://www.cplusplus.com/reference/string/");cout << url << endl;size_t start = url.find("://");if (start == string::npos){cout << "invalid url" << endl;return;}start += 3;size_t finish = url.find('/', start);string address = url.substr(start, finish - start);cout << address << endl;}void TestRfind_Getline()
{//笔试题:求字符串最后出现单词的长度string str;//注意:为什么这里使用 getline 而不使用 cin //因为 cin 类似于scanf ,读取字符遇到空格或者\0就会终止,无法读取后面的字符//使用c++提供了 getline :遇到换行符才会终止读取getline(cin, str);size_t pos = str.rfind(' ');if (pos != string::npos){cout << str.size() - pos - 1 << endl;}else{//只有一个单词的情况cout << str.size() << endl;}}void TestErase()
{string str("hello world");str.erase(5, 1);cout << str << endl;str.erase(5, 10);cout << str << endl;str.erase(1);cout << str << endl;
}void TestC_str()
{string str("hello world");cout << str << endl;cout << str.c_str() << endl;cout << str << endl;cout << (void*)str.c_str() << endl;str += ' ';str += '\0';str += "******";cout << str << endl;cout << str.c_str() << endl;
}int main()
{TestString();TestInsert();TestFind_Replace();TestFind_Substr();TestRfind_Getline();TestErase();TestC_str();return 0;
}
注意:
  • 1. string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
  • 2. string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

string类常用接口的简单模拟实现

#include <iostream>using namespace std;#include <assert.h>
#include<string>class _string
{public://模拟实现常用接口//...private:char* _str;size_t size;size_t capacity;static const size_t npos;
};const size_t string::npos = -1;

注:npos

       关于npos ,这里建议类里面声明,类外面定义,不建议在类里面给缺省值。因为成员变量给缺省值是因为会在初始化列表进行初始化,但是strtic修饰的静态成员变量,不能给缺省值,因为静态成员变量存储位置在静态区,属于整个工程。

        另外,c++11有一个值得吐槽的地方,就是开了一个特例,如果加const ,那么整型静态成员变量可以给缺省值,如下图:

1.构造函数
	_string():_str(new char[1]), _size(0),_capacity(0){_str[0] = '\0';}_string(const char* str):_size(strlen(str)){_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}

问:为什么无参的字符串构造函数 _str(new char[1])  初始化不给 nullptr 要给一个空间且加上[ ]?

答:因为如果给nullptr的话,cout是会对_str进行解引用,这样会导致程序崩溃,所以才会给一个空间。而给[ ]是为了在析构的时候与delete[ ] 保持一致。

问:为什么 _str = new char[_capacity + 1] 中要+1?

答:因为_capacity是容量字符,指的是能够存取多少个有效字符,而vs认为 '\0'属于标识符,不属于有效字符的范畴,所以+1是为了给'\0'预留空间。

  • 优化:以上两个函数可以优化为缺省函数
	_string(const char* str = "\0"):_size(strlen(str)){_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}

1.1拷贝构造
	_string(const _string& str):_size(str._size),_capacity(str._capacity){_str = new char[_capacity + 1];strcpy(_str, str._str);}

2.赋值 =

	_string operator=(const _string& str){delete[] _str;_str = new char[str._capacity + 1];strcpy(_str, str._str);_size = str._size;_size = str._capacity;return *this;}
  • 上述代码有一个问题,就是程序开始就将_str的空间进行释放,这样可能会导致数据的丢失,所以需要进行优化。
	_string operator=(const _string& str){if (this != &str){char* tmp = new char[str._capacity + 1];strcpy(tmp, str._str);delete[] _str;_str = tmp;_size = str._size;_capacity = str._capacity;}return *this;}

3.析构函数 ~

	~_string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}

4.成员访问

    char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}size_t size() const{return _size;}size_t capacity() const{return _capacity;}const char* c_str(){return _str;}

5.简单迭代器 iterator
	typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}

6.关系运算符(relational operators)string

    bool operator>(const _string& str) const{return strcmp(_str, str._str) > 0;}bool operator==(const _string& str) const{return strcmp(_str, str._str) == 0;}bool operator>=(const _string& str) const{return *this > str || *this == str;}bool operator<(const _string& str) const{return !(*this >= str);}bool operator<=(const _string& str) const{return !(*this > str);}bool operator!=(const _string& str) const{return !(*this == str);}

7.reserve

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

问:这里为什么要加个 if 进行判断?

答:因为如果不进行判断,当 n < _capacity 的时候,会导致缩容的问题,对程序的安全造成隐患,因此要加个判断,避免出现缩容的情况。

8.push_back
	void push_back(char ch){if (_size + 1 > _capacity){reserve(_capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}

       上述代码有一个隐藏的问题,那就是如果 _capacity 如果为 0 ,这个时候进行push_back,代码就会越界,从而崩溃。解决办法有两个,一是修改一下构造函数,而是进行判断,如果_capacity 为 0 就直接进行赋值。

优化:
	_string(const char* str = "\0"):_size(strlen(str)){_capacity = _size == 0 ? 3 : _size;_str = new char[_capacity + 1];strcpy(_str, str);}
9.append
	void append(const char* str){if (_size + 1 > _capacity){reserve(_capacity * 2);}size_t len = strlen(str);strcpy(_str + _size, str);_size += len;}

问:这里为什么不适用strcat?

答:因为 strcat 是自己去寻找 '\0' 的位置,而 _str + len 就是 '\0' 的位置 ,strcpy 函数会把需要拷贝的字符串最后的位置的 '\0'拷贝过来。

10.+=
	_string& operator+=(char ch){push_back(ch);return *this;}_string& operator+=(const  char* str){append(str);return *this;}

11.resize
void resize(size_t n, char ch = '\0')
{if (n <= _size){//保留前n个 - 删除数据_size = n;_str[_size] = '\0';}else  //n > size{if (n > _capacity){reserve(n);}size_t i = _size;while (i < n){_str[i++] = ch;}_size = n;_str[_size] = '\0';}
}

12.insert
	void insert(size_t pos, char ch){assert(pos <= _size);if (_size + 1 > _capacity){reserve(_capacity * 2);}size_t end = _size;while (end >= pos){_str[end + 1] = _str[end];--end;}_str[pos] = ch;++_size;}

        以上代码有个问题,那就是 end 属于无符号整型,而 pos 也属于无符号整型,这里会造成程序的死循环。即使把 end 置成 int 类型,但是也会发生隐式类型转换,有符号会转换成无符号。也不建议进行强转,所以解决办法的话,就是修改挪动数据的逻辑。

优化:

	void insert(size_t pos, char ch){assert(pos <= _size);if (_size + 1 > _capacity){reserve(_capacity * 2);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;}

当然,insert 还需要重载插入字符串

	void insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_capacity * 2 + len);}size_t end = _size + len;while (end > pos + len - 1){_str[end] = _str[end - len];--end;}strncpy(_str + pos, str, len);_size += len;}

这里之所以选择 strncpy 而不是 strcpy ,因为 strcpy 会拷贝字符串结尾的标识符 '\0'。

13.erase
	void erase(size_t pos, size_t len = npos){//尾部直接删除if (pos + len > _size || len == npos){_str[pos] = '\0';_size = pos;}else //挪动数据{strcpy(_str + pos, _str + pos + len);_size -= len;}}

14.swap
	void swap(_string& str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}

15.find
	size_t find(char ch, size_t pos = 0){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);char* p = strstr(_str + pos, str); //strstr : 返回第一次指针匹配的位置if (p == nullptr){return npos;}else{return p - _str;}}

17.<<
ostream& operator<<(ostream& out, const string& str)
{for (auto ch : str){out << str;}return out;
}

        注:因为在类域中存在this指针,而友元函数又会增加耦合度,破环封装,所以这里建议流插入或者流提取的实现不写在类域之中。

18.>>        
istream& operator>>(istream& in, string& str)
{char ch;in >> ch;while (ch != ' ' && ch != '\n'){str += ch;in >> ch;}return in;
}

         问:为什么如果输入多组字符,中间用空格或者换行隔开的话,编译器只能拿到第一组字符,拿不到后面的字符。

答:因为cin或者sancf读取的时候会默认忽然空格或者换行,不进行识别,默认空格或者换行是多个值之间的间隔。流提取并未在输入中获取字符,而是在缓冲区获取字符,而空格或者换行未进入缓冲区,c++/c 规定,值与值之间的区分必须是空格或者换行,所以输入空格或者换行会被认为是多个字符之间的间隔,不会被cin 或者 scanf 拿到。

优化:

istream& operator>>(istream& in, string& str)
{str.clear();  //清除掉之前的字符char ch = in.get(); //get()函数不区分间隔while (ch != ' ' && ch != '\n'){str += ch;ch = in.get();}return in;
}

上述版本只是一个简单的版本,实际实现可能有些复杂

istream& operator>>(istream& in, string& str)
{str.clear();  //清除掉之前的字符char ch = in.get(); //get()函数不区分间隔char buff[128];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';str += buff;i = 0;}ch = in.get();}if (i != 0) //防止最后的数据没有添加进去{buff[i] = '\0';str += buff;}return in;
}

接口实现代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>using namespace std;#include <string>
#include <assert.h>class _string
{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}//模拟实现 //_string()//	:_str(new char[1])//	, _size(0)//	,_capacity(0)//{//	_str[0] = '\0';//}_string(const char* str = "\0"):_size(strlen(str)){_capacity = _size == 0 ? 3 : _size;_str = new char[_capacity + 1];strcpy(_str, str);}_string(const _string& str):_size(str._size), _capacity(str._capacity){_str = new char[_capacity + 1];strcpy(_str, str._str);}_string operator=(const _string& str){if (this != &str){char* tmp = new char[str._capacity + 1];strcpy(tmp, str._str);delete[] _str;_str = tmp;_size = str._size;_capacity = str._capacity;}return *this;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}size_t size() const{return _size;}size_t capacity() const{return _capacity;}const char* c_str(){return _str;}bool operator>(const _string& str) const{return strcmp(_str, str._str) > 0;}bool operator==(const _string& str) const{return strcmp(_str, str._str) == 0;}bool operator>=(const _string& str) const{return *this > str || *this == str;}bool operator<(const _string& str) const{return !(*this >= str);}bool operator<=(const _string& str) const{return !(*this > str);}bool operator!=(const _string& str) const{return !(*this == str);}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 + 1 > _capacity){reserve(_capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}void append(const char* str){if (_size + 1 > _capacity){reserve(_capacity * 2);}size_t len = strlen(str);strcpy(_str + _size, str);_size += len;}_string& operator+=(char ch){push_back(ch);return *this;}_string& operator+=(const  char* str){append(str);return *this;}void resize(size_t n, char ch = '\0'){if (n <= _size){//保留前n个 - 删除数据_size = n;_str[_size] = '\0';}else  //n > size{if (n > _capacity){reserve(n);}size_t i = _size;while (i < n){_str[i++] = ch;}_size = n;_str[_size] = '\0';}}void insert(size_t pos, char ch){assert(pos <= _size);if (_size + 1 > _capacity){reserve(_capacity * 2);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;}void insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_capacity * 2 + len);}size_t end = _size + len;while (end > pos + len - 1){_str[end] = _str[end - len];--end;}strncpy(_str + pos, str, len);_size += len;}void erase(size_t pos, size_t len = npos){//尾部直接删除if (pos + len > _size || len == npos){_str[pos] = '\0';_size = pos;}else //挪动数据{strcpy(_str + pos, _str + pos + len);_size -= len;}}void swap(_string& str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}size_t find(char ch, size_t pos = 0){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);char* p = strstr(_str + pos, str); //strstr : 返回第一次指针匹配的位置if (p == nullptr){return npos;}else{return p - _str;}}void clear(){_str[0] = '\0';_size = 0;}~_string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}private:char* _str;size_t _size;size_t _capacity;//static const size_t npos;static const size_t npos = -1;
};//const size_t string::npos = -1;ostream& operator<<(ostream& out, const string& str)
{for (auto ch : str){out << str;}return out;
}istream& operator>>(istream& in, string& str)
{str.clear();  //清除掉之前的字符char ch = in.get(); //get()函数不区分间隔char buff[128];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';str += buff;i = 0;}ch = in.get();}if (i != 0) //防止最后的数据没有添加进去{buff[i] = '\0';str += buff;}return in;
}


以上仅代表个人看法,欢迎讨论

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

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

相关文章

shell条件语句

一.条件测试 1.三种测试方法 ①test命令测试 ②[ ]测试&#xff08;注意前后需要有空格&#xff09; ③[[ ]]&#xff1a;加强版[ ]&#xff0c;测试支持通配符&#xff08;匹配字符串&#xff09;和正则表达式 二.条件语句 2.1 test命令 测试特定的表达式是否成立…

谷歌浏览器任意文件访问漏洞(CVE-2023-4357)复现

1.漏洞级别 高危 2.漏洞描述 该漏洞的存在是由于 Google Chrome中未充分验证 XML 中不受信任的输入。远程攻击者可利用该漏洞通过构建的 HTML 页面绕过文件访问限制&#xff0c;导致chrome任意文件读取。 总结&#xff1a;一个XXE漏洞 3.利用范围 Google Chrome < 116.…

px4+vio实现无人机室内定位

文章主要讲述px4 如何利用vins_fusion里程计数据实现在室内定位功能。 文章基于以下软、硬件展开。 硬件软件机载电脑&#xff1a; Intel NUC系统&#xff1a;Ubuntu 20.04相机&#xff1a; Intel Realsense D435iros&#xff1a;noetic飞控&#xff1a;Pixhawk 2.4.8固件&am…

服务器系列之 成功解决 com.jcraft.jsch.JSchException: Auth fail

我 | 在这里 &#x1f575;️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 &#x1f3e0; 工作 | 广州 ⭐ Java 全栈开发&#xff08;软件工程师&#xff09; &#x1f383; 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 &#x1f3f7;️ 标签 | 男 自律狂人 目标明确 责任心强 ✈️公…

如何使用rclone将腾讯云COS桶中的数据同步到华为云OBS

在多云策略与数据迁移趋势下&#xff0c;企业往往需要将数据在不同云服务提供商之间进行迁移。本文介绍如何使用rclone工具同步腾讯云COS&#xff08;Cloud Object Storage&#xff09;桶中的数据到华为云OBS&#xff08;Object Storage Service&#xff09;。先决条件是您已经…

Python---函数的应用案例(多个)

案例&#xff1a;使用print方法打印一条横线 print(- * 40) 案例&#xff1a;对上个案例进行升级&#xff0c;可以根据输入的num数值&#xff0c;生成指定数量的横线 def print_lines(num, length):""" print_lines函数主要作用用于生成多条指定长度的横线&…

快速幂极简写法快速幂求逆元

快速幂原理介绍 快速幂模板 int qmi(int a, int k, int p) {int res 1;while (k) {//后面的a其实是底数与其指数的运算结果了&#xff0c;是不断迭代的//第一个a其实就是a的2的0次方if (k & 1) res (res * a) % p;a (a * a) % p;//注意&#xff0c;a是一个不断变化的过…

Linux操作系统使用及C高级编程-D9D10Linux 服务搭建与使用

TFTP服务器 TFTP&#xff08;Trivial File Transfer Protocol&#xff09;即简单文件传输协议&#xff0c;是TCP/IP协议中一个用来在客户机与服务器之间进行简单文件传输的协议&#xff0c;提供不复杂、开销不大的文件传输服务。端口号为69 1、使用客户服务器方式和使用UDP数据…

python趣味编程-5分钟实现一个简单弹跳球游戏(含源码、步骤讲解)

简单的Python弹跳球程序是使用Python编程语言开发的。 Python 中的弹跳球游戏是 使用 Tkinter 和图形用户界面 (GUI) 设计的,它是一个桌面应用程序。 Python 中的弹跳球游戏代码使用Canvas 在 Python 中绘制对象和随机模块。

UVM项目笔记——通过寄存器模型实现AHB接口的寄存器读写(内含源码)

目录 1.前言 2.DRIVER实现 2.1 AHB二级流水时序 2.2 “队列错位法”实现driver 2.3 driver代码 2.4 仿真log与波形 2.5 多级流水拓展方法 1.前言 UVM driver在接口协议的实现中起着非常重要的作用&#xff0c;因为它一端处理基于类的事务级sequence&#xff0c;另一端处…

Pytorch从零开始实战10

Pytorch从零开始实战——ResNet-50算法实战 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNet-50算法实战环境准备数据集模型选择开始训练可视化模型预测总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c…

QT专栏2 -Qt for Android

#2023年11月18日 # Qt version 6.6 JDK17 JDK 安装 Java Downloads | Oracle 设置环境变量 鼠标右键我的电脑&#xff0c;出现如下界面 Qt配置 改用JDK18&#xff0c;没有乱码&#xff0c;由于不影响APK产生。 做了好多尝试&#xff0c;更换JDK版本(11,18,19,21)&…

labelImg

labelImg 在anaconda虚拟环境中安装labelImg 进入conda虚拟环境DL2中 输入命令&#xff1a; pip install PyQt5 pip install pyqt5-tools pip install lxml pip install labelimg PyQt5:是用于创建GUI应用程序的跨平台工具包&#xff0c;它将Python与Qt库融为一体 Lxml&#…

GDB Debugging Notes

1 Debugging programs using gdb 1.1 gdb简介 gdb是一个功能强大的调试工具&#xff0c;可以用来调试C程序或C程序。在使用这个工具进行程序调试时&#xff0c;主要涉及下面几个方面的操作&#xff1a; 启动程序:在启动程序时&#xff0c;可以设置程序运行环境。设置断点:程序…

Double 4 VR智能互动系统在轨道交通实训教学中的应用

Double 4 VR智能互动系统是一种集成了虚拟现实技术、人工智能和物联网技术的教学系统。计算机通过模拟真实的轨道交通环境&#xff0c;为学生提供了一个高度仿真的学习环境&#xff0c;帮助他们更好地理解和掌握轨道交通的相关知识和技能。 首先&#xff0c;Double 4 VR智能互动…

composer切换全局镜像源的方法

composer 默认配置中的镜像地址为国外的&#xff0c;在下载一些依赖包的时候会感觉很慢。当然国内也有很多composer镜像地址的&#xff0c;比如阿里云&#xff0c;腾讯云等。下面的博文73so博客就和大家说说&#xff0c;如何将composer的默认镜像改为国内镜像源的方法。 compo…

Redis跳跃表

前言 跳跃表(skiplist)是一种有序数据结构&#xff0c;它通过在每一个节点中维持多个指向其他节点的指针&#xff0c;从而达到快速访问节点的目的。 跳跃表支持平均O(logN)&#xff0c;最坏O(N)&#xff0c;复杂度的节点查找&#xff0c;还可以通过顺序性来批量处理节点…

2021秋招-算法-递归

算法-递归 教程: ⭐告别递归&#xff0c;谈谈我的一些经验 LeetCode刷题总结-递归篇 基础框架 leetcode刷题 1.leetcode-101. 对称二叉树-简单 101. 对称二叉树 给定一个二叉树&#xff0c;检查它是否是镜像对称的。 例如&#xff0c;二叉树 [1,2,2,3,4,4,3] 是对称的。…

子虔与罗克韦尔自动化合作 进博会签约自动化净零智造联创中心

11月6日进博会现场&#xff0c;漕河泾罗克韦尔自动化净零智造联创中心合作协议签约暨合作伙伴&#xff08;第一批&#xff09;授牌仪式举办&#xff0c;子虔科技作为联创中心合作伙伴签约&#xff0c;携手共建智能制造&#xff0c;引领行业可持续发展。 图示&#xff1a;子虔科…

【电路笔记】-电源电压

电源电压 文章目录 电源电压1、概述1.1 交流发电机1.2 电池1.3 理想电压源1.4 实际电压源1.5 连接规则 2、相关源2.1 压控电压源 (VCVS)2.2 电流控制电压源 (CCVS) 3、总结 在本文中&#xff0c;我们详细介绍了称为电源电压的重要电子元件的架构、功能和使用。 我们首先提出理想…