标准库中 string 的使用

目录

1. string 是什么

2. 标准库中的string

2.1. C++11 的 string::string

2.2. C++ 11 的 string::operator= 

2.3. element access

2.3.1. operator[]

2.3.2. at

2.4. iterator

2.4.1. begin() and end()

2.4.2. rbegin() and rend()

2.4. Modifiers

2.4.1. push_back

2.4.2. append

2.4.3. operator+=

2.4.4. assign

2.4.5. insert

2.4.6. erase

2.5. string实例化对象的扩容机制

2.5.1. reserve

2.5.2. resize 

2.6. string operations

2.6.1. c_str

2.6.2. find and substr

2.7. Non-member function overloads

2.7.1. getline

2.7.2. to_string

2.7.3. 字符串转化成对应的数字类型:


1. string 是什么

  • string是表示字符串的一个类;
  • 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作 string 的常规操作;
  • string在底层实际是: 通过 basic_string 这个类模板实例化的具体类,即basic_string<char>
  • typedef  basic_string<char>  string;
  • 不能操作多字节或者变长字符的序列;
  • 在使用string类时,必须包含 #include<string>。

2. 标准库中的string

2.1. C++11 的 string::string

首先看看 string 的默认构造:

int main()
{
	std::string s1;
	return 0;
}

现象如下: 

用一个字符串构造一个string:

int main()
{
	std::string s1("hello string");
	return 0;
}

现象如下:

通过上面的两个例子,我们发现,对于标准库中的 string 来说,不管 string 对象是空串还是非空串,都会有一个 '\0' 作为字符串的结尾,这是为了满足C风格字符串的约定和方便字符数组的处理,同时,我们发现,'\0' 这个字符并不计入 string 中的 size;

C++11 的 string 构造函数具体如下:

//default(1)
string();

//copy (2)	
string (const string& str);

//substring (3)	
//这里的npos 是一个 static const size_t npos = -1;
string (const string& str, size_t pos, size_t len = npos);

//from c-string (4)	
string (const char* s);

//from buffer (5)	
string (const char* s, size_t n);

//fill (6)	
string (size_t n, char c);

//range (7)	
template <class InputIterator>
string  (InputIterator first, InputIterator last);

// initializer list (8)
string (initializer_list<char> il);

// move (9)
string (string&& str) noexcept;

下面是上述构造函数的使用示例: 

void Test1()
{
	// default
	std::string s1;
	std::cout << "s1: " << s1 << std::endl;

	// from c-string
	std::string s2("cowsay hello");
	std::cout << "s2: " << s2 << std::endl; //cowsay hello

	// copy
	std::string s3(s2);
	std::cout << "s3: " << s3 << std::endl;   //cowsay hello

	// substring
	std::string s4(s2, 5, 3);  
	std::cout << "s4: " << s4 << std::endl;  //y h
	// 如果此时不显示给最后一个参数,将会使用缺省值npos
	std::string s5(s2, 5);   // size_t npos = -1;
	std::cout << "s5: " << s5 << std::endl;  //y hello
	// 如果此时给最后一个参数,传递了一个很大的值(从pos位置超过了字符串的结尾),那么此时字符串有多长拷多长
	std::string s6(s2, 5, 20);
	std::cout << "s6: " << s6 << std::endl; //y hello

	// from buffer
	// 拷贝一个字符串前n个字符
	std::string s7("cowsay hello", 5);
	std::cout << "s7: " << s7 << std::endl; //cowsa

	// fill
	std::string s8(10, 'x'); // 实例化一个n个同字符组成的字符串
	std::cout << "s8: " << s8 << std::endl;  //xxxxxxxxxx

	// range
	// 利用一个对象的迭代器实例化一个对象
	std::string s9(s2.begin(), s2.end());
	std::cout << "s19: " << s9 << std::endl; //cowsay hello

	// 最后再补充一点
	std::string s10 = "cowsay world";   //在这里实际上是 构造 + 拷贝构造 然后 被编译器优化成了 直接构造
	std::cout << "s10: " << s10 << std::endl;  //cowsay world

	//  initializer list  
	std::string s11 = { 'a', 'b', 'c', 'd' };  
	std::cout << "s11: " << s11 << std::endl; // abcd

	// move 
	std::string&& s12 = std::move(s11);   
	std::cout << "s12: " << s11 << std::endl; // abcd

}

现象如下: 

2.2. C++ 11 的 string::operator= 

C++11 的 string 的 operator= 具体如下:

// string (1)	
string& operator= (const string& str);

