文章目录
前言
-
本篇博客的内容来源有c prime puls,
(抄书的 ),加上鹏哥的视频(我是白嫖党),再加上自己的一些总结。在这里附上本书的pdf文件:链接:https://pan.baidu.com/s/1frLUTJfrjT4mLsQ7wERBnQ?pwd=3nsm
提取码:3nsm -
由于大部分的字符串函数都位于< string.h >头文件中,所以在介绍各个函数时不会指出。
-
destination指针简写为dest,其指向的字符串用“第一个字符串”表示
source指针简写为src,其指向的字符串用“第二个字符串”表示 -
本人才疏学浅,能力有限,如有疏漏,还望各位大佬指出
1、strlen函数
(1)、介绍strlen函数
- strlen函数用于统计字符串的长度,碰到’\0’后停止计数。
函数原型
(2)、使用strlen函数时的常见错误
strlen统计的是字符串的长度
int main(){
char arr1[]="abcdef";
char arr2[]={'a','b','c','d','e','f'};
int n = strlen(arr1); //在vs2022上的运行结果:n=6
int m = strlen(arr2); //m=33
int i = strlen(*arr2); //error
}
strlen函数的返回值类型是size_t类型
请看以下代码
int main() {
if (strlen("abc") -strlen("abcdef")>0 ){
printf(">\n");
}
else {
printf("<\n");
}
}
大家觉得答案是什么呢,是不是觉得会打印 “<“呢。
其实打印的是”>”。
因为strlen函数返回值类型是无符号整形,两个无符号整形数做运算,其结果依然是无符号整形数。
无符号整形数:可以简单理解为正数
(3)、模拟实现strlen函数
这里提供三个版本的实现方式
计数器的版本
int my_strlen(const char* str) {
int count = 0;
assert(str != NULL); //断言str不为空指针,是代码更安全
while (*str) // \0的asc2码值为0,如果*str=\0,循环结束
{
count++;
str++;
}
return count;
}
指针-指针的版本
//指针-指针的值为两个指针之间的元素个数,
int my_strlen(char* str) {
char* start = str;
while (*str) {
str++;
}
return str - start;
}
递归的版本
int my_strlen(char* str) {
if (*str == '\0') {
return 0;
}
else {
return 1 + my_strlen(str+1);
}
}
2、strcpy函数
(1)、 引入strcpy函数
如果要把arr1的存放内容改为字符串"HQUer"
int main(){
char arr1[10]={1,2,3,4,5};
arr1="HQUer"; //error
}
以上的代码不能完成我们的目标。因为数组名为首元素的地址,地址显然不能为字符串。完成目标的一种方法就是用strcpy函数。
(2)、预备知识(字符串常量)
- 用双引号括起来的内容被称为字符串字面量(也叫做字符串常量),如 “Hello HQUer”.
- 双引号内的字符和编译器自动加上的\0字符,都作为字符串存储在内存中。
- 字符串常量属于静态存储类别,这表明在函数里使用字符串常量,该字符串只会存储一次
- 最重要的:字符串字面量被视作const数据。如果用指针ptr指向它,就意味着不能用ptr改变这个字符串字面量,但是仍然可以改变ptr的值(即改变ptr指向的位置)。 如 char* ptr =“###”; *ptr = “ABC”; //error
(3)、介绍strcpy函数
函数原型
翻译成中文
strcpy接受两个字符串的指针为参数。
strcpy函数会将src指针指向的字符串(为了表示方便我们称它为源字符串)复制到dest指针指向的数组里(了表示方便我们称它为目标空间)
注:dest指针不一定要指向数组的开始,这个属性可以用于拷贝数组的一部分。 如strcpy(arr1+2,arr2) 这么写是可以的
(4)、使用strcpy函数的注意事项
- 目标空间必须足够大,以确保能存放源字符串
- 目标空间必须可变 (不能是字符串常量)
- 源字符串必须以\0结束
- 会将源字符串的\0拷贝到内存空间
因此,我们可以写出几个BUG
#include<string.h>
int main(){
char arr[10]="#########";
char arr1[5]={'a','b','c','d','e'}; //没有以\0结束
char arr2[20]="take a seat" //源字符串大于目标空间
char* str = "******"; //目标空间是字符串常量,不能变化
strcpy(arr,arr1) // error
strcpy(arr,arr2) //error
strcpy(str,arr); //error
}
大家以后不要犯类似的错误啊。
(5)、模拟实现strcpy函数
char* my_strcpy(char* dest, const char* src) //用const修饰,防止src被修改
{
char* ret = dest; //记录dest的首地址
assert(dest && src); //防止dest和src为空指针
while (*dest++ = *src++)
{
;
}
return ret;
}
3、strcmp函数
(1)、引入strcmp函数
如果我们要比较两个字符串是否相等,可以直接用==比较吗?
#include<stdio.h>
int main(){
char arr1[10] = "abcd";
char arr2[10] ="abcd";
if(arr1==arr2){
printf("right");
}else{
printf("false");
}
}
不行,输出的结果不是我们想要的。
原因: arr1和arr2都是首元素的地址,所以arr1==arr2检查的不是arr1和arr2的内容是否相同,而是检查这两个字符串的地址是否相同。而两个数组的地址一定不相同,所以这个表达式恒为假。
(2)、strcmp函数的功能
函数原型
这个函数会比较str1和str2所指向的字符串的大小(本质上是比较两个字符串的asc2码值)。
- 具体比较方法:首先,这个函数会比较两个字符串的首个字符。如果首个字符不相等,就结束比较并返回一个值。如果首个字符相等,就比较下一个字符。
- 何时比较结束:当比较的两个字符不相等或者比较到空字符时,结束比较并返回一个值
- 返回值:返回的是整数。1. 当str1指向的字符的asc2码值>str2指向字符的asc2码值时,返回正数。2. 当str1指向的字符的asc2码值<str2指向字符的asc2码值时,返回负数。3、否则返回0(就是两个字符串相等的时候)
(3)、模拟实现strcmp函数
先用伪代码明确一下思路
然后我们模拟实现strcmp函数
int my_strcmp(const char* s1,const char* s2) {
assert(s1&&s2); //保证代码的健壮性
while (*s1==*s2) {
if (*s1=='\0') {
return 0;
}
s1++;
s2++;
}
/*if (*s1>*s2) {
return -1;
}
else if (*s1<*s2) {
return 1;
}*/
return *s1 - *s2; //上面注释的语句可以简化为这一行
}
4、strcat函数
(1)、介绍strcat函数
函数原型
翻译成中文:
strcat函数接受两个字符串的指针为函数参数 ,把源字符串复制到目标字符串后面,返回源字符串的地址,同时,目标字符串内容不变。
(2)、模拟实现strcat函数
void my_strcat(char* dest,char* src) {
//1、找目标字符串的\0
while (* dest) {
dest++;
}
//2、追加源字符串
while (*dest++=*src++) {
;
}
}
5、strstr函数
(1)、介绍strstr函数
函数原型
翻译:在str1字符串中寻找str2字符串的位置。如果找到了,返回str2第一次出现在str1的位置,如果找不到,返回空指针。
(2)、模拟实现strstr函数
因个人水平,画不出图解……☹
#include<assert.h>
char* my_strstr(const char* str1,const char* str2) {
assert(str1&&str2); //只有老司机才这么写
const char* s1 = NULL;
const char* s2 = NULL;
//可以更改指针指向的对象,但不能直接更改指针的内容
char* cp = str1; //cp指向第一个字符串的第一个字符
while (*cp)
{
s1 = cp;
s2 = str2;
//上面两行相当于每一次查找前的初始化
if (*str2 =='\0') //如果第二个字符串为\0
{
return str1;
}
while (*s1 && *s2 &&(*s1==*s2))
//当s1和s2指向的字符都相等且不为\0
{
s1++;
s2++;
}
if(*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;
}
6、7、8 strncpy strncmp strncat 函数
我们可以对上面的函数进行分类,
把strcpy strcmp strcat函数归为长度不受限制的字符串函数
把strncpy strncmp strncat函数归为长度受限制的字符串函数
(1)、函数原型
为什么要有这几个函数呢?因为strcat,strcpy函数都不能检查目标空间能否容纳源字符串,用strncat和strncpy会更加安全。
(2)、strncpy函数
函数的第三个参数(num)表示拷贝的最大字符个数。
注:strcpy拷贝的字符串长度不会超过num,如果拷贝到第num个字符时还没有拷贝完整个源字符串,那么就不会拷贝空字符。
(3)、strncat函数
函数的第三个参数(num)表示添加的最大字符个数
举例说明: strncat(arr1,arr2,10);
表示将arr2字符串的内容附加给arr1字符串,直到第10个字符或者空字符时停止。(空字符一定会添加)。 所以,arr1数组的空间一定要足够。
(4)、strncmp函数
用strncmp函数比较两个字符串时,只比较到第三个参数指定的字符数。
还有一些字符串函数,如strtok函数,strerror函数,就不细讲了。
好了,大家学会了吗? 我们下次再见。