【C语言库函数】各字符串函数的使用及模拟实现
1. 1.1。 如何使用
这个功能大家一定都很熟悉了。 顾名思义,它的功能就是求字符串的长度。 使用时只需要传递一个字符串即可。 让我们在以下位置搜索这个函数:
你可以看看这个描述。 我们可以忽略下面一大堆英文描述。 我们看一下它的返回值类型,结果是——无符号整数。 这样的设计其实考虑到了字符串的长度必须大于零,但是这样的设计也会导致一种有些“奇怪”的情况:
这里它显然小于,但大于打印。 这是因为当进行两次计算时,最终的结果也必须是类型,即必须大于0。
所以关于这一点,我们在以后使用的时候需要特别注意。 如果我们想要将两个字符串的长度相减,最好强制将每个长度转换为int类型或者保存在int类型变量中。 例如:
1.2. 模拟实施
思路分析:
实现原理很简单,就是在遇到字符串结束标志'\0'之前统计字符串中的字符数,最后返回统计到的字符数。
模拟实现:
第一个是最简单的实现,计数器:
int my_strlen1(const char* str) {
assert(str);
int count = 0;
while (*str++) {
count++;
}
return count;
}
当我们了解了指针之后,我们知道指针减去指针就代表了指针之间的元素个数。 于是就有了第二种实现方法,指针减指针:
int my_strlen2(const char* str) {
assert(str);
const char* temp = str;
while (*temp) {
temp++;
}
return temp - str;
}
但有些问题可能要求你不要创建临时变量。 这时候就应该使用递归了,于是第三种实现方法,递归方法就出来了:
int my_strlen3(const char* str) {
assert(str);
if ('\0' == *str) {
return 0;
}
else {
return 1 + my_strlen3(str + 1);
}
}
2.和2.1。 如何使用
作用是将一个字符串的内容(包括末尾的'\0')复制到另一个字符串中。 其次,还有n个以上。 这个n代表要复制的字符数。 。 例如我们现在有两个字符串:
char str1[] = "overtime!";
char str2[] = "no overtime!";
如果我们想将 str1 复制到 str2,我们可以使用:
如果我们想要复制str1的所有内容,但只想复制前4个字符,那么我们可以使用:
2.2. 模拟实施
在模拟之前,我们先看一下这两个函数的描述信息:
红线表示两个函数是否复制'\0'。 其中,strcp无论如何都会复制'\0',但只有当源字符串的长度小于要复制的字符数时,才会在末尾追加'\0',直到到达复制的字符为止。 直到数字等于num。
模拟实现:
:
char* my_strcpy(char* dest, const char* src) {
assert(dest && src);
char* start = dest;
while (*dest++ = *src++) {
;
}
return start;
}
:
char* my_strncpy(char* dest, const char* src, int num) {
assert(dest && src);
char* start = dest;
while (num-- && (*dest++ = *src++)) {
;
}
if (0 == num) {
;
}
else {
while (num-- > 0) {
*dest++ = '\0';
}
}
return start;
}
3.和3.1。 如何使用
作用是在一个字符串后面附加(连接)另一个字符串,和上面一样,意思是只连接几个字符,而不是整个字符串。
例如,我们现在有这两个字符串:
char str1[20] = "Salary";
char str2[] = " increase!!";
我们可以使用 str2 连接 str1:
我们还可以使用以下方法仅附加一个字符:
3.2. 模拟实施
在模拟实现之前,我们先看一下这两个函数的说明:
从描述中我们可以知道,两个函数在追加结束时都会添加一个字符串结束标志'\0',并且最多只会追加到原字符串的末尾。
事实上,当我们找到目标字符串的第一个'\0'时,我们只需要重复操作即可,但是要注意最多追加到原字符串的末尾。
模拟实现:
:
char* my_strcat(char* dest, const char* src) {
assert(dest && src);
char* start = dest;
// 先找到的dest的第一个'\0'
while (*dest) {
dest++;
}
// 然后重复strcpy的操作即可
while (*dest++ = *src++) {
;
}
return start;
}
:
char* my_strncat(char* dest, const char* src, int num) {
assert(dest && src);
char* start = dest;
// 先找到的dest的第一个'\0'
while (*dest) {
dest++;
}
// 然后重复strncpy的操作即可
while (num-- && (*dest++ = *src++)) {
;
}
dest = '\0'; // 只追加到src的结尾
return start;
}
4.和4.1。 用法
功能是比较两个字符串的大小。 如果两个字符串相等,则返回0,否则返回其他数字。 比较方法是逐个字母进行比较。 如果当前比较的两个字母相等,则跳转到下一个字母。 如果它们不相等,则直接返回大于零或小于零的数字。
它将比较两个字符串的末尾,但最多只比较 n 个字符。
例如,我们现在有两个字符串:
char str1[] = "str";
char str2[] = "string";
我们可以通过以下方式比较这两个字符串是否相等:
它还可以用于仅比较它们的前三个字符,看看它们是否相同:
4.2. 模拟实施
两个函数的返回值应满足下表:
而我们知道字符的本质是一个ASCII码值,所以当我们找到两个不相等的字符后,我们可以直接返回它们的差值。
这两个函数的模拟方法其实很简单。 我这里直接编码:
模拟实现:
:
int my_strcmp(const char* str1, const char* str2) {
assert(str1 && str2);
while ((*str1 == *str2) && (*str1 && *str2)) {
str1++;
str2++;
}
return *str1 - *str2;
}
:
int my_strncmp(const char* str1, const char* str2, int num) {
assert(str1 && str2);
int i = 0;
for (i = 0; i < num; i++) {
if (*(str1 + i) != *(str2 + i)) {
return *(str1 + i) - *(str2 + i);
}
}
return *(str1 + i - 1) - *(str2 + i - 1);
}
5. 5.1. 如何使用
作用是判断一个字符串是否是另一个字符串的字符串。 如果是,则返回指向子字符串出现的第一个位置的指针。 比如“ab”就是“aab”的字符串,他们两个传入返回的应该是指向“aab”中第二个a的指针。 如果不是,则返回空指针。
例如,我们现在有两个字符串:
char str1[] = "bab";
char str2[] = "aaababbbb";
我们可以用它来确定 str1 是否是 str2 的子字符串:
我们可以看到它返回的应该是一个指向第四个字符b的指针。
5.2. 模拟实施
虽然子串匹配的算法有很多,但今天我向大家介绍一种最简单的方法——朴素法:
char* my_strstr(const char* str1, const char* str2) {
assert(str1 && str2);
const char* temp = str1; // 在外层遍历str1,找到有一个*str2就停下
const char* s1 = NULL; // 当temp找到一个*str2之后s1继续遍历temp后面的字符,判断子串
const char* s2 = NULL; // 当temp找到一个*str2之后s2继续遍历str2后面的字符,判断子串
while (*temp) {
while ((*temp != *str2) && *temp) {
temp++;
}
s1 = temp;
s2 = str2;
while ((*s1 == *s2) && (*s1 && *s2)) {
s1++;
s2++;
}
if ('\0' == *s2) {
return (char*)temp;
}
else {
temp++;
}
}
return NULL;
}