// c-string (2)	
string& operator= (const char* s);

// character (3)	
string& operator= (char c);

// initializer list (4)
string& operator= (initializer_list<char> il);

// move (5)
string& operator= (string&& str) noexcept;

测试用例如下: 

void Test2(void)
{
	// std::string::operator= 
	// string(1)
	std::string s1 = "cowsay hello";
	std::string s2 = "cowsay world";
	std::cout << "s1: " << s1 << std::endl;
	std::cout << "s2: " << s2 << std::endl;
	std::cout << "---------------------------------" << std::endl; 

	s1 = s2;
	std::cout << "s1: " << s1 << std::endl;
	std::cout << "s2: " << s2 << std::endl;
	std::cout << "---------------------------------" << std::endl;

	// c-string(2)   一个字符串赋值
	s2 = "hello world";
	s1 = s2;
	std::cout << "s1: " << s1 << std::endl;
	std::cout << "s2: " << s2 << std::endl;
	std::cout << "---------------------------------" << std::endl;

	// character (3) 一个字符赋值
	s1 = 'a';
	std::cout << "s1: " << s1 << std::endl;
	std::cout << "---------------------------------" << std::endl;

	// initializer list (4)  初始化列表
	s1 = { 'a', 'b', 'c', 'd' };
	std::cout << "s1: " << s1 << std::endl;
	std::cout << "---------------------------------" << std::endl;

	// move (5)  移动赋值
	s1 = std::move(s2);
	std::cout << "s1: " << s1 << std::endl;
	std::cout << "---------------------------------" << std::endl;
}

现象如下:

2.3. element access

2.3.1. operator[]

如果要遍历一个 string 对象,该如何做呢?

通过 std::string::operator[]:

//std::string::operator[]

char& operator[] (size_t pos);   
const char& operator[] (size_t pos) const;

测试用例: 

void Test3(void)
{
	string s("cowsay hello");
	//遍历
	for (size_t i = 0; i < s.size(); ++i)
	{
		cout << s[i];
	}
	cout << endl;
}

如果我想改这个 string 对象中的元素,也可以这样做:

void Test3(void)
{
	std::string s("cowsay hello");
	//遍历
	for (size_t i = 0; i < s.size(); ++i)
	{
		++s[i];  //修改
		std::cout << s[i];
	}
	std::cout << std::endl;
}

之所以可以这样,是因为此时是引用返回,并且没有加const,可读可写; 

如果是一个const string对象,理论上是不可以修改的: 

 const 对象只有读权限,没有写权限; 

const string s("cowsay world");
for (size_t i = 0; i < s.size(); ++i)
{
	cout << s[i];  //const对象只有读权限
}

operator[] 可以让 string 对象向数组一样操作,那么会不会存在越界访问的情况呢? 如下:

void Test4(void)
{
	std::string s("haha");
	std::cout << s[10] /* 越界访问 */ << std::endl;
}

现象如下:

可以清楚的看到, 在访问 string 对象时,如果存在越界访问,会导致进程挂掉 (assert)。

2.3.2. at

at 是 string 类的一个成员函数,而 opeartor[] 是一个运算符重载的成员函数,它们的作用和用法几乎一样,只不过operator[] 失败是断言检查 (assert),at 失败是抛异常;

//std::string::at

char& at(size_t pos);
const char& at(size_t pos) const;

证明:at 失败会抛异常,测试用例如下:

void Test4(void)
{
	std::string s("haha");
	s.at(10) = 'x';  // 越界访问
}

int main()
{
	try
	{
		Test4();
	}
	catch (const std::exception& e)
	{
		std::cout << e.what() << std::endl;
	}
	return 0;
}

现象如下:

可以看到, std::string::at 失败会抛异常。 

这里有一道 string 练习题 (仅仅反转字母):  https://leetcode.cn/problems/reverse-only-letters/solution/

代码如下:

class Solution {
public:
    bool is_letter(const char& c) const
    {
        if((c >= 'A' && c <= 'Z')
        || (c >= 'a' && c <= 'z'))
        return true;
        else
        return false;
    }
    string reverseOnlyLetters(string s) {
        size_t left = 0;
        size_t right = s.size() - 1;
        while(left < right)
        {
            while(left < right && !is_letter(s[left]))
                ++left;
            while(left < right && !is_letter(s.at(right)))
                --right;
            swap(s[left++],s.at(right--));
        }
        return s;
    }
};

2.4. iterator

2.4.1. begin() and end()

