文章目录
-
-
- 字符串和字符串函数
-
- 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;
}