在C语言中,字符串表示为字符的数组。字符串中的最后一个字符是空字符(\0’) C++包含一些来自C语言的字符串操作函数,它们在< cstring >头文件中定义。
函数名称说明strlen()返回字符串长度,不包含空字符‘\0’的一字节,字符串长度不等于字符个数strcpy()字符串拷贝C和C++中的sizeof操作符可用于获得给定数据类型或变量的大小。例如,sizeof(char)返回1, 因为char的大小是1字节。但是,在C风格的字符串中,sizeof()和strlen()是不同的。绝对不要通过 sizeof()获得字符串的大小。如果C风格的字符串存储为char[],则sizeof()返回字符串使用的实际内存,包括‘\0’字符。例如:
char text[]= "abcdef"; size_t s1= sizeof(text); // is 7 size_t s2 = strlen(text); // is 6但是,如果C风格的字符串存储为char*, sizeof()就返回指针的大小!例如:
const char* text2 = "abcdef"; size_t s3 = sizeof(text2); // is platform-dependent size_t s4 = strlen(text2); // is 6在32位模式编译时,s3的值为4,而在64位编译时,s3的值为8,因为这返回的是指针const char* 的大小。可在<cstring>头文件中找到操作字符串的C函数的完整列表。
在Microsoft Visual Studio中使用C风格的字符串函数时,编译器可能会给 出安全相关的警告甚或错误,说明这些函数已经被废弃了。使用其他C标准库函数可以避免这些警告,例如 strcpy_s()和strcat_s(),这些函数是“安全C库” (ISO/IEC TR 24731)标准的一部分。然而,最好的解决方案是切换到C++的 string 类。
注意,C++程序中编写的字符串要用引号包围。例如,下面的代码输出字符串"hello",这段代码 包含这个字符串本身,而不是一个包含这个字符串的变量:
cout <<"hello" << endl;在上面的代码中,"hello”是一个字符串字面量(string literal),因为这个字符串以值的形式写出, 而不是一个变量。与字符串字面量关联的真正内存在内存的只读部分中。通过这种方式,编译器可 以重用等价字符串字面量的引用,来优化内存的使用。也就是说,即使一个程序使用了 500次"hello"字符串字面量,编译器也只在内存中创建一个hello实例。这种技术称为字面量池 (literal pooling)。 字符串字面量可以赋值给变量,但因为字符串字面量位于内存的只读部分,且使用了字面量池, 所以这样做会产生风险。C++标准正式指出:字符串字面量的类型为“n个const char的数组”,然而为了向后兼容较老的不支持const的代码,大部分编译器不会强制程序将字符串字面量赋值给 const char类型的变量。这些编译器允许将字符串赋值给不带有const的char,而且整个程序可以 正常运行,除非试图修改字符串。一般情况下,试图修改字符串的行为是没有定义的。它可能会导 致程序崩溃;可能使程序继续执行,看起来没有什么莫名其妙的副作用;可能不加通告地忽略修改 行为;可能修改行为是有效的,这完全取决于编译器。例如,下面的代码展示了未定义的行为:
char* ptr = "hello"; // Assign the string literal to a variable. ptr[1] = 'a '; // Undefined behavior!一种更安全的编码方法是在引用字符串常量时,使用指向 const 字符的指针。下面的代码包含 同样的 bug,但由于这段代码将字符串字面量赋值给 const char* 所以编译器会捕捉到任何写入只 读内存的企图。
const char* ptr = "hello"; // Assign the string literal to a variable. ptr[ 1] = 'a'; // Error! Attempts to write to read-only memory还可以将字符串字面量用作字符数组(char®的初始值。这种情况下,编译器会创建一个足以放 下这个字符串的数组,然后将字符串复制到这个数组。因此,编译器不会将字面量放在只读的内存中,也不会进行字面量的池操作。
char arr [] = "hello"; // Compiler takes care of creating appropriate sized // character array arr. arr[ 1] = 'a '; // The contents can be modified.C++提供了一个得到极大改善的字符串概念,并作为标准库的一部分提供了这个字符串的实现。 在C++中,std::string是一个类(实际上是basic string模板类的一个实例),这个类支持 <cstring >中提 供的许多功能,还能自动管理内存分配。string类在std名称空间的< string >头文件中定义。
尽管string是一个类,但是几乎总是可以把string当做内建类型使用。事实上,把string想象为 简单类型更容易发挥string的作用。通过运算符重载的神奇作用,C++的string使用起来比C字符串容易得多。
源代码中的字符串字面量通常解释为const char*。使用用户定义的标准字面量”s”可以把字符串 字面量解释为std::string。例如:
auto stringl = "Hello World"; // stringl will be a const char* auto string2 = "Hello World"s; // string2 will be an std::stringint stoi(const string& str, size_t *idx=0, int base=10)
stoi将n进制字符串转为十进制,第二个参数是字符串起始位置,第三个参数表示n进制
也可以直接用重载的 int stoi(const string& str),默认字符串为十进制,起始位置为0,制
#include<string> #include <iostream> #include <exception> using namespace std; int main() { int i=0; try { i = stoi("FEEF", 0, 16); //int i = stoi("我的"); 输入非法时,可以捕获异常"invalid stoi argument" } catch (exception e) { cout << e.what() << endl; } system("pause"); return 0; }输出结果:
转十进制可以用to_string,但是低版本的编译器可能不支持
转多进制可以用_itoa_s,但似乎没有安全机制,导致无法捕获异常
char cstr[20]; _itoa_s(100,cstr,2); cout << cstr << endl;转多进制还可以用 stringstream
#include<string> #include <iostream> #include <sstream> #include <bitset> using namespace std; int main() { int num = 1234; stringstream stream; //转二进制 stream << bitset<16>(num); cout << stream.str() <<endl; stream.str(""); //清空缓存,如果注释掉,那么会输出所有的历史结果 //转8进制 stream << oct << num; cout << stream.str() << endl; stream.str(""); //转十六进制 stream << hex << num; cout << stream.str() << endl; stream.str(""); system("pause"); return 0; }结果:
如果需要把格式化后的字符串通过>>输出到字符串, 必须每次都调用clear()方法
原始字符串字面量(raw string literal)是可以横跨多行代码的字符串字面量,不需要转义嵌入的双引号,像\t和\1!这种转义序列不按照转义序列的方式处理,而是按照普通文本的方式处理。如果像下面这样编写普通的字符串字面量,那么会收到一个编译器错误,因为 字符串包含了未转义的引号:
string str = "Hello "World"!// Error!对于普通的字符串,必须转义双引号,如下所示:
string str = "Hello \"World\"!";对于原始字符串字面量,就不需要转义引号了。 原始字符串字面量的写法:
string str = R"(Hello "World"!)";原始字符串字面量可以跨越多行代码。例如,如果像下面这样编写普通的字符串字面量,那么会收到一个编译器错误,因为普通的字符串字面量不能跨越多行:
string str = "Line 1 Line 2 with \t"; // Error!可使用如下原始字符串字面量来替代:
string str = R"(Line 1 Line 2 with \t)";这也说明,使用原始字符串字面量时,\t转义字符没有替换为实际的制表符字符,而是按照字面形式保存。将str写入控制台得到的输出如下所示: Line 1 Line 2 with \t 因为原始字符串字面量以)“结尾,所以使用这个语法时,不能在字符串中嵌入)”。例如,下面的 字符串是不合法的,因为在这个字符串中间包含了一个)”:
string str = R"(The characters )"n are embedded in this string)" // Error!如果需要嵌入)",则需要使用扩展的原始字符串字面量语法,如下所示:
R"d-char-sequence(r-char-sequence)d-char-sequence"r-char-sequence是实际的原始字符串。d-char-sequence是可选的分隔符序列,原始字符串首尾的分隔符序列应该一致。分隔符序列最多能有16个字符。应选择未出现在原始字符串字面量中的序列作为分隔符序列。上面的例子可以改用唯一的分隔符序列:
string str = R"-(The characters )" are embedded in this string)-";在操作数据库查询字符串和正则表达式等字符串时,原始字符串字面量可以令程序的编写更加方便。