strncpy
的自我实现
#include <stdio.h> #include <assert.h> #include <string.h> char* my_strncpy(char* dest, const char* src, int n) { assert(dest && src); char* ret = dest; // 这里求src的长度是为了解决拷贝个数大于源字符串的长度 + 1的情况 // 每拷贝一个lenSrc--,当 lenSrc == 0,而 n != 0,此时应该在后面拷贝\0直至n == 0; // 因为字符串后面还有一个\0,要把他算在内,所以lenSrc要等于长度 + 1; int lenSrc = (int)strlen(src) + 1; while (n--) { if (!lenSrc) // 当lenSrc为0时,!lenSrc为真,后面拷贝\0直至 n == 0; { *dest++ = '\0'; } else { *dest++ = *src++; lenSrc--; // 每拷贝一次源字符串的内容,lenSrc--; } } return ret; } int main() { char arr1[20] = "xxxxxxxxxxxxxxxx"; char arr2[] = "abcdef"; printf("%s\n", my_strncpy(arr1, arr2, 5)); return 0; }
strncat
该函数的功能就是指定在目的地字符串后面追加(连接)源字符串的几个字符,其注意事项与
strcat
差不多,由于长度受限制,所以追加的形式与strcat
也会不同。
strncat
的使用
1.目的地字符串只有末尾有\0
:
#include <stdio.h> #include <string.h> int main() { char a1[20] = "xxxxxxxxxxx"; char a2[] = "abcdef"; printf("%s\n", strncat(a1, a2, 4)); return 0; }
运行结果为:xxxxxxxxxxxabcd
2.目的地字符串中间也有\0
:
#include <stdio.h> #include <string.h> int main() { char a1[20] = "xxx\0xxxxxxx"; char a2[] = "abcdef"; printf("%s\n", strncat(a1, a2, 5)); return 0; }
运行结果为:xxxabcde
可以发现,当追加完所定个数的字符后,会在此的后面自动追加一个\0
(打印的时候遇到\0
停止可确定)。
3.当追加的个数大于源字符串的长度时,将源字符串追加过去后便停止追加:
#include <stdio.h> #include <string.h> int main() { char a1[20] = "xxxx"; char a2[] = "abcdef"; printf("%s\n", strncat(a1, a2, 8)); return 0; }
运行结果为:xxxxabcdef
strncat
的自我实现
了解到上面函数的功能后,接下来就将这些功能实现成
strncat
函数
- 核心功能:
1.追加完后自动再追加一个\0;
2.目的地字符串先找\0;
3.源字符串整个追加完后停止追加;
4.追加的代码;
#include <stdio.h> #include <assert.h> #include <string.h> char* my_strncat(char* dest, const char* src, int n) { assert(dest && src); char* ret = dest; int lenSrc = (int)strlen(src); // 目的地字符串先找\0 while (*dest) { dest++; } while (n) { // 如果整个源字符串追加完了此时 n != 0,在后面追加一个\0,停止追加 if (!lenSrc) { *dest++ = '\0'; break; } else { *dest++ = *src++; lenSrc--; } n--; } // 如果n == 0也就是说要追加的追加完了,在后面再追加一个\0 if (n == 0) *dest = '\0'; return ret; } int main() { char a1[20] = "xxxxxxx"; char a2[] = "abcdef"; printf("%s\n", my_strncat(a1, a2, 8)); return 0; }
strncmp
该函数功能是指定两个字符串多少对字符进行对比,对比的方式与
strcmp
函数相同。
strncmp
的使用
#include <stdio.h> #include <string.h> int main() { char a1[] = "abcdef"; char a2[] = "abcdq"; printf("%d\n", strncmp(a1, a2, 5)); return 0; }
当比对到e
和q
时 e的ASCLL
码值小于q
的ASCLL
码值,所以打印小于零的数,如果第三个参数为4
,则返回0
,也就要打印0
。
strncmp
的自我实现
这里是按照vs的标准来实现的,也就是比对小于返回-1,比对大于返回1,等于返回0;
#include <stdio.h> #include <assert.h> int my_strncmp(const char* str1, const char* str2, int n) { assert(str1 && str2); while (n--) { if (*str1 - *str2) { if (*str1 < *str2) return -1; else return 1; } str1++; str2++; } // n个都比对完了,而前面没有返回(比对都相同),说明这n个相等 return 0; } int main() { char a1[20] = "abc"; char a2[] = "abcgdef"; printf("%d\n", my_strncmp(a1, a2, 3)); // 1:a1 > a2 // 0:a1 == a2 // -1:a1 < a2 return 0; }
3.字符串查找
strstr
该函数功能实际上是判断一个字符串是否是另一个字符串的子串,例如字符串s1 = “iou”,字符串s2 = “youioume?”,s2中间出现了iou这样的子串,所以该函数返回i的地址,打印出来也就是ioume?。
返回指向 str2
中指定的整个字符序列在 str1
中首次出现
的指针,如果字符序列str2
在 str1
中不存在,则返回 null
指针。
strstr
的使用
#include <stdio.h> #include <string.h> int main() { char arr1[] = "abcdef"; char arr2[] = "bcde"; char arr3[] = "bcb"; printf("%s\n", strstr(arr1, arr2)); printf("%s\n", strstr(arr1, arr3)); return 0; }
运行结果为: bcdef (null)
strstr
的自我实现
strstr
的自我实现相对较难,这里我用暴力解法。定义三个指针cur ,s1,s2,cur为开始匹配的位置(匹配成功好返回),s1与s2是比对指针。
什么时候停止匹配返回NULL呢?
1.当*cur为\0时停止
2.当从cur位置开始后面的字符个数小于str2的字符个数时停止(strlen(cur)< strlen(str2));
代码实现:
#include <stdio.h> #include <string.h> #include <assert.h> char* my_strstr(const char* str1, const char* str2) { assert(str1 && str2); if (*str2 == '\0') return (char*)str1; const char* s1 = NULL; const char* s2 = NULL; const char* cur = str1; while (*cur) { s1 = cur; s2 = str2; while (!(*s1 - *s2) && *s1 && *s2) { s1++; s2++; } if (!*s2) // 如果上面的循环停止是因为*s2 == \0,那么匹配成功 return (char*)cur; if ((int)strlen(cur) < (int)strlen(str2)) return NULL; cur++; } return NULL; } int main() { char arr1[] = "abbbce"; char arr2[] = "bbc"; printf("%s\n", my_strstr(arr1, arr2)); return 0; }
运行结果为:bbce
strtok
这个函数的功能通俗来说是分割字符串,在一个字符串内输入需要在此字符分割的字符,例如
“@.”
,也就是说在另一个字符串里,要找到@
和.
并在此字符的位置对该字符串进行分割。
函数参数介绍:
strtok
的使用
- 当我们第一次传参时,将要分割的字符串和确定分割的字符的字符串传过去,第一次分割好后,
strtok
函数会自动记住分割的位置,下一次我们要继续调用这个函数,不过函数第一个参数要传NULL(因为strtok自动记住了第一次分割的位置),直到要分割的字符串中没有要分割的字符,此时返回一个 NULL,停止分割。- 这里我们可以用一个fou循环来进行分割,当最后返回一个NULL的时候表示分割结束,循环结束。
#include <stdio.h> #include <string.h> int main() { char a1[] = "I@love.you"; char a2[] = "@."; char* ret = NULL; for (ret = strtok(a1, a2); ret != NULL; ret = strtok(NULL, a2)) { printf("%s\n", ret); } return 0; }
4.错误信息报告
strerror
- 该函数的功能相当于是报错误,如果我们在实现某个功能的时候,怕这个程序出现问题,这时我们可以if(如果怎么怎么样),就报一个错误(用strerror),当然学习这个函数还要认识另一个函数,那就是errno(对应头文件为(errno.h))errno:C语言的库函数在运行的时候,如果发生错误,就会将错误码存在一个变量中,这个变量> 是:errno,这时我们用strerror将其输出,就可以得到错误信息。
- 当然有一些错误码是一些数字:1 2 3 4 5
- 我们也可以将这些数字作为strerror函数的参数输出,这时需要将错误码翻译成错误信息然后再输出。
strerror
的使用
1.数字错误码:
#include <stdio.h> #include <string.h> int main() { printf("%s\n", strerror(0)); printf("%s\n", strerror(1)); printf("%s\n", strerror(2)); printf("%s\n", strerror(3)); printf("%s\n", strerror(4)); printf("%s\n", strerror(5)); return 0; }
2.errno
对应的使用:
这里开开辟一个巨大的空间,如果开辟失败,就会返回NULL,然后就会输出对应的错误信息(为什么开辟失败)。
#include <stdio.h> #include <string.h> #include <errno.h> // 使用errno所需头文件 #include <stdlib.h> int main() { int* tmp = (int*)malloc(sizeof(int) * 12345678910); if (tmp == NULL) { printf("%s\n", strerror(errno)); } else { printf("开辟成功!\n"); } free(tmp); tmp = NULL; return 0; }
写在最后
常用字符串函数的熟练使用可以在某些地方大大提升写代码效率,因此一定要好好掌握,最好能够自我实现,吃透这些函数的运行逻辑,以便更精确更融洽的使用。
感谢阅读本小白的博客,错误的地方请严厉指出噢!