-ciox.jpg)
【C】字符串
字符串
1. 字符串概述
字符串在开发中是非常重要数据载体,常用于数据传递和存储,具备较强的稳定性和安全性(可以进行加密操作)。针对于字符串操作涉及到拼接,拷贝,查询…
字符串的两种定义方式:
- char *arr = “hello”;需要注意的是必须初始化!
- char arr[10] = “hello”;
2. 字符串相关函数
补充知识点 字符串数据要求
在 C/C++ 中字符串数据【字符串常量/字符数组】,必须结尾是一个 ‘\0’,建议以下所有函数的两个参数对应字符串均以\0结尾。
以下所有函数针对的都是二进制,与外部数据无关
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
printf("strlen(\"ABC\") : %ld\n", strlen("ABC")); // 3 有效字符个数
printf("sizeof(\"ABC\") : %ld\n", sizeof("ABC")); // 4 当前字符串占用内存字节数
/*
strlen("ABC") : 3
sizeof("ABC") : 4
sizeof 多出一个字节,多出的内容是一个字符串标记 '\0'
*/
/*
当前 arr 算不算是一个字符数组?
算
当前 arr 算不算一个字符串数据?
不算!!!
*/
char arr[5] = {'A', 'B', 'C', 'D', 'E'};
char arr2[5] = {'A', 'B', 'C', 'D', 'E'};
/*
对于计算机而言,字符串数据必须是 '\0' 结尾,包括
打印/数据占位符 %s ,需要展示字符串数据,要求到 '\0' 结束
但是 arr 和 arr2 中不存在 '\0',且两个字符数组内存空间连续
因为在调用过程中,未发现 '\0' ,所以打印 arr 内容,展示的
效果是 arr + arr2 + 后续野值数据
*/
printf("arr = %s\n", arr);
/*
当前 arr3 算不算是一个字符数组?
算
当前 arr3 算不算一个字符串数据?
算!!!
*/
char arr3[5] = {'A', 'B', 'C', 'D', '\0'};
return 0;
}
2.1 strcat 和 strncat(不会复制\0)
char *strcat(char *dest, const char *src)
函数功能: 将 src 对应的字符串内容,拼接到 dest 对应的字符串数据空间中,要求 dest 必须有足够的内存空间存储目标 src 字符串数据
参数解释:
- dest : 通常情况下是一个字符数组形式,可以是静态数组,也可以是通过动态内存(malloc calloc realloc)分配得到的连续存储字符串数据内存空间。要求必须有足够的预留内存空间存储目标
src
数据, 同时要求保证可以满足字符串数据要求- src:提供给当前函数作为拼接到
dest
末尾的字符串数据,可以是字符串常量,也可以是字符数组返回值解释:
- 返回值内容是当前参数 dest 地址。
char *strncat(char *dest, const char *src, size_t n)
函数功能: 将 src 对应的字符串内容前 n 个字符,拼接到 dest 对应的字符串数据空间中,要求 dest 必须有足够的内存空间存储目标 src 字符串数据
参数解释:
- dest : 通常情况下是一个字符数组形式,可以是静态数组,也可以是通过动态内存(malloc calloc realloc)分配得到的连续存储字符串数据内存空间。要求必须有足够的预留内存空间存储目标
src
数据, 同时要求保证可以满足字符串数据要求- src:提供给当前函数作为拼接到
dest
末尾的字符串数据,可以是字符串常量,也可以是字符数组- n: 限制当前
src
中前n
个字符拼接到目标dest
之后返回值解释:
- 返回值内容是当前参数 dest 地址。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
*/
int main(int argc, char const *argv[])
{
/*
使用字符串常量给予字符数组进行赋值操作
当前 arr 字符串数据中的数据存储情况为
{'A', 'B', 'C', 'D', '\0', '\0', '\0', '\0', '\0', '\0'}
当前字符数组中有 6 个 '\0' 存在,如果需要保证当前字符数组数据
依然满足字符串要求,有且最多可以填充的字符个数为 5 个
*/
char arr[10] = "ABCD";
/*
strcat 操作需要明确的知晓当前操作过程中 src 对应字符串数据是否
满足当前 dest 剩余内存空间情况。防止出现越界行为。
strcat(arr, "ABCDEFG"); // 1 不行,超出范围
strcat(arr, "12345"); // 2 可以!!!
strcat(arr, "8888"); // 3 可以!!!
strcat(arr, "987654321"); // 4 不行,超出范围
*/
strcat(arr, "123");
printf("arr = %s\n", arr);
strncat(arr, "ABCDEFG", 2);
printf("arr = %s\n", arr);
return 0;
}
2.2 strcpy 和 strncpy(会复制\0,且复制过去从下标为0的元素覆盖)
char *strcpy(char *dest, const char *src)
函数功能: 将 src 对应的字符串内容复制到 dest 指向的内存空间中,要求 dest 必须有足够的内存空间保证字符串数据完整
tips : strcpy 会将 src 对应的完整字符串数据拷贝到 dest 中,同时会将 ‘\0’ 同时提供给 dest
参数解释:
- dest : 通常情况下是一个字符数组形式,可以是静态数组,也可以是通过动态内存(malloc calloc realloc)分配得到的连续存储字符串数据内存空间。要求必须有足够的预留内存空间存储目标
src
数据, 同时要求保证可以满足字符串数据要求- src:提供给当前函数,将
src
对应字符串数据拷贝到dest
对应内存空间中返回值解释:
- 返回值内容是当前参数 dest 地址。
char *strncpy(char *dest, const char *src, size_t n)
函数功能: 将 src 对应的字符串内容前 n 个字符复制到 dest 指向的内存空间中,要求 dest 必须有足够的内存空间保证字符串数据完整
tips : strncpy 仅将限制以内的字符拷贝提供给当前 dest 不会自行补充 '\0’
参数解释:
- dest : 通常情况下是一个字符数组形式,可以是静态数组,也可以是通过动态内存(malloc calloc realloc)分配得到的连续存储字符串数据内存空间。要求必须有足够的预留内存空间存储目标
src
数据, 同时要求保证可以满足字符串数据要求- src:提供给当前函数,将
src
对应字符串数据拷贝到dest
对应内存空间中- n: 将 src 前 n 个字符拷贝到目标 dest 空间中,同时保证字符串数据完整
返回值解释:
- 返回值内容是当前参数 dest 地址。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
char *strcpy(char *dest, const char *src)
char *strncpy(char *dest, const char *src, size_t n)
*/
int main(int argc, char const *argv[])
{
/*
使用字符串常量给予字符数组进行赋值操作
当前 arr 字符串数据中的数据存储情况为
{'1', '2', '3', '4', '5', '6', '7', '\0', '\0', '\0'}
*/
char arr[10] = "1234567";
strcpy(arr, "ABC");
/*
以上 strcpy 执行完毕,arr 中数据存储情况为
{'A', 'B', 'C', '\0', '5', '6', '7', '\0', '\0', '\0'}
*/
printf("arr = %s\n", arr); // ABC ABC4567
printf("arr[5] = %c\n", arr[5]); // '\0' '6'
printf("arr[4] = %c\n", arr[4]); // '\0' '5'
arr[3] = '1';
printf("arr = %s\n", arr); // ABC ABC4567
/*
以上操作完成,arr 中存储的数据情况
{'A', 'B', 'C', '1', '5', '6', '7', '\0', '\0', '\0'}
*/
strncpy(arr, "666", 2);
printf("arr = %s\n", arr); // 66 66C1567
arr[2] = '\0';
char arr1[3] = {'C', 'D', 'E'};
char *str1 = (char *)calloc(10, sizeof(char));
str1[0] = '1';
str1[1] = '2';
str1[2] = '3';
strcpy(str1, arr1);
printf("str1 = %s\n", str1); //
free(str1);
return 0;
}
2.3 strcmp 和 strncmp
int strncmp(const char *str1, const char *str2, size_t n);
函数功能: 字符串比较函数,将 str1 和 str2 对应的字符串数据,前 n 个字符进行比较,如果一致返回 0,如果不一致,返回结果不为 0
参数解释:
- str1: 用户提供的字符串数据
- str2: 用户提供的字符串数据
- n : 要求比较 str1 和 str2 前 n 个字符是否一致
返回值解释:
- 如果两个字符串前 n 个字符串一致,返回 0,否则返回值非 0
int strcmp(const char *str1, const char *str2);
函数功能: 字符串比较函数,将 str1 和 str2 对应的字符串数据进行逐一比较,如果一致返回 0,如果不一致,返回结果不为 0
参数解释:
- str1: 用户提供的字符串数据
- str2: 用户提供的字符串数据
返回值解释:
- 如果两个字符串前一致,返回 0,否则返回值非 0
2.4 strstr 和 strchr
char *strchr(const char *str, int c)
函数功能: 在当前 str 字符串中,找到目标字符 c ,如果存在,返回 c 第一次出现的地址,如果不存在返回 NULL
tips: 参数
c
是一个int
数据类型,但是实际上提供给函数使用的有且只有整个int
内存低 8 位,相当于有且只有一个字节数据有效参数解释:
- str:目标搜索字符数据的字符串数据,可以是字符串常量也可以是满足字符串要求的字符数组
- c: 目标搜索的字符数据
返回值解释:
- 如果找到目标字符,返回字符在当前字符串中的地址,如果未找到返回
NULL
char *strstr(const char *haystack, const char *needle)
函数功能: 在当前 haystack 字符串中,找到目标字符串 needle ,如果存在,返回 needle 第一次出现的地址,如果不存在返回 NULL
参数解释:
- str:目标搜索字符数据的字符串数据,可以是字符串常量也可以是满足字符串要求的字符数组
- c: 目标搜索的字符数据
返回值解释:
- 如果找到目标字符,返回字符在当前字符串中的地址,如果未找到返回
NULL
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
char *strchr(const char *str, int c)
char *strstr(const char *haystack, const char *needle)
*/
int main(int argc, char const *argv[])
{
char *str1 = "ABCDEFG";
if (strchr(str1, 'a'))
{
printf("目标字符存在!\n");
}
else
{
printf("Source Not Found! 404!\n");
}
if (strstr(str1, "CB"))
{
printf("目标字符串存在!\n");
}
else
{
printf("Source Not Found! 404!\n");
}
/*
"" C/C++ 中的空字符串,当前字符串中有且只有一个 '\0'
*/
char arr[10] = "";
strcpy(arr, strchr(str1, 'C'));
printf("arr = %s\n", arr);
return 0;
}
2.5 自学函数
菜鸟教程-string.h
char *strrchr(const char *str, int c);
char *strtok(char *str, const char *delim); // VIP 函数
3. 内存操作相关函数
以下函数是在 <string.h> 头文件中,针对于内存进行操作的函数,关注点是内存中的二进制数据情况,不需要考虑外部的数据类型。所有函数相关操作都是以字节为单位。
3.1 memchr
void *memchr(const void *p, int b, size_t n)
函数功能: 在 p 指向内存空间中,前 n 个字节搜索指定字节 b 对应数据是否存在,如果存在,返回所在内存地址位置,如果不存在,返回 NULL
参数解释:
- p: 目标内存空间首地址,可以是静态内存地址,也可以是动态申请的内存地址
- b: 参数类型为
int
类型,实际提供给当前函数的有效数据是当前int
类型的低 8 位,一个字节数据。- n: 表示搜索范围的内存字节数
返回值解释:
- 如果目标内存数据存在,返回对应地址,否则返回
NULL
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
当前操作考虑的内容是内存中的数据情况,不需要考虑内存二进制对外的
数据类型和数据形式。
参数 int b 在函数中要求的参数为 int 类型,但是在函数实际运行过程
中,有效数据仅是当前 int 类型数据的低 8 位参与代码运行。
例如:
b 对应的实际参数为 321 函数实际解析参与代码运行的数据为 65
void *memchr(const void *p, int b, size_t n)
*/
int main(int argc, char const *argv[])
{
int arr[5] = {321, 833, 1857, 3905, 8001};
if (memchr(arr, 65, 20)) //
{
printf("目标存在!\n");
}
else
{
printf("Source Not Found!\n");
}
if (memchr(arr, 15, 20)) //
{
printf("目标存在!\n");
}
else
{
printf("Source Not Found!\n");
}
printf("memchr(arr, 65, 20) : %p\n", memchr(arr, 65, 20)); // 0x7fff3a17d3b0
printf("memchr(arr, 256, 20) : %p\n", memchr(arr, 256, 20)); // 0x7fff3a17d3b2
printf("memchr(arr, 15, 20) : %p\n", memchr(arr, 15, 20)); // 0x7fff3a17d3bd
return 0;
}
3.2 memcmp
int memcmp(const void *p1, const void *p2, size_t n)
函数功能: 比较参数 p1 和 p2 指向内存空间中,前 n 个字节内容是否一致。如果一致返回 0,如果不一致返回其他
参数解释:
- p1: 用户提供进行比较操作的内存空间首地址
- p2: 用户提供进行比较操作的内存空间首地址
- n: 比较限制的前 n 个字节
返回值解释:
- 如果两个内存对应的数据完全一致,返回 0,否则返回其他整数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
int memcmp(const void *p1, const void *p2, size_t n);
*/
int main(int argc, char const *argv[])
{
int num = 1145258561;
/*
当前 num 是一个 int 类型,对应内存为
0100 0100
0100 0011
0100 0010
0100 0001
字符串 "ABCD" 二进制内容为
0000 0000 ==> '\0'
0100 0100 ==> 'D'
0100 0011 ==> 'C'
0100 0010 ==> 'B'
0100 0001 ==> 'A'
将 num 和 字符串 "ABCD" 对应内存的前 4 个字节进行比较
1145258561 "ABCD"
0100 0100 0100 0100 ==> 'D'
0100 0011 0100 0011 ==> 'C'
0100 0010 0100 0010 ==> 'B'
0100 0001 0100 0001 ==> 'A'
*/
int ret = memcmp(&num, "ABCD", 4);
printf("ret = %d\n", ret); // 0
return 0;
}
3.3 memcpy 和 memmove
void *memcpy(void *dest, const void *src, size_t n)
void *memmove(void *dest, const void *src, size_t n)
函数功能: 以上两个函数是将 src 对应内存中的 n 个字节数据,拷贝到 dest 对应内存,要求 dest 对应内存必须具备足够的数据空间
tips : memcpy 性能好,但是安全性较低,memmove 性能较低,安全性好,如果涉及到【同源地址】拷贝操作,请使用 memmove
tips: 【同源地址】dest 和 src 来自于同一块连续内存空间,例如同一个数组 &arr[2] &arr[5],同一个动态申请内存空间
参数解释:
- dest : 目标存储数据的内存空间首地址
- src:提供拷贝源数据的首地址
- n: 拷贝目标对应的字节个数
返回值解释:
- 返回值内容是当前参数 dest 地址。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
void *memcpy(void *dest, const void *src, size_t n)
void *memmove(void *dest, const void *src, size_t n)
*/
int main(int argc, char const *argv[])
{
char arr[10] = "ABCDEFG12";
printf("arr = %s\n", arr);
memmove(&arr[3], &arr[1], 5);
printf("arr = %s\n", arr);
memcpy(&arr[3], &arr[1], 5);
printf("arr = %s\n", arr);
return 0;
}
3.4 memset
void *memset(void *p, int b, size_t n)
函数功能: 将用户提供的指针 p 对应内存的 n 个字节,全部赋值为 b
参数解释:
- p: 用户提供内存的空间首地址
- b: 参数类型为
int
类型,实际提供给当前函数的有效数据是当前int
类型的低 8 位,一个字节数据。- n 覆盖操作对应的字节个数
返回值解释:
- 返回值内容是当前参数 p 地址。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
void *memset(void *p, int b, size_t n)
*/
int main(int argc, char const *argv[])
{
char arr[10];
memset(arr, 321, 10);
for (size_t i = 0; i < 10; i++)
{
printf("%c\n", arr[i]);
}
printf("=------------------------------\n");
int *p1 = (int *)malloc(10 * sizeof(int));
memset(p1, 65, sizeof(int) * 10);
// memset(p1, 0, sizeof(int) * 10); 正常操作!
for (size_t i = 0; i < 10; i++)
{
printf("%d\n", p1[i]);
}
free(p1);
return 0;
}
- ☐ ssacnf
- ☐ sprintf
- 感谢你赐予我前进的力量