字符串


C 风格字符串

C 风格字符串就是以空字符 \0 结尾的字符数组。

操作风格字符串函数定义在 头文件中。

常见的操作:

操作 解释
strlen(p) 返回p的长度,空字符不计算在内。
strcmp(p1, p2) 比较p1p2的相等性:
如果p1==p2,返回0;
如果p1>p2,返回一个正值;
如果p1,返回一个负值。
strcat(p1, p2) p2附加到p1之后,返回p1
strcpy(p1, p2) p2拷贝给p1,返回p1
  • 传入此类函数的指针必须指向以空字符作为结尾的数组,否则行为是未定义的。
  • strcatstrcpy 都需要程序员保证内存不会溢出,否则行为将是未定义的。

字符串字面量

字面量池

与字符串字面量关联的内存位于内存的只读部分,通过这种方式,编译器可以重用等价字符串字面量的引用,从而优化内存的使用,这种技术称为字面量池。

字符串字面值赋值给变量,不能通过变量修改字符串字面量,这将产生未定义的行为,通常在引用字符串常量时,使用 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_sequencesuffix_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) s2s1的副本。
string s2 = s1 等价于s2(s1)s2s1的副本。
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 返回s1s2连接后的结果。
s1=s2 s2的副本代替s1中原来的字符。
s1==s2 如果s1s2中所含的字符完全一样,则它们相等;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::errcptr 指向被写入字符尾后一位置的指针。
    • 错误时:ec 的值为 std::errc::value_too_largeptr 的值为 last
    std::array str;
    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 指向首个不匹配的模式的字符,若所有字符都匹配则指向 lastec 被值初始化。
    • 若无可匹配模式:ec 的值为 std::errc::invalid_argumentptr 的值为 first,不修改 value
    • 若模式匹配,但是分析值不在 value 类型表示范围内:ec 的值为 std::errc::out_of_rangeptr 指向首个不匹配模式的字符,不修改 value
    std::array str{"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;