//begin是第一个有效元素的位置
iterator begin();
const_iterator begin() const;
//end是最后一个有效元素位置的下一个位置
iterator end();
const_iterator end() const;

我们知道, string 和 vector<T> 这种类所实例化的对象中的元素所在的地址本质是连续的,即是一段连续的空间,因此,这种类,一般情况下,迭代器就是原生指针。

用户可以通过迭代器访问 string 对象中的各个元素,示例如下:

void Test5()
{
	std::string s = "cowsay hello";
	//利用迭代器遍历string实例化的对象
	std::string::iterator it = s.begin();  //begin 是第一个element的位置
	while (it != s.end())    //end是最后一个有效element下一个的位置,在这里就是'\0'
	{
		std::cout << *it;
		++it;
	}
	std::cout << std::endl;
}

现象如下: 

如果是const string 对象,那么所使用的迭代器就是 const_iterator,此时只能读,不能写,示例如下:

void Test6(void)
{
	const std::string s("haha");
	std::string::const_iterator cit = s.begin();
	while (cit != s.end())
	{
		std::cout << *cit;
		++cit;
	}
	std::cout << std::endl;
}

现象如下: 

迭代器是所有容器通用的访问方式,用法十分类似,用户需要重视,而在以前的学习中,我们知道C++有一个语法,即范围for,事实上,在底层实现,范围for就是通过迭代器实现的。

在这里回顾一下范围for的使用:

void Test7()
{
	std::string s = "cowsay hello";

	// 范围for: a.自动迭代  b.自动判断结束 
	// 如果想在范围for里面进行写操作,需要加上引用 for(auto& e : s)
	for (auto e : s)
	{
		std::cout << e;
	}
	std::cout << std::endl;
}

现象如下: 

我们也可以通过汇编验证范围for的底层是否是通过迭代器实现的呢? 验证如下:

可以清晰的看到,范围for底层的实现本质就是通过迭代器和相关操作 (operator++、operator!=) 来实现的。

2.4.2. rbegin() and rend()

// rbegin 是最后一个有效元素的位置
iterator rbegin();
const_reverse_iterator rbegin() const;
// rend 是第一个有效元素位置的前一个位置
iterator rend();
const_reverse_iterator rend() const;

测试用例如下: 

void Test9()
{
	std::string s("abcdef");
	//std::string::reverse_iterator rit = s.rbegin(); //这样写太麻烦了,可以这样写
	auto rit = s.rbegin();
	while (rit != s.rend())
	{
		std::cout << *rit;
		++rit;
	}
	std::cout << std::endl;
}

现象如下: 

 

string 也会存在const 反向迭代器,使用如下:

void Test10()
{
	const std::string s("cowsay world");
	std::string::const_reverse_iterator crit = s.crbegin();
	while (crit != s.crend())
	{
		std::cout << *crit;
		++crit;
	}
	std::cout << std::endl;
}

现象如下:

总结:对于 std::string 来说,我们一般很少使用迭代器,因为 operator[] 更好用、更方便;但是迭代器 iterator 是所有容器的通用访问方式,用法类似,因此也很重要。

2.4. Modifiers

2.4.1. push_back

// std::string::push_back

void push_back (char c);

std::string::push_back 只支持一次插入一个字符,示例如下:

void Test11(void)
{
	std::string s;
	s.push_back('a');
	s.push_back('b');
	s.push_back('c');
	s.push_back('d');

	for (const auto& it : s)
	{
		std::cout << it;
	}
	std::cout << std::endl;
}

现象如下: 

2.4.2. append

// string (1)	
string& append(const string& str);
// substring (2)	
string& append(const string& str, size_t subpos, size_t sublen);
// c-string (3)	
string& append(const char* s);
// buffer (4)	
string& append(const char* s, size_t n);
// fill (5)	
string& append(size_t n, char c);
// range (6)	
template <class InputIterator>
string& append(InputIterator first, InputIterator last);
void Test9(void)
{
	std::string s1("cowsay");
	std::string s2("hello");
	std::cout << s1 << std::endl;
	std::cout << s2 << std::endl;

	//string(1):
	//追加一个string实例化的对象
	s1.append(s2);
	std::cout << s1 << std::endl;

	//substring(2):
	//从s2这个对象的下标为2的位置上进行拷贝,因为第三个参数为-1,即拷贝到结尾
	s1.append(s2, 2, -1);
	std::cout << s1 << std::endl;

	//如果第三个参数很大,那么就会一直拷贝到结尾
	s1.append(s2, 2, 20);
	std::cout << s1 << std::endl;

	//如果第二个参数超过了 is copied 的对象结尾,那么就会 try catch ,
	//在这里就会抛异常 /* invalid string position */
	s1.append(s2, 6, 10);
	std::cout << s1 << std::endl;

	//c-string (3):	 
	//追加一个字符串
	s1.append("haha");
	std::cout << s1 << std::endl;	

	//buffer (4):
	//追加字符串的前n个字符
	s1.append("hehe", 2);
	std::cout << s1 << std::endl;

	//fill (5):
	//追加n个相同的字符
	s1.append(10, 'A');
	std::cout << s1 << std::endl;

	//range (6):
	//利用迭代器进行追加
	s1.append(s2.begin(), s2.end());
	std::cout << s1 << std::endl;
}

