dw如何用表格做网站,网站建设结构图下载,wordpress 调用评论,wordpress提速插件文章目录 目录
一、strlen 的使用和模拟实现
二、strcpy 的使用及模拟实现
三、strcat 的使用和模拟实现
四、strcmp 的使用和模拟实现
五、strncpy 的使用和模拟实现
六、strncat 的使用和模拟实现
七、strncmp 的使用和模拟实现
八、strstr 的使用和模拟实现
九、st… 文章目录 目录
一、strlen 的使用和模拟实现
二、strcpy 的使用及模拟实现
三、strcat 的使用和模拟实现
四、strcmp 的使用和模拟实现
五、strncpy 的使用和模拟实现
六、strncat 的使用和模拟实现
七、strncmp 的使用和模拟实现
八、strstr 的使用和模拟实现
九、strtok函数的使用
十、strerror 函数的使用
2.补充perror 函数的使用 前言 本文介绍和模拟实现的字符串函数有strlen、strcpy、strcat、strcmp、strncpy、strncat、strncmp、strstr。另外详细介绍了 strtok 、strerror、perror函数的使用。基本囊括了所有常用的字符串函数。模拟实现有助于我们理解和记忆这些库函数我们都能够自己实现这些库函数使用时需要注意的细节我们肯定也更加清楚和深刻。最后希望本文的内容能够帮助到大家更好的理解这些库函数 注意字符串函数包含的头文件都为 string.h 一、strlen 的使用和模拟实现 1.使用 功能strlen 函数其功能相信大家很熟悉了就是计算字符串的长度 函数声明size_t strlen ( const char * str ); 用法传入字符串首字符的地址计算出的结果将以 size_t 类型返回 size_t 是一种无符号整形是为了代码的可移植性而定义的一种自定义类型使用 %zd 打印 使用演示
#include stdio.h
#include string.hint main()
{char ch1[] { abcdefg };char* ch2 qwertyuiop;printf(%zd\n, strlen(ch1));printf(%zd\n, strlen(ch2));return 0;
}
运行结果 解疑上述ch1是数组名表示数组首元素地址ch2是字符指针指向的是一个字符串字面量的首字符地址 2.模拟实现 想要模拟实现 strlen 我们就应该了解其机制strlen 就是通过寻找字符串结尾处的 \0 字符来计算字符串的长度的像我们平时写在双引号中的字符串其末尾自动包含了一个\0我们也可以在定义字符数组的时候在其末尾手动添加 \0只有包含了 \0的字符串才能被strlen正确的计算长度 以下演示三种 strlen 的模拟实现
以下所以代码中包含了 assert 函数其为断言用来检查指针是否为空详细请移步主页指针基础知识其中有详细讲解 1边寻找 \0 边统计字符
#include stdio.h
#include assert.hsize_t my_strlen(const char* str)
{assert(str ! NULL);size_t count 0;while (*str){str;count;}return count;
}
2通过指针相减算出元素个数
#include stdio.h
#include assert.hsize_t my_strlen(const char* str)
{const char* str1 str;assert(str ! NULL);while (*str1){str1;}return str1 - str;
}
3使用递归实现
size_t my_strlen(const char* str)
{assert(str ! NULL);if (*str \0){return 0;}else{return 1 my_strlen(str 1);}
}二、strcpy 的使用及模拟实现 1.使用 功能将源字符串拷贝到目标字符串之中返回目标字符串首地址 函数声明char * strcpy ( char * destination, const char * source ); 用法按顺序先传入目标字符串再传入源字符串最后 strcpy 返回的目标字符串首地址另外函数有以下几个要求和细节 源字符串必须以 \0 结束。会将源字符串中的 \0 拷贝到目标空间。目标空间必须足够⼤以确保能存放源字符串。目标空间必须可修改。因此目标字符串参数没有使用const修饰 使用演示
#include stdio.h
#include string.hint main()
{char ch1[20] { xxxxxxxxxxxxx };char* ch2 abcdefg;char* ret strcpy(ch1, ch2);printf(%s\n, ch1);printf(%s\n, ret);return 0;
}
运行结果 解疑值得注意的是ch2中的\0也会被拷贝到ch1中我们可以通过调试观察到 另外目标字符串小于原字符串将导致报错 2.模拟实现
#include stdio.h
#include assert.hchar* my_strcpy(char* dest, const char* src)
{assert(dest src);char* ret dest;while (*dest *src){;}return ret;
}
解疑这里面比较难理解的估计就是这个while循环*dest *src首先 的优先级高于 *因此先执行但因为是后置先使用后因此会先解引用将src的值赋给dest然后两字符串地址向后走一个字节长度来到下一个字符的地址依次循环下去最后 src 解引用遇到\0赋值给dest后整个表达式值为0循环停止注意循环体为空语句。最后包括\0在内的所有字符都从src中拷贝到了dest中最后的最后返回目标字符串首地址 三、strcat 的使用和模拟实现 1.使用 功能将源字符串追加到目标字符串的末尾 函数声明char * strcat ( char * destination, const char * source ); 用法先传入目标字符串首地址再传入源字符串首地址追加后返回目标字符串首地址 有以下需要注意的细节和要求 源字符串必须以 \0 结束。目标字符串中也得有 \0 否则没办法知道追加从哪里开始。目标空间必须有足够的大能容纳下源字符串的内容。目标空间必须可修改。 使用演示
#include stdio.h
#include string.hint main()
{char ch1[20] { abcdef };char ch2[] { qwerty };char* ret strcat(ch1, ch2);printf(%s\n, ch1);printf(%s\n, ret);return 0;
}
2.模拟实现 2.模拟实现
#include stdio.h
#include assert.hchar* my_strcat(char* dest, const char* src)
{assert(dest src);char* ret dest;while (*dest){dest;}while (*dest *src){;}return ret;
}
解疑第一个while循环用来定位 dest 中\0位置也就是dest中第一次出现\0的位置第二个循环与前面 strcpy 一样将源字符串src内容拷贝到目标字符串dest中只不过是接在dest第一个\0的位置处最后返回目标字符串首地址 另外考虑一个问题问strcat 能不能给自己追加自己
我们使用自己模拟的strcat试一试 结果是不可以因为 src 追加后使得自己变长永远到不了\0结果就会导致死循环
官方的库函数却可以但其返回值也不可以底层逻辑的实现不同这里不再深究 四、strcmp 的使用和模拟实现 1.使用 功能比较两字符串大小不是比较长度而是按顺序比较每一位对应字符的ASCII码值 函数声明int strcmp ( const char * str1, const char * str2 ); 用法分别传入需要比较的字符串首地址strcmp 会比较两字符串的对应位字符的ASCII码值其返回值分为三种 返回值 0表示 str1 中某一位字符大于 str2 对应位的字符返回值 0表示 str1 中某一位字符小于 str2 对应位的字符返回值 0表示 str1 与 str 2完全相同 使用演示
#include stdio.h
#include string.hint main()
{char* ch1 abcdefg;char* ch2 abcz;int ret strcmp(ch1, ch2);printf(%d\n, ret);return 0;
}
运行结果 解疑在vs中strcmp三种返回值为10-1对应的三种情况但C语言标准中是按照大于0小于0等于0分的。上图结果为-1因为ch2中的第四个字符为 z大于ch1中第四个字符 d因此判定ch1小于ch2返回-1。也就是返回0的值 2.模拟实现
#include stdio.h
#include assert.hint my_strcmp(const char* str1, const char* str2)
{assert(str1 str2);while (*str1 *str2){if (*str1 \0){return 0;}str1;str2;}return *str1 - *str2;/*if (*str1 *str2){return 1;}else{return -1;}*/
}
解疑首先while循环判断两字符串对应位置字符是否相同相同就进入循环在进行判断如果其中有一个字符为\0表示这两个字符走到头了并且完全相等返回0如果没有就使两字符串地址向后走一位再进行循环判断如果两字符串对应位字符不相等就跳出循环直接令这两个字符串对应位置的字符相减其返回值就能判断两字符串的大小也可以使用分支判断两字符串使其返回1或-1如代码中注释的部分 五、strncpy 的使用和模拟实现 1.使用 功能拷贝指定个数的字符从源字符串到目标字符串上 函数声明char * strncpy ( char * destination, const char * source, size_t num ); 用法和 strcpy 相比多了一个参数 num用来指定复制多少个字符有以下几点需要注意 如果源字符串的长度小于num则拷贝完源字符串之后在目标的后边追加0直到num个。如果原字符串的长度大于num则只拷贝num个字符到目标文件中目标文件中如果有数据将会被覆盖并且不会追加\0。目标字符串的容量必须足够大能存放下拷贝的字符 使用演示
#include stdio.h
#include string.hint main()
{char ch1[10] { xxxxxxxxx };char ch2[] { abcdef };char* ret strncpy(ch1, ch2, 9);printf(%s\n, ch1);printf(%s\n, ret);return 0;
}运行结果 监视窗口 解疑上述代码符号第一种情况即如果源字符串的长度小于num则拷贝完源字符串之后在目标的后边追加0直到num个。 2.模拟实现
#include stdio.h
#include string.h
#include assert.hchar* my_strncpy(char* dest, char* src, size_t num)
{assert(dest src);char* ret dest;size_t len strlen(src);int count (int)num - (int)len;while (num *src){*dest *src;dest;src;num--;}while (count 0){*dest 0;dest;count--;}return ret;
}
解疑以上的实现是我个人的想法不是最优解。首先除了保存目标字符串首地址计算了源字符串大小并保存了num与源字符串长度的差值第一个while循环在保证拷贝没有超过 num 个字符和原字符串没有走到结尾的情况下拷贝了能拷贝的字符。然后下面一个while循环用来判断 num是否大于源字符串长度如果大于则在目标字符串末尾补0。直至刚好拷贝完num个字符最后返回目标字符串首地址。 六、strncat 的使用和模拟实现 1.使用 功能将源字符串的前num个字符追加到目标字符串指向的字符串末尾再追加⼀个\0字符 函数声明char * strncat ( char * destination, const char * source, size_t num ); 用法前两个参数与strcat一致也是后面多了一个num用来指定追加多少个字符。这里需要注意的有以下几条 如果 source 指向的字符串的长度小于num的时候只会将字符串中到 \0 的内容追加到destination指向的字符串末尾。大于num的话就是源字符串的前num个字符追加到目标字符串指向的字符串末尾再追加⼀个\0字符目标字符串的容量得足够大能容下追加的字符 使用演示
#include stdio.h
#include string.hint main()
{char ch1[20] { abcd\0xxxxxxxx };char* ch2 qwerty;char* ret strncat(ch1, ch2, 8);printf(%s\n, ch1);printf(%s\n, ret);return 0;
}
运行结果 监视窗口 解疑以上代码就符合num大于源字符串长度的情况即 source 指向的字符串的长度小于num的时候只会将字符串中到 \0 的内容追加到destination指向的字符串末尾。为了方便观察我在ch1中插入了\0和xxxxxxxx最后发现末尾确实追加了一个\0字符。 2.模拟实现
#include stdio.h
#include assert.hchar* my_strncat(char* dest, const char* src, size_t num)
{assert(dest src);char* ret dest;while (*dest){dest;}while (num *src){*dest *src;dest;src;num--;}*dest \0;return ret;
}
解疑前面步骤与strcat一致到了第二个while循环也是在保证没有追加超过num个字符和源字符串地址没有走到字符串末尾的情况下追加所有能追加的字符然后无论 num 大于或者小于 源字符串长度只需要追加一个\0即可。最后返回目标字符串首地址。 七、strncmp 的使用和模拟实现 1.使用 函数声明int strncmp ( const char * str1, const char * str2, size_t num ); 功能及用法比较str1和str2的前num个字符如果相等就继续往后比较最多比较num个字母如果提前发现不一样就提前结束大的字符所在的字符串大于另外⼀个。如果num个字符都相等就是相等返回0。返回值情况与strcmp一致 使用演示
#include stdio.h
#include string.hint main()
{char* ch1 abcde;char* ch2 abcqwer;int ret1 strncmp(ch1, ch2, 3);int ret2 strncmp(ch1, ch2, 5);printf(%d\n, ret1);printf(%d\n, ret2);return 0;
}运行结果 解疑基本和strcmp一样只是多了指定比较的个数 2.模拟实现
#include stdio.h
#include assert.hint my_strncmp(const char* str1, const char* str2, size_t num)
{assert(str1 str2);while ((*str1 *str2) num){if (*str1 \0){return 0;}str1;str2;num--;}if (*str1 *str2){return 0;}else if (*str1 *str2){return 1;}else{return -1;}
}
解疑模拟过程与strcmp相比while循环多了一个num的判断最后的条件判断也多了一条判断相等的情况因为while循环的终止可能是由于num等于0的情况此时需要再对字符串进行一次比较。 八、strstr 的使用和模拟实现 1.使用 功能在一个字符串中寻找与另一个字符串完全相同的片段 函数声明char * strstr ( const char * str1, const char * str2 ); 用法传入两个字符串的首地址函数返回字符串str2在字符串str1中第一次出现的位置的地址如果找不到就返回空指针(NULL)。 使用演示
#include stdio.h
#include string.hint main()
{char ch1[] This is a simple string;char ch2[] simple;char* ret strstr(ch1, ch2);printf(%s\n, ret);return 0;
}
运行结果 解疑因为函数返回的是str2字符串内容在str1中第一次出现时的地址所以我们以%s打印时会从这个地址一直打印到str1字符串末尾遇到\0停止 2.模拟实现
#include stdio.h
#include assert.h
#include string.hchar* my_strstr(const char* str1, const char* str2)
{assert(str1 str2);const char* s1 NULL;const char* s2 NULL;const char* cur str1;if (*str2 \0){return (char*)str1;}while (*cur){s1 cur;s2 str2;while (*s1 *s2 *s1 *s2){s1;s2;}if (*s2 \0){return (char*)cur;}if (strlen(cur1) strlen(str2)){return NULL;}cur;}return NULL;
}
解疑
首先创建了三个指针变量s1,s1分别用来记录str1和str2比较过程中的地址cur记录的是str1当前位置的地址因为途中的比较过程会打乱str1指针的指向因此需要cur来记录str1当前位置的地址以便s1在比较过程中没有找到相同字符串时可以通过cur找回起始位置。而str2本身指向是不会变的因此不需要另外的指针进行记录当前位置。 if (*str2 \0) 这个意思是如果str2是个空字符串的话直接返回str1的地址这是C语言标准中strstr的规定。并且空字符串本身也不需要寻找任何字符串都包含空字符串while (*cur) 这个循环条件就是cur没有指向字符串末尾。然后给s1赋值为curs2赋值为str2,。s1,s2就是用来比较判断两字符串是否有相同的指针。while (*s1 *s2 *s1 *s2)这个循环意思是只要s1,s2没有指向字符串末尾并且它两指向的字符相等就让s1,s2一直往后走只要有其中一个条件不满足时循环就终止循环终止后就进行一个判断if (*s2 \0)该判断的意思是如果s2等于\0表示前一个循环是因为s2走到字符串末尾而终止的s2能走到末尾就表示s2前面的字符与s1都相同这就表明能在str1中找到str1此时只需要终止函数返回cur也就是str1当前的地址就行而如果s1指向的字符不为\0就表示前一个循环的终止是因为s1,s2指向的字符不相同导致的就再进行一个判断if (strlen(cur1) strlen(str2))这个判断表示当前str1指向的下一个位置到字符串末尾的长度如果小于str2的长度就表明str1后面一定找不到str2了为了提高效率直接返回空指针。如果两个判断都不满足就让str1当前的位置往后走一步也就是cur再进行循环判断。如果直到最后cur都指向\0了就直接返回空指针。 九、strtok函数的使用 功能将一个字符串以指定字符的格式分隔 函数声明char * strtok ( char * str, const char * sep ); 用法第一个参数指向了一个字符串第二个参数指向了需要分隔的字符的集合并且有以下要求和细节 第一个参数指定一个字符串它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。简单来说就是str中可能有sep包含的字符sep参数指向一个字符串定义了用作分隔符的字符集合strtok函数找到str中的下一个标记字符(sep)并将其用 \0 结尾返回一个指向这个标记的指针。注 strtok函数会改变被操作的字符串所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。第一次调用strtok函数的第⼀个参数不为 NULL 函数将找到str中第一个标记字符strtok函数将保存它在字符串中的位置下一次调用strtok函数的第一个参数为 NULL 函数将在同一个字符串中被保存的位置开始查找下一个标记简单来说就是 strtok 具有保存记忆的功能如果第一个参数传入NULLstrtok能记起同一个字符串上一次被分隔的位置如果字符串中不存在更多的标记则返回 NULL 指针。 使用演示
#include stdio.h
#include string.hint main()
{char ch1[] abcd.bbc/123xp;char ch2[] ./;printf(第一次分割\n);char* ret strtok(ch1, ch2);printf(%s\n, ret);printf(%s\n, ch1);printf(第二次分割\n);ret strtok(NULL, ch2);printf(%s\n, ret);printf(%s\n, ch1);printf(第三次分割\n);ret strtok(NULL, ch2);printf(%s\n, ret);printf(%s\n, ch1);printf(第四次分割\n);ret strtok(NULL, ch2);printf(%s\n, ret);printf(%s\n, ch1);printf(第五次分割\n);ret strtok(NULL, ch2);printf(%s\n, ret);printf(%s\n, ch1);return 0;
}运行结果 解疑第一次分割将字符.修改为\0返回了起始地址也就是字符a的地址因为改变了源字符串的数据所以此后以%s打印ch1只能打印abcd。第二次分割将字符/修改为\0然后返回了第二段起始地址也就是字符b的地址。后面的结果依次类推就行。直到最后没有可分割字符返回空指针
是不是发现上面有大量重复的代码其实我们可以使用循环来进行打印
#include stdio.h
#include string.hint main()
{char str[] 123.4545.446.xpashisdidqq.com;char* sep .;for (char* ret strtok(str, sep); ret ! NULL; ret strtok(NULL, sep)){printf(%s\n, ret);}return 0;
}
运行结果 解疑以上for循环使用地非常巧妙首先初始化部分调用一次strtok传入需分割的字符串和分割字符。创建一个ret接收strtok的返回值因为for循环初始化部分只会进行一次。所以该部分不会重复进行然后判断部分写 ret ! NULL只要返回值不为空指针循环就不终止。for调整部分写再一次调用strtok传入空指针即可。strtok具有记忆保存的属性。如此一来就实现了循环分割打印的效果 十、strerror 函数的使用 1.使用 功能接收并记录程序运行时的错误码返回错误码对应的错误信息的字符串地址 函数声明char * strerror ( int errnum ); 功能介绍在不同的系统和C语言标准库的实现中都规定了一些错误码一般是放在 errno.h 这个头文件中说明的C语言程序启动的时候就会使用一个全局的变量errno来记录程序的当前错误码只不过程序启动的时候errno是0表示没有错误当我们在使用标准库中的函数的时候发生了某种错误就会将对应的错误码存放在errno中而一个错误码的数字是整数很难理解是什么意思所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。 打印0~10错误码对应的信息
#include stdio.h
#include string.h
#include errno.hint main()
{int i 0;for (i 0; i 10; i){printf(%s\n, strerror(i));}return 0;
}运行结果 注不包含 errno.h 头文件也可以打印 使用演示
#include stdio.h
#include string.hint main()
{FILE* pf fopen(xxx.txt, r);if (pf NULL){printf(%s\n, strerror(errno));}return 0;
}
运行结果 解疑定义一个文件指针以只读的形式打开一个不存在的文件pf会接收到一个空指针此时这个文件打开错误会被记录使用if判断然后打印出这个错误信息这在我们日常写代码中非常实用。另外记住使用strerror时要传参errno 2.补充perror 函数的使用 函数声明void perror ( const char * str ); 功能介绍perror与strerror类似都是记录错误信息但是不同的是 perror使用时会直接打印出错误信息不需要向strerror那样使用printf进行打印。perror的参数指我们可以自己添加一个需要打印的字符串信息在错误信息的前面perror函数包含在 stdio.h 头文件中 使用演示
#include stdio.hint main()
{FILE* pf fopen(xxx.txt, r);if (pf NULL){perror(fopen);}return 0;
}
运行结果 解疑如图所示我们传入perror的字符串参数最终会加上:打印在屏幕上我们传入的字符串可以提醒我们哪里或者哪个函数出的问题。更加的方便和实用 关于strerror与perror函数的选择是根据自己的情况而定只记录不打印选择strerror只打印选择perror即可 总结 以上就是本文的全部内容了希望对大家有所帮助感谢支持