字符串
C 风格字符串
C 风格字符串就是以空字符 \0 结尾的字符数组。
操作风格字符串函数定义在 头文件中。
常见的操作:
| 操作 | 解释 |
|---|---|
strlen(p) |
返回p的长度,空字符不计算在内。 |
strcmp(p1, p2) |
比较p1和p2的相等性:如果 p1==p2,返回0;如果 p1>p2,返回一个正值;如果 p1 |
strcat(p1, p2) |
将p2附加到p1之后,返回p1。 |
strcpy(p1, p2) |
将p2拷贝给p1,返回p1。 |
- 传入此类函数的指针必须指向以空字符作为结尾的数组,否则行为是未定义的。
strcat和strcpy都需要程序员保证内存不会溢出,否则行为将是未定义的。
字符串字面量
字面量池
与字符串字面量关联的内存位于内存的只读部分,通过这种方式,编译器可以重用等价字符串字面量的引用,从而优化内存的使用,这种技术称为字面量池。
字符串字面值赋值给变量,不能通过变量修改字符串字面量,这将产生未定义的行为,通常在引用字符串常量时,使用 const char*:
char* ptr = "hello"; //@ 字符串字面量赋值给变量
ptr[0] = 'H'; //@ 未定义的行为
const char* cptr = "hello";
字符串字面值初始化字符数组,此时编译器会创建一个足够能容下这个字符串的数组,然后将字符串复制给这个数组,此时编译器不会将字面量放在只读内存中,也不会进行字面量池操作:
char arr[] = "hello"; //@ 字符串字面量初始化字符数组
ptr[0] = 'H'; //@ 可以修改
原始字符串字面量
原始字符串字面量形式:
R"( ...string... )"
例如:
const char* str = R"(hello,"World")";
const char* str2 = R"(Line1
Line2
)";
如果要在字符串中嵌入 )" 则需要扩展原始字符串字面量语法:
R"prefix_sequence( ...string... )suffix_sequence"
这里 prefix_sequence 和 suffix_sequence 是可选的分隔序列,必须一致,最多 16 个字符。
const char* str = R"-((Embed))-";
cctype
cctype 头文件中定义了一组函数:
| 操作 | 解释 |
|---|---|
isalnum(c) |
当c是字母或数字时为真。 |
isalpha(c) |
当c是字母时为真。 |
iscntrl(c) |
当c是控制字符时为真。 |
isdigit(c) |
当c是数字时为真。 |
isgraph(c) |
当c不是空格但可以打印时为真。 |
islower(c) |
当c是小写字母时为真。 |
isprint(c) |
当c是可打印字符时为真。 |
ispunct(c) |
当c是标点符号时为真。 |
isspace(c) |
当c是空白时为真(空格、横向制表符、纵向制表符、回车符、换行符、进纸符)。 |
isupper(c) |
当c是大写字母时为真。 |
isxdigit(c) |
当c是十六进制数字时为真。 |
tolower(c) |
当c是大写字母,输出对应的小写字母;否则原样输出c。 |
toupper(c) |
当c是小写字母,输出对应的大写字母;否则原样输出c。 |
string
string 表示可变长度的字符串。string 类型包含在 头文件中。实际上是 basic_string 模板类的一个实例。
定义和初始化 string 对象
| 操作 | 解释 |
|---|---|
string s1 |
默认初始化,s1是个空字符串。 |
string s2(s1) |
s2是s1的副本。 |
string s2 = s1 |
等价于s2(s1),s2是s1的副本。 |
string s3("value") |
s3是字面值“value”的副本,除了字面值最后的那个空字符。 |
string s3 = "value" |
等价于s3("value"),s3是字面值"value"的副本。 |
string s4(n, 'c') |
把s4初始化为由连续n个字符c组成的串。 |
string 对象上的操作
| 操作 | 解释 |
|---|---|
os << s |
将s写到输出流os当中,返回os。 |
is >> s |
从is中读取字符串赋给s,字符串以空白分割,返回is。 |
getline(is, s) |
从is中读取一行赋给s,返回is。读取一整行,包括空白符。 |
s.empty() |
s为空返回true,否则返回false。 |
s.size() |
返回s中字符的个数。返回的类型是 string::size_type |
s[n] |
返回s中第n个字符的引用,位置n从0计起。 |
s1+s2 |
返回s1和s2连接后的结果。 |
s1=s2 |
用s2的副本代替s1中原来的字符。 |
s1==s2 |
如果s1和s2中所含的字符完全一样,则它们相等;string对象的相等性判断对字母的大小写敏感。 |
s1!=s2 |
同上。 |
<, <=, >, >= |
利用字符在字典中的顺序进行比较,且对字母的大小写敏感。 |
c_str() |
返回 C 风格字符串 const char*。但是一旦 string 对象执行任何内存重分配或 string 对象被销毁了,返回的这个指针就失效了。 |
data() |
C++14 及以前版本返回 const char*,C++ 17 以后在非 const 字符串上调用时,返回 char*。 |
string 字面量
源代码中字符串字面量通常解释为 const char*,添加 s 后缀可以把字符串字面量解释为 string :
auto string1 = "hello"; //@ string1 类型是 const char*
auto string2 = "hello"s; //@ string2 类型是 string
数值转换函数
数值转换成字符串
std::string to_string(int value);
std::string to_string(long value);
std::string to_string(long long value);
std::string to_string(unsigned value);
std::string to_string(unsigned long value);
std::string to_string(unsigned long long value);
std::string to_string(float value);
std::string to_string(double value);
std::string to_string(long double value);
字符串转换成数值
int stoi(const std::string& str, std::size_t* pos = 0, int base = 10);
long stol(const std::string& str, std::size_t* pos = 0, int base = 10);
long long stoll(const std::string& str, std::size_t* pos = 0, int base = 10);
float stof(const std::string& str, std::size_t* pos = 0);
double stod(const std::string& str, std::size_t* pos = 0);
long double stold(const std::string& str, std::size_t* pos = 0);
unsigned long stoul(const std::string& str, std::size_t* pos = 0, int base = 10);
unsigned long long stoull(const std::string& str, std::size_t* pos = 0, int base = 10);
str是要转换的字符串,pos接受第一个未转换的字符索引,base是转换过程中使用的进制。- 如果不能执行任何转换会抛出
invalid_argument异常,如果转换的值超出类型的表示范围,抛出out_of_range异常。
低级数值转换
C++ 17 提供了一些低级数值转换函数,定义在 charconv 头文件中。这些函数不执行内存分配,由使用者分配缓冲区,与更高级的数值转换函数相比,运行速度要高几个数量级。
数值转换成字符串
std::to_chars_result to_chars(char* first, char* last,int value, int base = 10);
std::to_chars_result to_chars(char* first, char* last, float value);
std::to_chars_result to_chars(char* first, char* last, double value);
std::to_chars_result to_chars(char* first, char* last, long double value);
std::to_chars_result to_chars(char* first, char* last, float value,std::chars_format fmt);
std::to_chars_result to_chars(char* first, char* last, double value,std::chars_format fmt);
std::to_chars_result to_chars(char* first, char* last, long double value,std::chars_format fmt);
std::to_chars_result to_chars(char* first, char* last, float value,std::chars_format fmt, int precision);
std::to_chars_result to_chars(char* first, char* last, double value,std::chars_format fmt, int precision);
std::to_chars_result to_chars(char* first, char* last, long double value,std::chars_format fmt, int precision);
-
first,last:要写入的字符范围。 -
value:要转换到其字符串表示的值。 -
base:使用的整数基底: 2 与 36 间的值(含上下限)。 -
fmt:使用的浮点格式,std::chars_format类型的位掩码:enum class chars_format { scientific, fixed, hex, general = fixed | scientific }; -
precision:使用的浮点精度。 -
to_chars_result:struct to_chars_result { char* ptr; std::errc ec; };- 成功时:
ec等于初始值std::errc,ptr指向被写入字符尾后一位置的指针。 - 错误时:
ec的值为std::errc::value_too_large,ptr的值为last。
std::arraystr; if (auto [p, ec] = std::to_chars(str.data(), str.data() + str.size(), 42); ec == std::errc()) std::cout << std::string_view(str.data(),p - str.data()) << std::endl; - 成功时:
字符串转换成数值
std::from_chars_result from_chars(const char* first, const char* last,int& value, int base = 10);
std::from_chars_result from_chars(const char* first, const char* last, float& value,std::chars_format fmt = std::chars_format::general);
std::from_chars_result from_chars(const char* first, const char* last, double& value,std::chars_format fmt = std::chars_format::general);
std::from_chars_result from_chars(const char* first, const char* last, long double& value,std::chars_format fmt = std::chars_format::general);
-
from_chars不会忽略前导空白字符。 -
from_chars_result:struct from_chars_result { const char* ptr; std::errc ec; };- 成功时:
ptr指向首个不匹配的模式的字符,若所有字符都匹配则指向last,ec被值初始化。 - 若无可匹配模式:
ec的值为std::errc::invalid_argument,ptr的值为first,不修改value。 - 若模式匹配,但是分析值不在
value类型表示范围内:ec的值为std::errc::out_of_range,ptr指向首个不匹配模式的字符,不修改value。
std::arraystr{"42"}; int result; std::from_chars(str.data(), str.data() + str.size(), result); std::cout << result << std::endl; - 成功时:
string_view
C++ 17 引入了 string_view 类,string_view 类是 std::basic_string_view 类模板的实例化,定义在 中。
string_view 可以看作是 const string& 和 const char* 的替代品,它指向字符串的指针以及字符串的长度。
string_view 支持与 std::string 相似的接口:
- 缺少
c_str()但是支持data()。 - 增加了
remove_prefix(size_t)和remove_suffix(size_t)方法。
无法从 string_view 隐式构建一个 std::string :
- 要么使用显式的
std::string构造函数。 - 要么使用
string_view::data()成员函数。
string_view 字面量
在字符串字面量添加 sv 后缀会解释为 string_view 字面量。
auto sv = "hello"sv;
要使用 string_view 字面量需要:
using namespace std::string_view_literals;
//@ 或者
using namespace std;