2.4.3. operator+=

// string (1)	
string& operator+= (const string& str);
// c-string (2)	
string& operator+= (const char* s);
// character (3)	
string& operator+= (char c);
void Test10(void)
{
	string s1("hello");
	string s2("world");

    //string (1):
    // +=一个string实例化的对象
	s1 += s2; 
	cout << s1 << endl;

    //c-string (2):
    // +=一个字符串
    s1 += "haha";
    cout << s1 << endl;

    //character (3)
    // +=一个字符
    s1 += 'X';
    cout << s1 << endl;
}

在底层层面,operator+= 底层就是调用的是 append() 和 push_back();

2.4.4. assign

Assigns a new value to the string, replacing it's current contents.

//string (1)	
string& assign (const string& str);

//substring (2)	
string& assign (const string& str, size_t subpos, size_t sublen);

//c-string (3)	
string& assign (const char* s);

//buffer (4)	
string& assign (const char* s, size_t n);

//fill (5)	
string& assign (size_t n, char c);

//range (6)	
template <class InputIterator>
string& assign (InputIterator first, InputIterator last);
void Test1(void)
{
	//assign
	string s1("cowsay hello");
	string s2("cowsay world");
	cout << "s1 =  " << s1 << endl << "s2 =  " << s2 << endl;
	/*
	*	s1 =  cowsay hello
	*	s2 =  cowsay world
	*/
	s1.assign(s2); 
	cout << "s1 =  " << s1 << endl << "s2 =  " << s2 << endl;
	/*
	*	s1 =  cowsay world
	*	s2 =  cowsay world
	*/
    //assign的作用相当于赋值
}

2.4.5. insert

在指定的pos(或者p)位置之前,插入字符串(或者字符)或者string对象

//string (1)	
string& insert (size_t pos, const string& str);

//substring (2)	
string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);

//c-string (3)	
string& insert (size_t pos, const char* s);

//buffer (4)	
string& insert (size_t pos, const char* s, size_t n);

//fill (5)	
string& insert (size_t pos, size_t n, char c);
void insert (iterator p, size_t n, char c);

//single character (6)	
iterator insert (iterator p, char c);

//range (7)	
template <class InputIterator>
void insert (iterator p, InputIterator first, InputIterator last);

2.4.6. erase

删除字符串的一部分

//sequence (1)	
string& erase (size_t pos = 0, size_t len = npos);

//character (2)	
iterator erase (iterator p);

//range (3)	
iterator erase (iterator first, iterator last);

2.5. string实例化对象的扩容机制

首先看一下,string 对象是如何扩容的:

void Test11(void)
{
	std::string s;
	size_t my_capacity = s.capacity();
	for (size_t i = 0; i < 1000; ++i)
	{
		if (my_capacity != s.capacity())
		{
			cout << "old_capacity = " << my_capacity << "--->" << "new_capacity = " << s.capacity() << endl;
			my_capacity = s.capacity();
		}
		s.push_back('x');
	}

}

运行结果:

old_capacity = 15--->new_capacity = 31
old_capacity = 31--->new_capacity = 47
old_capacity = 47--->new_capacity = 70
old_capacity = 70--->new_capacity = 105
old_capacity = 105--->new_capacity = 157
old_capacity = 157--->new_capacity = 235
old_capacity = 235--->new_capacity = 352
old_capacity = 352--->new_capacity = 528
old_capacity = 528--->new_capacity = 792
old_capacity = 792--->new_capacity = 1188

 在vs2013的环境下,string实例化的对象扩容机制:按照1.5倍的方式进行扩容;

相同的代码,在g++ 编译器下,string 实例化的对象扩容机制:按照2倍的方式进行扩容;

