C++ string类

2023-10-31

目录

1. 为什么要学习string类

1.1 C语言中的字符串

1.2 两个面试题(暂不做讲解)

2. 标准库中的string类

2.1 string类(了解)

 2.2 string类的常用接口说明(注意下面我只讲解最常用的接口)

1. string类对象的常见构造

 2. string类对象的容量操作

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

4. string类对象的修改操作

 5. string类非成员函数

6. 牛刀小试

3. string类的模拟实现

3.1 经典的string类问题

3.2 浅拷贝

3.3 深拷贝

 3.3.1 传统版写法的string类

 3.3.2 现代版写法的string类

 3.3 写时拷贝(了解)

3.4 string类的模拟实现

4. 扩展阅读


1. 为什么要学习string

1.1 C语言中的字符串

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

1.2 两个面试题(暂不做讲解)

力扣  字符串相加
OJ 中,有关字符串的题目基本以 string 类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string 类,很少有人去使用 C 库中的字符串操作函数。

2. 标准库中的string

2.1 string(了解)

string - C++ Reference

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类的常用接口说明(注意下面我只讲解最常用的接口)

1. string类对象的常见构造

函数名称

功能说明
string()(重点) 构造空的string类对象,即空字符串
string(const char*s) (重点) 用C-string来构造string类对象
string(size_t n, char c) string类对象中包含n个字符c
string(const string&s)(重点) 拷贝构造函数

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

 2. string类对象的容量操作

函数名称 功能说明
string::size - C++ Reference(重点) 返回字符串有效字符长度
string::length - C++ Reference 返回字符串有效字符长度
string::capacity - C++ Reference 返回空间总大小
string::empty - C++ Reference(重点) 检测字符串释放为空串,是返回true,否则返回false
string::clear - C++ Reference(重点) 清空有效字符
string::reserve - C++ Reference(重点) 为字符串预留空间**
string::resize - C++ Reference(重点) 将有效字符的个数改成n个,多出的空间用字符c填充
// size/clear/resize
void Teststring1()
{
	// 注意:string类对象支持直接用cin和cout进行输入和输出
	string s("hello, bit!!!");
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;

	// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
	s.clear();
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
	// “aaaaaaaaaa”
	s.resize(10, 'a');
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
	// "aaaaaaaaaa\0\0\0\0\0"
	// 注意此时s中有效字符个数已经增加到15个
	s.resize(15);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
	// 将s中有效字符个数缩小到5个
	s.resize(5);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
}
//================================================================================
====
void Teststring2()
{
	string s;
	// 测试reserve是否会改变string中有效元素个数
	s.reserve(100);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
	s.reserve(50);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}
// 利用reserve提高插入数据的效率,避免增容带来的开销
//================================================================================
====
void TestPushBack()
{
	string s;
	size_t sz = s.capacity();
	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}
void TestPushBackReserve()
{
	string s;
	s.reserve(100);
	size_t sz = s.capacity();

	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}
注意:
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 不会改变容量大小。

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

函数名称 功能实现
string::operator[] - C++ Reference(重点) 返回pos位置的字符,const string类对象调用
string::begin - C++ Reference+string::end - C++ Reference begin获取一个字符的迭代器+end获取最后一个字符下一个位置的迭代器
string::rbegin - C++ Reference+string::rend - C++ Reference begin获取一个字符的迭代器+end获取最后一个字符下一个位置的迭代器
范围for C++11支持更简洁的范围for的新遍历方式
void Teststring()
{
	string s1("hello Bit");
	const string s2("Hello Bit");
	cout << s1 << " " << s2 << endl;
	cout << s1[0] << " " << s2[0] << endl;

	s1[0] = 'H';
	cout << s1 << endl;

	// s2[0] = 'h'; 代码编译失败,因为const类型对象不能修改
}
void Teststring()
{
	string s("hello Bit");
	// 3种遍历方式:
	// 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,
	// 另外以下三种方式对于string而言,第一种使用最多
	// 1. for+operator[]
	for (size_t i = 0; i < s.size(); ++i)
		cout << s[i] << endl;

	// 2.迭代器
	string::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << endl;
		++it;
	}

	string::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
		cout << *rit << endl;

	// 3.范围for
	for (auto ch : s)
		cout << ch << endl;
}

