C-style字符串、库函数 与 std::string对象
一. C - style字符串(以空字符结尾的字符数组)
1. 字符串定义与初始化
可以使用字符数组来表示C - style字符串。
char str1[] = "Hello"; char str2[6]; str2[0] = 'W'; str2[1] = 'o'; str2[2] = 'r'; str2[3] = 'l'; str2[4] = 'd'; str2[5] = '\0';
在初始化字符数组时,如果使用字符串字面量(如"Hello"),编译器会自动在末尾添加空字符'\0'。而手动初始化字符数组时,必须确保最后一个元素是'\0',否则在使用一些字符串处理函数时可能会导致问题。
2. 字符串操作库函数
C标准库提供了一些用于处理C - style字符串的函数,如strcpy(字符串复制)、strcat(字符串连接)、strcmp(字符串比较)等。这些函数定义在<string.h>头文件中。
<string.h>是 C 语言中用于字符串操作的标准头文件。在 C++中也可以使用,但 C++更推荐使用<cstring>头文件(功能与<string.h>类似,但更符合 C++的标准)。以下是<string.h>中一些常见的函数及其功能:
(1). 字符串复制函数:
strcpy(char* dest, const char* src):将 src 指向的字符串复制到 dest 所指向的字符数组中,包括字符串结束符 '\0'。使用时需确保 dest 数组有足够的空间来容纳复制的字符串,否则会导致缓冲区溢出错误。
strncpy(char* dest, const char* src, size_t n):最多从 src 字符串中复制 n 个字符到 dest 字符数组中。当 src 的长度大于等于 n 时,只复制 n 个字符;当 src 的长度小于 n 时,先复制 src 的内容,然后将剩余空间用 '\0' 填充。
#include <stdio.h> #include <string.h> int main() { char dest[20]; char src[] = "Hello, World!"; strncpy(dest, src, 5); dest[5] = '\0'; // 手动添加结束符,因为如果src长度大于等于5,strncpy不会自动添加 printf("Copied string: %s ", dest); return 0; }
(2). 字符串连接函数:
strcat(char* dest, const char* src):将 src 字符串连接到 dest 字符串的末尾,覆盖 dest 字符串末尾的 '\0',并在连接后的字符串末尾添加一个新的 '\0'。同样,要确保 dest 数组有足够的空间来容纳连接后的字符串。
#include <stdio.h> #include <string.h> int main() { char dest[10] = "Hello"; char src[] = " World"; // dest数组长度为10,已经存放了"Hello"(占6个字节,包括'\0'),没有足够空间容纳" World" strcat(dest, src); printf("The concatenated string is: %s ", dest); return 0; }
strncat(char* dest, const char* src, size_t n):最多将 src 字符串的前 n 个字符连接到 dest 字符串的末尾。如果 src 的长度小于 n,则将 src 的全部内容连接到 dest 末尾,然后在末尾添加 '\0'。
#include <stdio.h> #include <string.h> int main() { char dest[30] = "Hello"; char src[] = " World"; strncat(dest, src, 5); printf("Concatenated string: %s ", dest); return 0; }
(3). 字符串比较函数:
strcmp(const char* s1, const char* s2):比较 s1 和 s2 两个字符串的大小。按照字典序逐个比较字符的 ASCII 值,直到找到不同的字符或者到达字符串末尾。如果 s1 小于 s2,返回一个负整数;如果 s1 等于 s2,返回 0;如果 s1 大于 s2,返回一个正整数。
#include <stdio.h> #include <string.h> int main() { char s1[] = "abc"; char s2[] = "abd"; int result = strcmp(s1, s2); if (result < 0) { printf("s1 is less than s2\n"); } else if (result == 0) { printf("s1 is equal to s2\n"); } else { printf("s1 is greater than s2\n"); } return 0; }
strncmp(const char* s1, const char* s2, size_t n):比较 s1 和 s2 两个字符串的前 n 个字符的大小。比较方式与 strcmp 类似,但只比较前 n 个字符。
#include <stdio.h> #include <string.h> int main() { char s1[] = "abcde"; char s2[] = "abcdf"; int result = strncmp(s1, s2, 3); if (result < 0) { printf("s1 is less than s2 (comparing first 3 characters)\n"); } else if (result == 0) { printf("s1 is equal to s2 (comparing first 3 characters)\n"); } else { printf("s1 is greater than s2 (comparing first 3 characters)\n"); } return 0; }
(4). 字符串查找函数:
strchr(const char* str, int c):在 str 字符串中查找字符 c 第一次出现的位置,并返回指向该位置的指针。如果未找到字符 c,则返回 NULL。
#include <stdio.h> #include <string.h> int main() { char str[] = "Hello, World!"; char *result = strchr(str, 'o'); if (result!= NULL) { printf("The part of the string starting from 'o': %s\n", result); } return 0; }
strstr(const char* haystack, const char* needle):在 haystack 字符串中查找 needle 子字符串第一次出现的位置,并返回指向该位置的指针。如果未找到 needle 子字符串,则返回 NULL。
#include <stdio.h> #include <string.h> int main() { char haystack[] = "Hello, World!"; char needle[] = "World"; char *result = strstr(haystack, needle); if (result!= NULL) { printf("The substring is found at position: %ld\n", result - haystack); } else { printf("The substring is not found in the string.\n"); } return 0; }
(5). 字符串长度计算函数:
strlen(const char* str):计算 str 字符串的长度,即从字符串的首地址开始,直到遇到字符串结束符 '\0' 为止的字符个数(不包括 '\0')。
#include <stdio.h> #include <string.h> int main() { char str1[] = "Hello"; char str2[] = " "; char str3[] = ""; size_t len1 = strlen(str1); size_t len2 = strlen(str2); size_t len3 = strlen(str3); printf("The length of 'Hello' is %zu\n", len1); printf("The length of ' ' is %zu\n", len2); printf("The length of '' is %zu\n", len3); return 0; }
(6). 内存操作函数:
memcpy(void* dest, const void* src, size_t n):从 src 所指向的内存空间中复制 n 个字节到 dest 所指向的内存空间。src 和 dest 所指向的内存区域不能重叠。
#include <stdio.h> #include <string.h> int main() { int arr1[5] = {1, 2, 3, 4, 5}; int arr2[5]; memcpy(arr2, arr1, sizeof(arr1)); for (int i = 0; i < 5; i++) { printf("%d ", arr2[i]); } printf("\n"); return 0; }
#include <stdio.h> #include <string.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; // 以下操作中源和目标内存区域重叠,使用memcpy会导致未定义行为 memcpy(&arr[1], &arr[0], sizeof(int) * 4); for (int i = 0; i < 5; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; }
memmove(void* dest, const void* src, size_t n):与 memcpy 类似,也是从 src 复制 n 个字节到 dest,但允许 src 和 dest 所指向的内存区域重叠。其实现方式是先将 src 中的数据复制到一个临时缓冲区,然后再从临时缓冲区复制到 dest。
#include <stdio.h> #include <string.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; // 源和目标内存区域重叠,使用memmove是安全的 memmove(&arr[1], &arr[0], sizeof(int) * 4); for (int i = 0; i < 5; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; }
memset(void* s, int c, size_t n):将 s 所指向的内存空间的前 n 个字节设置为指定的字符 c。常用于初始化数组或内存块。
#include <stdio.h> #include <string.h> int main() { int arr[5]; char str[10]; memset(str, 'a', 5); // 字符数组初始化 str[5] = '\0'; printf("%s\n", str); memset(arr, 0, sizeof(arr)); // 整数数组初始化(清零) for (int i = 0; i < 5; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; }
memcmp(const void* s1, const void* s2, size_t n):比较 s1 和 s2 所指向的内存空间的前 n 个字节的大小。比较结果与 strcmp 类似,返回值小于 0 表示 s1 小于 s2,返回值等于 0 表示 s1 等于 s2,返回值大于 0 表示 s1 大于 s2。
#include <stdio.h> #include <string.h> int main() { int arr1[5] = {1, 2, 3, 4, 5}; int arr2[5] = {1, 2, 3, 4, 6}; int result = memcmp(arr1, arr2, sizeof(arr1)); if (result < 0) { printf("arr1 is less than arr2\n"); } else if (result == 0) { printf("arr1 is equal to arr2\n"); } else { printf("arr1 is greater than arr2\n"); } return 0; }
二. std::string类(C++标准库中的字符串类)
1. 定义与初始化
使用std::string类可以更方便地处理字符串。可以通过多种方式初始化std::string对象。
(1) 直接初始化
可以使用字符串字面量直接初始化std::string对象。
std::string str1 = "Hello"; std::string str2("World");
(2) 复制初始化
通过已有的std::string对象进行复制初始化。
std::string str3 = str1;
(3) 使用n个相同字符初始化
使用std::string的构造函数,可以创建一个由n个相同字符组成的字符串。
std::string str4(5, 'a'); // 创建一个包含5个 'a' 的字符串,即 "aaaaa"
2. 成员函数
(1) 获取字符串长度:length和size
这两个函数的功能相同,都用于返回字符串中字符的个数。
std::string str = "Hello"; std::cout << "Length of the string: " << str.length() << std::endl; std::cout << "Size of the string: " << str.size() << std::endl;
(2) 字符串连接:+运算符和append函数
+运算符:可以将两个字符串连接起来,也可以将字符串和字符串字面量连接。
std::string str5 = "Hello"; std::string str6 = " World"; std::string str7 = str5 + str6; std::string str8 = str5 + " there";
append函数:用于在原字符串末尾添加另一个字符串或字符序列。
std::string str9 = "Hello"; std::string str10 = " World"; str9.append(str10);
(3) 字符串比较:compare函数
用于比较两个字符串的大小关系。如果返回值小于0,表示当前字符串小于被比较的字符串;等于0,表示相等;大于0,表示大于。
std::string str11 = "abc"; std::string str12 = "abd"; int result = str11.compare(str12); if (result < 0) { std::cout << "str11 is less than str12" << std::endl; } else if (result == 0) { std::cout << "str11 is equal to str12" << std::endl; } else { std::cout << "str11 is greater than str12" << std::endl; }
(4) 访问字符串中的字符:[]运算符和at函数
[]运算符:可以像访问数组元素一样访问字符串中的字符,但不进行边界检查。
std::string str13 = "Hello"; std::cout << "The first character of str13: " << str13[0] << std::endl; // 如果使用越界的索引,可能会导致未定义行为,如 str13[10]
at函数:与[]运算符类似,但会进行边界检查,如果越界则抛出std::out_of_range异常。
try { std::string str14 = "Hello"; std::cout << "The first character of str14: " << str14.at(0) << std::endl; std::cout << "The sixth character of str14: " << str14.at(5) << std::endl; } catch (std::out_of_range& e) { std::cout << "Index out of range: " << e.what() << std::endl; }
(5) 查找子字符串:find函数
用于在字符串中查找子字符串。如果找到,则返回子字符串在原字符串中的起始位置(索引);如果找不到,则返回std::string::npos。
std::string str15 = "Hello World"; int pos = str15.find("World"); if (pos!= std::string::npos) { std::cout << "Substring 'World' found at position: " << pos << std::endl; } else { std::cout << "Substring not found" << std::endl; }
(6) 替换子字符串:replace函数
可以用指定的字符串替换原字符串中的部分内容。
std::string str16 = "Hello World"; str16.replace(0, 5, "Hi"); std::cout << "After replacement: " << str16 << std::endl;
三. 字符串输入输出操作
可以使用std::cin和std::cout对std::string对象进行输入输出操作。
std::string input; std::cout << "Enter a string: "; std::cin >> input; std::cout << "You entered: " << input << std::endl;
当使用std::cin读取字符串时,如果输入包含空格,std::cin会在遇到第一个空格时停止读取。如果要读取包含空格的整行字符串,可以使用std::getline函数。
std::string line; std::cout << "Enter a line: "; std::getline(std::cin, line); std::cout << "You entered: " << line << std::endl;