文章目录
-
-
- 字符串和字符串函数
-
- 1. 字符串
-
- 1.1 C/C++ 字符串概述
-
- 1.1.1 字符串常量
- 1.1.2 字符数组
- 1.2 字符串函数
-
- 1.2.1 strcpy 和 strncpy
- 1.2.2 strcat 和 strncat
- 1.2.3 strcmp 和 strncmp
- 1.2.4 strchr 和 strrchr
- 1.2.5 strstr 和 strlen
- 1.2.6 memory 函数
-
字符串和字符串函数
1. 字符串
1.1 C/C++ 字符串概述
1.1.1 字符串常量
字符串常量
格式要求:采用英文双引号包含的所有内容,C/C++ 语言规定,自负床常量都存在一个 ‘ ’ 结尾
在内存的【数据区】,而且字符串本身在程序中是对应当前字符串所在内存的空间首地址,可以采用 char * 存储对应的首地址。
"ABCDEFG" 占用字节为 8 个字节!!!
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { printf("字符串占用字节数: %ld ", sizeof("ABCDEFG")); // 8 /* str 可以存储字符串常量在内存【数据区】的空间首地址 同时也是当前字符串下标为 0 的元素空间首地址 */ char *str = "1234567890"; printf("str : %s ", str); // 1234567890 printf("%p ", "1234567890"); // 0x400697 printf("&str[5] : %s ", &str[5]); // 67890 printf("*str : %c ", *str); // 1 printf("str[5] : %c ", str[5]); // 6 printf(""1234567890"[5] : %c ", "1234567890"[5]); // 6 return 0; }
1.1.2 字符数组
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { char arr[4] = {'a', 'b', 'c', ' '}; /* arr 数组名数据类型为 char * 是当前字符数组空间首地址 同时也是下标为 0 的元素空间首地址 可以将一个符合 C/C++ 规范的字符数组当作一个字符串【变量】操作 C/C++ 规范要求末尾必须有 */ printf("arr = %s ", arr); printf("arr = %p ", arr); printf("arr[1] = %c ", arr[1]); // 在字符数组可以进行数据的更改 arr[1] = 'G'; printf("arr = %s ", arr); // 段错误!字符串常量无法修改 char *str = "ABC"; str[1] = 'G'; printf("str = %s ", str); return 0; }
1.2 字符串函数
【重要提示】
- 字符串是一个常量,数据内容无法修改,地址内容无法修改
- 字符串函数操作请注意【内存空间问题】
- 字符串函数操作,注意返回值类型和返回值情况
1.2.1 strcpy 和 strncpy
char *strcpy(char *dest, const char *src); 将 src 指向的字符串内容,拷贝到 dest 字符数据空间中 要求: 1. src 可以是字符串常量,也可以是字符数组 2. dest 必须是可以存储字符数据的内存空间,一般是字符数组或者动态申请内存字符空间,而且空间要求足够使用 char *strncpy(char *dest, const char *src, size_t n); 将 src 指向的字符串内容,拷贝到 dest 字符数据空间中,最多复制 n 个字符。 要求: 1. src 可以是字符串常量,也可以是字符数组 2. dest 必须是可以存储字符数据的内存空间,一般是字符数组或者动态申请内存字符空间,而 且空间要求足够使用。
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { /* 【重要提示】 - 字符串是一个常量,数据内容无法修改,地址内容无法修改 - 字符串函数操作请注意【内存空间问题】 - 字符串函数操作,注意返回值类型和返回值情况 */ // strcpy 函数 char dest[20] = {' '}; char *src = "0213456789"; printf("dest = %s ", dest); // 空 printf("src = %s ", src); // 0213456789 printf("--------------------------------- "); strcpy(dest, src); printf("dest = %s ", dest); // 0213456789 printf("src = %s ", src); // 0213456789 printf("--------------------------------- "); // strncpy 函数 char dest1[20] = {' '}; char *src1 = "12345"; strncpy(dest1, src1, 20); printf("dest1 = %s ", dest1); // 12345 printf("src1 : %s ", src1); // 12345 return 0; }
1.2.2 strcat 和 strncat
char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾 注意: 1. 末尾标记' ' 2. 返回值数据类型为 char *,返回内容是 dest 对应的空间首地址 3. dest 必须有对应的内存空间 char *strncat(char *dest, const char *scr, size_t n) 把 src 所指向的字符串类型追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止 注意: 1. 末尾标记' ' 2. 返回值数据类型为 char *,返回内容是 dest 对应的空间首地址 3. dest 必须有对应的内存空间
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { char *src = "ABCD"; // 定义一个容量为 20 的字符串数组 char dest[20] = {'E', 'F', 'G', ' '}; // strcat 操作 char *s1 = strcat(dest, src); // 将字符串 ABCD 复制到字符数组 dest 的末尾 printf("s1 = %s ", s1); // EFGABCD printf("dest = %s ", dest); // EFGABC printf("----------------------------- "); // strncat 操作 char *s2 = strncat(dest, src, 3); // 字符串的三个元素复制到字符数组 dest 的末尾 printf("s2 = %s ", s2); //EFGABCDABC(在 strcat 操作的基础上) printf("dest = %s ", dest); // EFGABCDABC return 0; }
1.2.3 strcmp 和 strncmp
int strcmp(const char *str1, const char *str2) 把 str1 所指向的字符串和 str2 所指向的字符串进行比较 返回值 1. 0 表示 str1 和 str2 两个字符串一致 2. 1 or -1 表示两个字符串不一致 int strncmp(const char *str1, const char *str2, size_t n) 把 str1 所指向的字符串和 str2 所指向的字符串进行比较,最多比较前 n 个字节 返回值 1. 0 表示 str1 和 str2 两个字符串一致 2. 1 or -1 表示两个字符串不一致
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { // strcmp 操作 printf("ret = %d ", strcmp("ABC", "ABC")); // 0 printf("ret = %d ", strcmp("AbC", "ABC")); // 1 printf("ret = %d ", strcmp("ABC", "aBc")); // -1 printf("------------------------------- "); /* 字符串数据通过 == 等值判断,比较的不是【字符串内容】 是比较两端的地址是否一致,如果是两个内容一致的字符串 常量比较, == 判断结果为 1(true),如果是两个字符数组 或者字符串和字符数组内容一致,但是通过 == 等值判断 结果为 0(false) */ printf("ret : %d ", "ABC" == "ABC"); // 1 char arr[4] = {'A', 'B', 'C', ' '}; printf("ret : %d ", "ABC" == arr); // 0 因为比较的是地址是否一致 printf("------------------------------- "); // strncmp 操作 printf("ret : %d ", strncmp("ABCDE", "ABCDE11111", 5)); // 0 printf("ret : %d ", strncmp("ABCDE", "ABCDE11111", 6)); // -1 return 0; }
1.2.4 strchr 和 strrchr
char *strchr(const char *str, int c); 在参数 str 所指向的字符串中搜索第一次出现字符 c (一个无符号字符) 的位置 char *strrchr(const char *str, int c); 在参数 str 所指向的字符串中搜索最后一次出现字符 c (一个无符号字符) 的位置
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { // strchr 操作,在参数 str 所指向的字符串中搜索 // 第一次出现字符 '8' 的位置 char *str = "ABCD8BCD"; char *p1 = strchr(str, '8'); printf("p1 : %s ", p1); // 8BCD printf("p1 = %p ", p1); // 0x40081c /* p1 和 str 都是 char * 指针,存储对应的数据得地址 因为字符数据在内存中,占用字节数为 1, 两个字符地址相减, 可以认为是下标位置,要求必须在同一个字符串地址范围以内 */ printf("p1 - str : %ld ", p1 - str); // 4 printf("-------------------------------- "); int arr[5] = {1, 2, 3, 4, 5}; /* 两个同数组中元素取地址相减操作 CPU 首先计算两个地址直接得字节差, 根据数据类型相减,最终结果是两个地址得【下标差/坐标差】 */ printf("&arr[4] - &arr[1] : %ld ", &arr[4] - &arr[1]); // 3 // strrchr 操作,在参数 str 所指向的字符串中搜索 // 最后一次出现字符 'C' 的位置 char *p2 = strrchr(str, 'C'); printf("p2 = %s ", p2); // CD printf("p2 = %p ", p2); // 0x40081e return 0; }
1.2.5 strstr 和 strlen
char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle (不包含空结束字符) 的位置 size_t strlen(const char *str) 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { // strstr 操作 // 在字符串 str 中查找第一次出现 // 字符串 target (不包含空结束字符) 的位置 char *str = "ABCDEFG"; char *target = "EFG"; char *p = strstr(str, target); printf("p = %p ", p); // 0x4007a8 系统分配的地址 printf("p = %s ", p); // EFG // 相当于 (E 的下标位置) - (A 的下标位置) printf("p - str = %ld ", p - str); // 4 // 计算字符串 "ABCD" 的长度 // 直到空结束字符,但不包括空结束字符 printf("strlen = %ld ", strlen("ABCD")); // 4 "ABCD" 字符串的长度 char arr[5] = {'A', 'B', 'C', 'D', ' '}; printf("strlen = %ld ", strlen(arr)); // 4 return 0; }
1.2.6 memory 函数
以下函数具备字符串处理功能,更多的使用场景是针对内存数据操作
void *memchr(const void *str, int c, size_t n) 在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c (一个无符号字符)的位置 int memcmp(const void *str1, const void *str2, size_t n) 把 str1 和 str2 的前 n 个字节进行比较
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct student { int id; char name[32]; int age; } Student; int main(int argc, char const *argv[]) { /* void *memchr(const void *str, int c, size_t n) 在参数 str 所指向的字符串的前 n 个字节中搜索 第一次出现字符 c (一个无符号字符) 的位置 */ char *str = "ABCDABCD"; void *p = memchr(str, 'C', 5); printf("p = %p ", p); // 0x4008e6 /* int memcmp(const void *str1, const void *str2, size_t n) 把 str1 和 str2 的前 n 个字节进行比较 0 相同,非 0 不同 */ char *str1 = "ABCDE"; char *str2 = "ABcDE"; int ret = memcmp(str1, str2, 5); printf("ret = %d ", ret); // != 0 为:-32 printf("--------------------------- "); // 用 malloc 申请空间 Student * stu1 = (Student *)malloc(sizeof(Student)); memset(stu1, 0, sizeof(Student)); Student * stu2 = (Student *)malloc(sizeof(Student)); memset(stu2, 0, sizeof(Student)); stu1->id = 1; strcpy(stu1->name, "James"); stu1->age = 39; stu2->id = 1; strcpy(stu2->name, "James"); stu2->age = 39; // stu1 和 stu2 的内存内容一样 ret = memcmp(stu1, stu2, sizeof(Student)); printf("ret = %d ", ret); // 0 相同为 0 free(stu1); free(stu2); stu1 = NULL; stu2= NULL; return 0; }
void *memcpy(void *dest, const void *src, size_t n) 从 src 复制 n 个字符到 dest 中 void *memmove(void *dest, const void *src, size_t n) 另一个用于从 src 复制 n 个字符到 dest 的函数 /* memcpy 和 memmove 功能 和 strncpy 一致,memmove 可以更好的保护拷贝源数据 src 【推荐】使用 memmove,不会导致存储数据丢失 */ void *memset(void *str, int c, size_t n) 复制字符 c (一个无符号字符) 到参数 str 所指向的字符串的前 n 个字符
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { char arr[10] = "ABCDE"; /* memove 操作 从 src 复制 n 个字符到 dest 中, */ memmove(arr, "123456789", 3); // 将前三位覆盖 printf("arr = %s ", arr); // arr = 123DE printf("------------------------ "); /* memcpy 操作 从 src 复制 n 个字符到 dest 中 */ char str[20] = "Hello World"; memcpy(&str[1], &str[5], 4); printf("%s ", str); // 结果:H Wor World printf("------------------------ "); /* memset 操作 复制字符 c (一个无符号字符) 到 参数 str 所指向的字符串的前 n 个字符 */ char str2[20] = "Hello World"; memset(str2, 'a', 5); printf("%s ", str2); // aaaaa World return 0; }