一.字符串长度
1.概述
strlen
是 C 语言中的一个标准库函数,用于计算一个字符串的长度(长度不包含\0
)。它包含在 string.h
或 cstring
头文件中。
2.使用
头文件:#include
函数的原型:
-
str
:是要计算长度的字符串
size_t strlen(const char *str);
返回值:
strlen
函数返回字符串 str
的长度,不包括结尾的\0
字符
3.示例
#include
#include
int main() {
char str1[20] = "HelloWorld!";
char* str2 = "HelloWorld!";
printf("字符串1的长度是%zu\n", strlen(str1));//11,它不会例会字符数据的长度,只会关系字符串的长度
printf("字符串2的长度是%zu\n", strlen(str2));//11,计算的不是指针的大小,而是其指向字符串的长度
}
二.字符串拷贝
不要试图将字符串复制到文字常量区,文字常量区是只读的。
1.StrCpy
(1)概述
① 介绍
strcpy
是 C 语言中的一个标准库函数,用于复制字符串,不能指定要复制字符串的长度。
② 注意事项
需要注意要为终止符
\0
预留空间
- **内存污染:**使用这个函数时,必须保证dest指向的内存空间足够承载拷贝过来的字符串,复杂它会强行占用dest后面其它程序使用的内存,造成内存污染
- **源字符串的终止符:**使用这个函数复制字符串,其会把字符串的终止符
\0
复制过来.
(2)使用
头文件:#include
**返回值:**目的内存的首地址
函数声明:
-
dest
是目标字符串的指针,strcpy
会将源字符串复制到这块内存中。 -
src
是源字符串的指针,即你想要复制的那个字符串。
char* strcpy(char* dest,const char* str);
(3)示例
代码:
#include
#include
int main() {
char src[] = "Hello, World!";
char dest[20]; // 确保目标数组足够大以容纳源字符串
// 使用strcpy复制字符串
strcpy(dest, src);
printf("Copied string: %s\n", dest);
return 0;
}
输出:
Copied string: Hello, World!
2.Strncpy
(1)概述
① 介绍
**功能:**将 src 指向的字符串前 n 个字节,拷贝到 dest 指向的内存中
② 注意事项
-
strncpy
不拷贝\0
- 复制完毕后要手动附加
\0
,确保字符串正确结束,避免未定义的出现
- 复制完毕后要手动附加
-
如果n大于src指向的字符串中的字符个数,则在dest后面填充
n-strlen(src)
个\0
(2)使用
头文件:#include
**返回值:**目的内存的首地址
函数原型:
-
dest
:指向目标字符数组的指针,即复制到的位置。 -
src
:指向源字符串的指针,即从哪里开始复制。 -
n
:要复制的字符数。注意这里的n
是指字节数,对于多字节字符集(如UTF-8编码的字符串),一个字符可能由多个字节组成。
char *strncpy(char *dest, const char *src, size_t n);
(3)示例
代码:
在这个例子中,strncpy
函数从 src
字符串中复制最多 5 个字符到 dest
字符串中。然后,我们手动在 dest
字符串的末尾添加一个空字符(\0
),因为 strncpy
不会自动添加它。最后,我们使用 printf
函数输出源字符串和目标字符串。
#include
#include
int main() {
char src[] = "Hello, World!";
char dest[20]; // 确保目标数组足够大以容纳源字符串和空字符
// 使用 strncpy 复制最多 5 个字符(不包括空字符)
strncpy(dest, src, 5);
// 手动添加空字符,因为 strncpy 不一定会在末尾添加它
dest[5] = '\0';
printf("源字符串: %s\n", src);
printf("目标字符串: %s\n", dest);
return 0;
}
三.字符串追加
1.StrCat
(1)概述
① 功能
**功能:**strcat函数追加src字符串到dest指向的字符串的后面。追加的时候会追加\0
② 注意
- 要保证目标字符数组指向的内存空间足够大
- 它追加以目标字符串
dest
的\0
为起点,追加字符串str
的\0
为终点- 请确保目标字符串与追加字符串都是正确的结束
(2)使用
头文件:
函数声明:
-
dest
:指向目标字符数组的指针,即要追加的位置 -
str
:要追加的字符串
char* strcat(char *dest,const char *str);
(3)示例
\0
是字符串的结尾,其后的字符不会被打印
从下面的例子可以得知,strcat
的追加是在\0
后的追加,且其追加也会将\0
追加到字符串后面,从而导致str中Text
被忽略。
#include
#include
#pragma warning(disable:4996)
int main() {
char str[20] = "HelloWorld\0Text";
char* strTemp = "你好";
strcat(str,strTemp);
printf("%s\n", str);//HelloWorld你好
}
2.StrnCat
(1)概述
① 功能
用于将源字符串(source)的前n个字符追加到目标字符串(destination)的末尾。
② 与strcat的区别
与 strcat
函数不同的是,strncat
会检查目标字符串是否有足够的空间来容纳要追加的字符,从而避免了缓冲区溢出的风险。
(2)使用
头文件:
函数声明:
-
dest
:指向目标字符串的指针,该字符串应包含一个 C 字符串- 要确保其有足够的空间来容纳追加后的字符串,包括额外的空字符。
-
src
:指向要追加的源字符串的指针 -
n
:要追加的最大字符数- 大于源字符长度,仅会追加源字符长度的字符
- 小于源字符长度,则会追加指定的字符长度
char *strncat(char *dest, const char *src, size_t n);
(3)示例
在目标字符串
\0
处追加
使用strncat
追加zuiStr的前5个字符到str的后面(\0后面)
#include
#include
#pragma warning(disable:4996)
int main() {
char str[] = "aaa\0aaaaaaaaaaaaa";
char* zuiStr = "HelloWorld!";
strncat(str, zuiStr, 5);//复制zuiStr的前5个字符
printf("%s", str);//aaaHello
}
四.字符串比较
1.StrCmp
(1)概述
**比较规则:**根据ASCII,逐个字符去比较,一旦比较出大小就返回结果,后面的的不会继续比
注意:
- 因为它是根据ASCII进行比较的,所以
strcmp
函数对大小写敏感- 例如:
Hello
和hello
不被认为是一个字符串
- 例如:
(2)使用
函数声明:
-
str1
:指向第一个要比较的字符串的指针。 -
str2
:指向第二个要比较的字符串的指针
int strcmp(const char *str1, const char *str2);
返回值:
- 如果
str1
和str2
是相同的,返回值为 0。 - 如果
str1
在字典顺序上小于str2
,返回一个负数。 - 如果
str1
在字典顺序上大于str2
,返回一个正数。
(3)示例
代码:
#include
#include
int main() {
const char *str1 = "Hello";
const char *str2 = "World";
const char *str3 = "Hello";
int result;
// 比较 str1 和 str2
result = strcmp(str1, str2);
if (result < 0) {
printf("str1 is less than str2\n");
} else if (result > 0) {
printf("str1 is greater than str2\n");
} else {
printf("str1 is equal to str2\n");
}
// 比较 str1 和 str3
result = strcmp(str1, str3);
if (result == 0) {
printf("str1 is equal to str3\n");
}
return 0;
}
结果:
str1 is less than str2
str1 is equal to str3
2.StrnCmp
(1)概述
它同样用于比较两个字符串的大小,但其可以设置比较的多少个字符
(2)使用
函数声明:
-
str1
:指向第一个要比较的字符串的指针 -
str2
:指向第二个要比较的字符串的指针 -
n
:要比较的字符的最大数量
int strncmp(const char *str1, const char *str2, size_t n);
返回值:
- 如果
str1
和str2
的前n
个字符相同,返回值为 0 - 如果
str1
在字典顺序上小于str2
的前n
个字符,返回一个负数 - 如果
str1
在字典顺序上大于str2
的前n
个字符,返回一个正数
(3)示例
下面的代码中设置了比较的字符数是5,即只比较二则的Hello
部分,
结果显而易见就是相等的,故num
的值为0,输出Str1等于str2"
#include
#include
#pragma warning(disable:4996)
int main() {
char* str1 = "Hello C!";
char* str2 = "Hello World!";
int num = strncmp(str1, str2, 5);
if (num > 0) {
printf("str1大于str2");
} else if (num < 0) {
printf("str1小于str2");
}else {
printf("str1等于str2");//打印这个
}
}
五.字符查找
1.Strchr
(1)概述
首次匹配原则,找到后就不会继续了
在字符指针指向的字符串中,找指定ASCII码的字符,并返回第一次出现的字符
(2)使用
头文件:
函数声明:
- s:要查找的字符串
- c:要查找字符的ASCII码
- 可以直接使用
''
包裹,会自动转换成ASCII码
- 可以直接使用
char *strchr(const char *s, int c);
返回值:
- 找到返回第一个找到字符的地址(首次匹配)
- 找不到就返回
NULL
(3)示例
找到的是距离str1首地址5个元素的W,也就是第一个W了,即首次匹配
#include
#include
#pragma warning(disable:4996)
int main() {
char* str1 = "HelloWorld,WoW!";
char* p = strchr(str1, 'W');
printf("str-p:%d\n", p - str1);//str-p:5,表示找到的是距离str1首地址5个元素W(首次匹配)
return 0;
}
2.Strrchr
(1)概述
末次匹配原则,只会返回最后一个匹配到的字符
在字符指针指向的字符串中,找指定ASCII码的字符,并返回最后一次出现的字符
(2)使用
头文件:
函数声明:
- s:要查找的字符串
- c:要查找字符的ASCII码
char *strrchr(const char *s, int c);
返回值:
- 找到返回最后一个找到字符的地址(末次匹配)
- 找不到就返回
NULL
(3)示例
找到的是距离str1首地址13个元素的W,也就是最后一个W,即末次匹配
#include
#include
#pragma warning(disable:4996)
int main() {
char* str1 = "HelloWorld,WoW!";
char* q = strrchr(str1, 'W');
printf("str-q:%d\n", q-str1);//str-q:13,表示找到的是距离str1首地址13个元素的W(末次匹配)
return 0;
}
六.字符串匹配-strstr
1.概述
**功能:**在传入的字符串中去查找第一次出现的指定字符串
2.使用
头文件:
函数声明:
-
str
要在其中搜索的字符串 -
substr
要查找的子字符串
char *strstr(const char *str, const char *substr);
返回值:
- 找到,会返回
substr
第一次出现位置的指针 - 找不到,会返回NULL
3.示例
代码:
#include
#include
int main() {
char str[] = "Hello, World!";
char substr[] = "World";
char* result;
result = strstr(str, substr);
if (result != NULL) {
printf("找到字符串的位置: %ld\n", result - str);
}
else {
printf("Substring not found.\n");
}
return 0;
}
返回值:
找到字符串的位置: 7
七.空间设定
1.概述
概述:memset
是 C 语言中的一个库函数,用于设置内存区域的内容
**功能:**通常用于初始化内存区域或者将不需要的内存区域清零
2.使用
头文件:string.h>
函数原型:
-
str
:指向要设置内存区域的指针。 -
c
:要设置的值,这个值以 int 形式提供 - 函数会按照 unsigned char来解析这个值,因此可以传入字符
-
n
:要设置的字节数
返回值:
- 目的内存的首地址,即str
void *memset(void *str, int c, size_t n);
3.示例
代码:
这个例子演示了memset的初始化内存的应用
- 第一次printf在初始化内存的情况下读取该内存时,出现了随机字符
- 这是因为
printf
在未初始化的空间中遇不到\0
,然后一直往下读,直到遇到随机字符为止
- 这是因为
- 第二次prinft读取使用memset初始化后的内存后就是正常的空字符了
#include
#include
#include
#pragma warning(disable:4996)
int main() {
char * q =malloc(6*sizeof(char));
if (q == NULL) {
printf("申请失败");
return 1;
}
printf("str = %s\n", q);//str = 屯屯妄?,尝试打印未初始化内存空间的结果,一串随机字符
memset(q, '\0', 6 * sizeof(char));//使用memset对申请的空间进行初始化,可以避免这个问题
printf("str = %s\n", q);//str =w
}
八.字符串转数值
1.概述
有点类似于Java的
Integer.parseIn
t方法
**功能:**将指向字符串按数字进行解析成整数并返回
**注意:**传入的字符串的内容必须是数字,否则返回值会是0,即错误
2.使用
头文件:
函数原型:
- str:要转换的字符串
int atoi(const char *str);
返回值:
- 转换成功,返回解析出来的整数
-
str
的开始部分不包含可转换的数字或符号,atoi
会返回 0 - 转换的值超出了
int
类型的表示范围,atoi
会返回INT_MAX
或INT_MIN
- 在
头文件中定义
- 在
3.示例
代码:
#include
#include
int main() {
char str[] = "12345";
int num;
num = atoi(str);
printf("这个整数的值是: %d\n", num);
return 0;
}
返回值:
这个整数的值是12345
九.字符串切割函数
1.概述
strtok
是C标准库中的一个函数,用于将字符串分解成一系列子字符串。
2.使用
(1)注意事项
- 这个函数要实现连续切割,必须先只在
str
传入要切割的字符串切一次,再传入NULL
才能实现连续切割,而切割的结束条件,就是当且出来的值位NULL
的时候
(2)语法
要分两次进行切割,先用要分解的字符串切一次,接着的就用
NULL
继续切
函数原型:
-
str
:要分解的字符串- 第一次调用时传入待分解的字符串
- 后续调用传入 NULL。
-
delim
:分隔符,用于指定分解字符串的分隔符字符集- 会把
""
内任何一个字符都视为分隔符(无需,
分隔)
- 会把
char *strtok(char *str, const char *delim);
3.示例
(1)连续切割
① 步骤
- 先用strtok传入要分解的字符串切割一次
- 再传入
NULL
作要分解的字符串,循环切割
② 代码
打印的位置是有讲究的,放置在下一次切割的前面,保证了上面用str
切割的字符能够被打印
#include
#include
int main() {
char str[] = "apple,banana,orange";
char *token = strtok(str, ",");
while (token != NULL) {
printf("%s\n", token);//第一个切出来的apple会在这里被打印,然后token的值才被处理
token = strtok(NULL, ",");
}
return 0;
}
③ 输出
apple
banana
orange
(2)切割练习
切割通信模块返回的字符串,得到手机号、日期、时间、内容这些信息
#include
#include
#pragma warning(disable:4996)
/*
参数 1:待切割字符串的首地址
参数 2:指针数组:存放切割完字符串的首地址
参数 3:切割字符
返回值:切割的字符串总数量
*/
int msg_deal(char* msg_src, char* msg_done[], char* delStr) {
int i = 0;
msg_done[i] = strtok(msg_src, delStr);
while (msg_done[i] != NULL) {
i++;
msg_done[i] = strtok(NULL, delStr);
}
return i;
}
int main() {
char msg_src[] = "+CMGR:REC UNREAD,+8613466630259,98/10/01,18:22:11,ABCdefGHI";
char *msg_done[10];
int num = msg_deal(msg_src, msg_done, ",");
//printf("%d", num);
printf("手机号:%s\n", msg_done[1]+3);//向前移动3个字符,去掉+86
printf("日期:%s\n", msg_done[2]);
printf("时间:%s\n", msg_done[3]);
printf("内容:%s\n", msg_done[4]);
}
十.格式化字符串操作函数
1.格式化数据到字符串
类似于
printf
但这个不会进行打印,而是实质的写入缓冲区,可以理解为就是用来拼接参数组成一个字符串的函数**过程:**参数 -融合-> 字符串
(1)概述
介绍:sprintf
和snprintf
都是标准C库函数,用于将格式化的数据写入一个字符串,其中,一个不可以指定字符串长度,一个可以。
**注意事项:**在使用 sprintf
时,务必确保目标缓冲区有足够的空间来存储格式化的字符串,否则可能会导致缓冲区溢出
(2)使用
① Sprintf
函数原型:
-
*buf
:指向要写入的字符数组的指针大小必须足够容纳格式化后字符串,以及一个额外的
\0
-
*format
:一个C字符串,包含格式化标签,这些标签会被随后的参数替换 -
...
(可变参数):这些参数根据format
字符串中的格式说明符来提供值。
int sprintf(char *buf, const char *format, ...);
返回值:
sprintf
函数返回写入 buf
的字符总数(不包括结尾的空字符)。如果发生错误,则返回一个负数。
② Snprintf
**优点:**可以避免sprintf
导致的缓存区溢出问题
函数原型:
-
char *str
:指向要写入的字符数组的指针 -
size_t size
:这是目标缓冲区str
的大小(以字节为单位)。snprintf
会确保不会写入超过size - 1
个字符到缓冲区,以留出空间放置字符串的结束符\0
。 -
const char *format
:这是格式字符串,指定了如何格式化后续的参数。 -
...
(可变参数):这些参数根据format
字符串中的格式说明符来提供值
int snprintf(char *str, size_t size, const char *format, ...);
**返回值:**返回实际写入缓存区的字符数
- 大于或等于
size
则说明字符串被截断了
(3)示例
① sprintf
#include
#pragma warning(disable:4996)
int main() {
char buf[40];
int year = 2024;
int mon = 2;
int day = 11;
sprintf(buf, "今天是%d年%d月%d日,新年快乐!", year, mon, day);
printf("%s\n", buf);//今天是2024年2月11日,新年快乐!
return;
}
② snprintf
将size
设置为接受字符数组的长度,保证其不会溢出
#include
int main() {
char buf[40]; // 缓冲区大小为40
int year = 2024;
int mon = 2;
int day = 11;
// 使用snprintf确保不会溢出缓冲区
snprintf(buf, sizeof(buf), "今天是%d年%d月%d日,新年快乐!", year, mon, day);
printf("%s\n", buf); // 输出:今天是2024年2月11日,新年快乐!
return 0;
}
2.从字符串读取信息
过程: 字符串 -读取-> 参数
(1)概述
sscanf
函数是 C 语言中用于从字符串中读取格式化输入的函数。
(2)使用
函数原型:
-
str
是要从中读取输入的字符串。 -
format
是一个字符串,指定要读取的输入的格式 -
...
表示与格式字符串对应的附加参数,其中从字符串中读取的值将被存储。
int sscanf(const char *str, const char *format, ...);
返回值:sscanf
函数的返回值是成功读取和转换的输入项的数量。如果转换失败,则返回值为负数。
(3)format的编写
① 格式说明符
遇到空格停止匹配,例如
%s
,遇到Hello Join,只会匹配到Join
-
%d
:读取一个十进制整数。 -
%f
:读取一个浮点数。 -
%c
:读取一个字符。 -
%s
:读取一个字符串(遇到空格或换行符停止)。 -
%x
:读取一个十六进制整数。 -
%o
:读取一个八进制整数。 -
%u
:读取一个无符号十进制整数。 -
%lf
:读取一个双精度浮点数。
运用:
#include
int main() {
char str[] = "John 25";
char name[20];
int age;
// 从字符串中读取姓名和年龄
sscanf(str, "%s %d", name, &age);
// 打印姓名和年龄
printf("Name: %s\n", name);
printf("Age: %d\n", age);
return 0;
}
② 修饰符
大体都是遇到空格停止匹配,取反符除外
-
%[...]
:用于指定要匹配的字符集合。例如
%[a-zA-Z]
将匹配a-z以及A-Z的字母字符。 -
%*...
:用于忽略输入中的某些数据例如:
%*d
将跳过一个整形,其它的也如此 -
%[width]...
:只匹配前width个的字符例如:
%4s
,只获取前4个字符 -
%[^...]
,取非,匹配除这个外的所有,包括空格例如
%[^aFc]
匹配非aFc的任意字符,包括空格
运用:
#include
#pragma warning(disable:4996)
int main() {
char str[20];
//跳过非#号的,再跳过一个字符,最后获取非@的字符,遇到@停下
sscanf("abc#def@ghi", "%*[^#]%*c%[^@]", str);
printf("%s", str);
}
十一.Const
1.概述
const
是C中的关键字,用于定义常量、指定常量指针、以及声明不可修改的变量。
2.使用
(1)定义常量
① 概述
const
关键字修饰的变量将变成常量,创建时赋值,赋值后不允许修改
② 例子
创建一个名为 MAX_VALUE
的常量,其值为 100。在程序的其他部分中,不允许修改 MAX_VALUE
的值。
const int MAX_VALUE = 100;
(2)修饰指针
① 指定常量指针
**概述:**常量指针可以指向内存中的数据,但不能通过它来修改内存中的数据
const int *ptr;
② 指向字符常量的指针
**概述:**可以通过这个指针访问、修改其指向的只,但不能修改指针的指向
char * const str
③ 指向常量字符常量的指针
**概述:**指针本身是不可修改的,而且它所指向的字符串也是不可修改的
const char * const str