三种遍历方式

 int main()
{
	string s1;
	string s2("hello bit");

	// 三种遍历
	// 1、下标+[]
	for (size_t i = 0; i < s2.size(); ++i)
	{
		// s2.operator[](i)
		s2[i] = 'x';
	}
	cout << endl;

	for (size_t i = 0; i < s2.size(); ++i)
	{
		// s2.operator[](i)
		cout << s2[i] << " ";
		//cout << s2.at(i) << " ";
	}
	cout << endl;

	//s2[10]; // 越界断言报错
	try 
	{
		s2.at(10);  // 越界抛异常
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}

	// 2、迭代器
	// [begin(), end() ) end()返回的不是最后一个数据位置的迭代器,返回是最后一个位置下一个位置
	// 也要注意的是,C++中凡是给迭代器一般都是给的[)左闭右开的区间
	// 迭代器是类似指针一样东西,具体是什么我们讲了底层实现才能知道
	string::iterator it = s2.begin();
	while (it != s2.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	// 迭代器意义:像string、vector支持[]遍历,但是list、map等等容器不支持[]
	// 我们就要用迭代器遍历,所以迭代器是一种统一使用的方式
	vector<int> v = { 1, 2, 3, 4 };
	vector<int>::iterator vit = v.begin();
	while (vit != v.end())
	{
		cout << *vit << " ";
		++vit;
	}
	cout << endl;

	list<int> lt = { 1, 2, 3, 4 };
	list<int>::iterator ltit = lt.begin();
	while (ltit != lt.end())
	{
		cout << *ltit << " ";
		++ltit;
	}
	cout << endl;

	// 反向迭代器
	string s3("123456");
	string::iterator it3 = s3.begin();
	while (it3 != s3.end())
	{
		*it3 += 5;

		++it3;
	}
	cout << endl;

	string::reverse_iterator rit = s3.rbegin();
	while (rit != s3.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	// 3、C++11 提供 范围for, 特点:写起来简洁
	// 依次取容器中的数据,赋值给e,自动判断结束
	//for (auto& e : s3)
	for (char& e : s3)
	{
		e += 1;
	}
	cout << endl;

	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;

	for (auto x : v)
	{
		cout << x << " ";
	}
	cout << endl;

	for (auto x : lt)
	{
		cout << x << " ";
	}
	cout << endl;


	return 0;
}

 

4. string类对象的修改操作

函数名称 功能说明
string::push_back - C++ Reference
在字符串后尾插字符 c
string::append - C++ Reference
在字符串后追加一个字符串
string::operator+= - C++ Reference(重点) 在字符串后追加字符str
string::c_str - C++ Reference(重点) 返回C格式字符串
string::find - C++ Reference+string::npos - C++ Reference(重点)
从字符串 pos 位置开始往后找字符 c ,返回该字符在字符串中的位置
string::rfind - C++ Reference
从字符串 pos 位置开始往前找字符 c ,返回该字符在字符串中的位置
string::substr - C++ Reference
str 中从 pos 位置开始,截取 n 个字符,然后将其返回
void Teststring()
{
	string str;
	str.push_back(' '); // 在str后插入空格
	str.append("hello"); // 在str后追加一个字符"hello"
	str += 'b'; // 在str后追加一个字符'b' 
	str += "it"; // 在str后追加一个字符串"it"
	cout << str << endl;
	cout << str.c_str() << endl; // 以C语言的方式打印字符串

	// 获取file的后缀
	string file1("string.cpp");
	size_t pos = file.rfind('.');
	string suffix(file.substr(pos, file.size() - pos));
	cout << suffix << endl;

	// npos是string里面的一个静态成员变量
	// static const size_t npos = -1;

	// 取出url中的域名
	sring url("http://www.cplusplus.com/reference/string/string/find/");
	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;

	// 删除url的协议前缀
	pos = url.find("://");
	url.erase(0, pos + 3);
	cout << url << endl;
}
int main()
{
	string s1;
	s1.push_back('h');
	s1.push_back('e');
	s1.push_back('l');
	s1.push_back('l');
	s1.push_back('o');

	s1.append("world");
	cout << s1 << endl;

	string s2("!!!!");
	//s1.append(s2);
	s1.append(s2.begin(), s2.end());
	cout << s1 << endl;

	// 实际中最喜欢用这个+=
	s1 += ' ';
	s1 += "比特";
	s1 += s2;
	cout << s1 << endl;

	// 尽量少用insert,因为底层实现是数组,头部或者中间插入需要挪动数据
	s1.insert(0, "x");
	cout << s1 << endl;
	s1.insert(3, "yyyy");
	cout << s1 << endl;
	s1.insert(0, "yyyy");
	cout << s1 << endl;
	//s1.insert(300, "yyyy");
	cout << s1 << endl;

	s1.erase(0, 1);
	cout << s1 << endl;

	s1.erase(0, 3);
	cout << s1 << endl;

	s1.erase(3, 10);
	cout << s1 << endl;

	//s1.erase(3, 100);
	s1.erase(3);
	cout << s1 << endl;

	s1.erase();
	cout << s1 << endl;

	return 0;
}

 c_str用于配合其他函数接口

 假设要求取出文件名的后缀

	// 假设要求取出文件名的后缀
	string filename = "test.txt.zip";
	size_t pos = filename.rfind('.');//实现只取最后一个后缀
	if (pos != string::npos)
	{
		//string suff(filename, pos, filename.size() - pos);
		//string suff(filename, pos);
		//string suff = filename.substr(pos, filename.size() - pos);
		string suff = filename.substr(pos);

		cout << suff << endl;
	}
要求写一个程序分别取出域名和协议名
string GetDomain(const string& url)
{
	size_t pos = url.find("://");
	if (pos != string::npos)
	{
		size_t start = pos + 3;
		size_t end = url.find('/', start);
		if (end != string::npos)
		{
			return url.substr(start, end - start);
		}
		else
		{
			return string();
		}
	}
	else
	{
		return string();
	}
}

string GetProtocol(const string& url)
{
	size_t pos = url.find("://");
	if (pos != string::npos)
	{
		return url.substr(0, pos - 0);
	}
	else
	{
		//string s;
		//return s;
		return string();//返回一个匿名对象
	}
}
    string url1 = "http://www.cplusplus.com/reference/string/string/rfind/";
	string url2 = "https://tower.im/users/sign_in";
	string url3 = "tower.im/users/sign_in";

	cout << GetDomain(url1) << endl;
	cout << GetProtocol(url1) << endl;

	cout << GetDomain(url2) << endl;
	cout << GetProtocol(url2) << endl;

	cout << GetProtocol(url3) << endl;

注意:
1. string 尾部追加字符时, s.push_back(c) / s.append(1, c) / s += 'c' 三种的实现方式差不多,一般情况下string 类的 += 操作用的比较多, += 操作不仅可以连接单个字符,还可以连接字符串。
2. string 操作时,如果能够大概预估到放多少字符,可以先通过 reserve 把空间预留好。

 5. string类非成员函数

函数 功能说明
operator+ (string) - C++ Reference
尽量少用,因为传值返回,导致深拷贝效率低
operator>> (string) - C++ Reference(重点)
输入运算符重载
operator<< (string) - C++ Reference(重点) 输出运算符重载
getline (string) - C++ Reference(重点) 获取一行字符串
relational operators (string) - C++ Reference(重点) 大小比较

 上面的几个接口大家了解一下,下面的OJ题目中会有一些体现他们的使用。string类中还有一些其他的操作,这里不一一列举,大家在需要用到时不明白了查文档即可。

6. 牛刀小试

见博客

3. string类的模拟实现

3.1 经典的string类问题

上面已经对 string 类进行了简单的介绍,大家只要能够正常使用即可。在面试中,面试官总喜欢让学生自己来模拟实现string 类,最主要是实现 string 类的构造、拷贝构造、赋值运算符重载以及析构函数。大家看下以下string 类的实现是否有问题?
class string
{
public:
	/*string()
	:_str(new char[1])
	{*_str = '\0';}
	*/
	//string(const char* str = "\0") 错误示范
	//string(const char* str = nullptr) 错误示范
	string(const char* str = "")
	{
		// 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
		if (nullptr == str)
		{
			assert(false);
			return;
		}

		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	~string()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}

private:
	char* _str;
};
// 测试
void Teststring()
{
	string s1("hello bit!!!");
	string s2(s1);
}

说明:
上述 string 类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用 s1 s2 时,编译器会调用默认的拷贝构造。最终导致的问题是, s1 s2 共用同一块内存空间,在释放时同一块 空间被释放多次而引起程序崩溃 ,这种拷贝方式,称为浅拷贝

3.2 浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来 。如果 对象中管理资源 ,最后就会 导致多个对象共 享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为 还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规 。要解决浅拷贝问题, C++ 中引入了深拷贝。

3.3 深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

 3.3.1 传统版写法的string

class string
{
public:
	string(const char* str = "")
	{
		// 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
		if (nullptr == str)
		{
			assert(false);
			return;
		}

		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	string(const string& s)
		: _str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}

	string& operator=(const string& s)
	{
		if (this != &s)
		{
			char* pStr = new char[strlen(s._str) + 1];
			strcpy(pStr, s._str);
			delete[] _str;
			_str = pStr;
		}

		return *this;
	}

	~string()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}

private:
	char* _str;
};

 3.3.2 现代版写法的string

class string
{
public:
	string(const char* str = "")
	{
		if (nullptr == str)
			str = "";

		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	string(const string& s)
		: _str(nullptr)
	{
		string strTmp(s._str);
		swap(_str, strTmp._str);
	}

	// 对比下和上面的赋值那个实现比较好?
	string& operator=(string s)
	{
		swap(_str, s._str);
		return *this;
	}

	/*
	string& operator=(const string& s)
	{
	if(this != &s)
	{
	string strTmp(s);
	swap(_str, strTmp._str);
	}

	return *this;
	}
	*/

	~string()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}

private:
	char* _str;
};

 3.3 写时拷贝(了解)

 

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成 1 ,每增加一个对象使用该资源,就给计数增加1 ,当某个对象被销毁时,先给该计数减 1 ,然后再检查是否需要释放资源,如果计数为 1 ,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

3.4 string类的模拟实现与补充

见博客

 

 

补充:

4. 扩展阅读

C++面试中string类的一种正确写法 | 酷 壳 - CoolShell

STL 的string类怎么啦?_haoel的博客-CSDN博客

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ string类 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 对类 static constexpr 结构的未定义引用,g++ 与 clang

    这是我的代码 a cp p struct int2 int x y struct Foo static constexpr int bar1 1 static constexpr int2 bar2 1 2 int foo1 return
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么

随机推荐