虽然二者扩容机制稍有差异,但是如果一个对象已经知道需要开多少空间了,我们可不可以提前把空间开好,避免了前期的频繁扩容呢? 当然,STL考虑到了这一点;  

2.5.1. reserve

//std::string::reserve

void reserve (size_t n = 0);

预先开好n个空间,只有capacity会发生变化,其size是不发生变化的;

void Test11(void)
{
	std::string s;
	s.reserve(1000);  //预先开好空间
	size_t my_capacity = s.capacity();
	for (size_t i = 0; i < 1000; ++i)
	{
		if (my_capacity != s.capacity())
		{
			cout << "old_capacity = " << my_capacity << "--->" << "new_capacity = " << s.capacity() << endl;
			my_capacity = s.capacity();
		}
		s.push_back('x');
	}
}

在vs2013的环境下,现象如下:

在g++的环境下,现象如下: 

不论是vs2013还是Linux环境下,在用户已经知道需要多少空间时,reserve 都可以在一定程度上减少前期频繁扩容的问题;

2.5.2. resize 

std::string::resize

void resize (size_t n);
void resize (size_t n, char c);

预先开好n个空间,并初始化,如果不显式初始化,那么resize默认的初始化值是0,并且此时capacity和size都会更新;

此时如果不显示初始化,默认值是0;

如果我们显示初始化了,那么值就是我们显式定义的;

2.6. string operations

2.6.1. c_str

用于返回一个以空字符结尾的 C 风格字符串(即以 '\0' 结尾的字符数组)

//std::string::c_str

const char* c_str() const;

通常用于将 std::string 对象转换为 C 风格字符串进行字符串处理或与 C 风格字符串相关的 API 进行交互。

void Test4(void)
{
	std::string s1("cowsay hehe");
	cout << s1 << endl;
	cout << s1.c_str() << endl;
	s1 += '\0';
	s1 += "i am a superman";
	cout << s1 << endl;
	cout << s1.c_str() << endl;
}

运行结果:

cowsay hehe
cowsay hehe
cowsay hehe i am a superman
cowsay hehe

我们可以看到,二者差异的起因是因为中间插入了一个 '\0',c_str()是以 '\0' 作为结束标识符的,而string自己重载的operator<<是以_size作为结束的,它不受'\0'影响;

2.6.2. find and substr

// string (1)	
size_t find (const string& str, size_t pos = 0) const;
// c-string (2)	
size_t find (const char* s, size_t pos = 0) const;
// buffer (3)	
size_t find (const char* s, size_t pos, size_t n) const;
// character (4)	
size_t find (char c, size_t pos = 0) const;

return:如果找到了对应的string对象/字符串/字符,返回对应的位置;没找到返回string::npos;

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

substr从 pos 到 pos + len(默认到string对象的结尾)构造一个新的对象并返回;

构造对象的范围:[pos,pos + len)

如何得到一个文件后缀:

void Test5(void)
{
	string s("Test.cpp");
	//如何得到该文件的后缀?
	size_t pos = s.find('c');
    if(pos != string::npos)
    {
        string ret = s.substr(pos);
	    cout << ret << endl;
    }	
}

但有时候呢,有的文件后缀是这样的

如果我们继续用find这个成员函数,可能就不符合我们的需求了,因此std::string里面也提供了rfind;

string s("Test.cpp.tar.zip");
size_t pos = s.rfind('.');
if (pos != string::npos)
{
	string ret = s.substr(pos);
	cout << ret << endl;
}

rfind()和find的区别:前者是从后往前找,后者从前往后找;

如何解析一个URL (得到协议、域名、资源路径)

void Test5(void)
{        
    string s("https://legacy.cplusplus.com/reference/string/string/find/");
	size_t pos1 = s.find("://");
	if (pos1 == string::npos)
	{
		printf("Protocol error");
		exit(1);
	}
	else
	{
		//协议
		string protocol = s.substr(0,pos1+3);  
		cout << protocol << endl;
	}
	size_t pos2 = s.find('/', pos1 + 3);
	if (pos2 == string::npos)
	{
		printf("Domain error");
		exit(1);
	}
	else
	{
		//域名
		string domain = s.substr(pos1 + 3, pos2 - pos1 - 3);
		cout << domain << endl;
	}
	//路径
	string path = s.substr(pos2);
	cout << path << endl;
}

现象如下:

sdt::string::find_first_of

用于在字符串中查找第一个匹配指定字符集合中任意字符的位置。

//string (1)	
size_t find_first_of (const string& str, size_t pos = 0) const;
//c-string (2)	
size_t find_first_of (const char* s, size_t pos = 0) const;
//buffer (3)	
size_t find_first_of (const char* s, size_t pos, size_t n) const;
//character (4)	
size_t find_first_of (char c, size_t pos = 0) const;

理解:

该函数用于执行字符级的搜索和匹配操作。它会从指定位置开始逐个检查字符串中的字符,如果遇到指定字符集合中的任何字符,就立即返回该字符在字符串中的位置。如果没找到,搜索会一直进行,直到遍历完整个字符串或找到第一个匹配字符为止。

void Test6(void)
{
	string s = "cowsay hehe";
	size_t pos1 = s.find_first_of('w');
	size_t pos2 = s.find_first_of("x");
	cout << s[pos1] << endl;   //正常打印
	cout << s.at(pos2) << endl;  //抛异常
}

运行结果:

w
invalid string position

find_first_of是从起始位置向结束位置遍历,find_last_of与之相反; 

find_first_not_of 接口如下:

//string (1)
size_t find_first_not_of (const string& str, size_t pos = 0) const;
//c-string (2)	
size_t find_first_not_of (const char* s, size_t pos = 0) const;
//buffer (3)	
size_t find_first_not_of (const char* s, size_t pos, size_t n) const;
//character (4)	
size_t find_first_not_of (char c, size_t pos = 0) const;

该函数的作用是,从起始向结束位置遍历,找第一个与之不匹配的string对象/字符串/字符,找到了就返回对应位置,没找到返回string::npos;

void Test7(void)
{
	string s = "cowsay world";
	size_t pos1 = s.find_first_not_of('w');  //找第一个不是这个string对象/字符串/字符的位置
	size_t pos2 = s.find_first_not_of('c');
	cout << s[pos1] << endl;
	cout << s[pos2] << endl;
}

运行结果:

c
o

find_first_not_of是从起始位置向结束位置遍历,find_last_not_of与之相反;

2.7. Non-member function overloads

2.7.1. getline

指的是与 std::string 相关的非成员函数,在C++中也称为自由函数或全局函数

//std::getline (string)
istream& getline (istream& is, string& str, char delim);
istream& getline (istream& is, string& str);

参数:

  • is:输入流,可以是 std::cin(标准输入)或其他输入流对象;
  • str:存储读取文本的目标字符串;
  • delim:可选参数,用于指定行分隔符,默认为换行符 '\n'。

返回值:

  • 输入流 is 的引用

功能:

  • 该函数会从输入流中读取字符,直到遇到行分隔符(默认为换行符),或者到达流的末尾。读取的字符会保存到目标字符串 str 中,包括行分隔符(如果存在)。

测试实例:

void Test9()
{
	string s;
	std::cin >> s;  //遇到空格/换行终止
	cout << s << endl;
}

结果:

hehe haha
hehe

void Test9()
{
	string s;
	getline(std::cin, s);   //遇到换行/到达流结尾终止
	cout << s << endl;
}

结果:

hehe haha
hehe haha 

2.7.2. to_string

std::to_string 是一个全局函数,用于将整数、浮点数等基本数据类型转换为对应的字符串表示形式。

下面是它的具体函数声明:

string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);

参数:

  • val:要转化为字符串的值;

返回值:

  • 该函数返回转换后的字符串;

示例:

void Test10(void)
{
	int i_val;
	double d_val;
	std::cin >> i_val >> d_val;
	string i_str = std::to_string(i_val);
	string d_str = std::to_string(d_val);
	cout << i_str << endl << d_str << endl;
}

输入

10
11.1

输出
10
11.100000

2.7.3. 字符串转化成对应的数字类型:

具体如下:

这里以 stoi 举例: 

//std::stoi
int stoi (const string&  str, size_t* idx = 0, int base = 10);

std::stoi 是 C++ 标准库中的一个函数,用于将字符串转换为对应的整数值。

参数介绍:

  • str:要转换的字符串;
  • pos:可选参数,指向一个对象的指针,用于存储转换结束后的下一个字符的位置。如果不提供该参数,或者该参数为 0,表示不需要存储位置信息;
  • base:可选参数,指定字符串中的数字的基数,默认为 10。

示例:

void Test11()
{
	string i_str;
	std::cin >> i_str;
	int i_val = std::stoi(i_str);
	cout << i_val << endl;
}

输入

20

输出
20

有了上面的理解,我们需要模拟实现一下 string,详细请看,string 的模拟实现-CSDN博客

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值