目录
一.strcmp()函数
二.strstr()函数
三.memcpy函数
四.memmove函数
五.strncpy函数
六.strcat函数
七.atoi函数
八.strlen函数
一.strcmp()函数
strcmp
函数是用于比较两个字符串是否相等的函数。它通过逐个字符比较两个字符串的 ASCII 值,来判断它们的相对大小。
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<errno.h>
int my_strcmp(const char* str1, const char* str2) {assert(str1 && str2);while (*str1 == *str2) {if (*str1 == '\0') {return 0;}str1++;str2++;}if (*str1 > *str2)return 1;elsereturn -1;//或者//return *str1 - *str2;
}
int main() {char arr1[] = {"abcdef"};char arr[] = {"abc"};int ret = my_strcmp(arr1, arr);if (ret == 0) {printf("=");}else if (ret >= 1) {printf(">");}elseprintf("<");return 0;
}
代码解释:
形参:用const修饰指针所指向的对象,表示通过该指针不能修改所指向的对象。
断言
assert(str1 && str2)
: 该断言确保传入的两个字符串指针不为NULL
,即确保输入有效。如果任何一个指针为NULL
,程序会在调试模式下抛出异常。while 循环:
while (*str1 == *str2)
表示当两个字符串当前字符相等时,继续循环进行比较。通过字符指针str1
和str2
遍历每一个字符,直到遇到不相等的字符或者字符串的末尾(即'\0'
)。判断结束条件: 当
*str1 == '\0'
时,表示字符串已经比较完毕,而且两者完全相同。因此,直接返回0
,表示两个字符串相等。返回比较结果:
- 如果
*str1 > *str2
,则返回1
,表示str1
在字典序上大于str2
。- 如果
*str1 < *str2
,则返回-1
,表示str1
在字典序上小于str2
。
二.strstr()函数
strstr
函数是 C 语言标准库中的一个字符串处理函数,用于查找一个字符串中是否包含另一个子字符串。
const char* my_strstr(const char* str1, const char* str2) {assert(str1 && str2);const char* s1 = str1;const char* s2 = str2;const char* cur = str1;//cur指针记可能的开始匹配的位置if (*str2 == '\0') {//str2是空字符串直接返回str1return str1;}//外层 while 循环遍历 str1,直到到达字符串末尾。每次//循环都将 s1 指向 cur,将 s2 指向 str2。while (*cur) {//完成一次匹配s1 = cur;s2 = str2;while (*s1 && *s2 && *s1 == *s2) {s1++;s2++;//内层 while 循环用于逐个字符比较 s1 //和 s2 指向的字符。如果它们相等,两个指针都向后移动。}if (*s2 == '\0') {return cur;//如果 s2 到达字符串末尾,说明 str2 完//全匹配了 str1 中以 cur 开始的位置,返回 cur。}cur++;//如果没有找到匹配,移动 cur 指针,继续检查下一个可能的匹配位置。}
}
int main() {char arr1[] = { "abcdefhij" };char arr2[] = { "def" };const char* ret = my_strstr(arr1, arr2);if (ret == NULL) {printf("找不到\n");}elseprintf("找到了:%s", ret);return 0;
}
代码解释:
(代码注释)
三.memcpy函数
memcpy
函数是 C 标准库中的一个函数,用于在内存中复制一块数据。作用是将源内存区域的数据复制到目标内存区域。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
//void* arr1: 指向目标内存的指针。
//const void* arr2: 指向源内存的指针。
//size_t num: 要复制的字节数。
void my_memcpy(void* arr1, const void* arr2, size_t num) {//保存 arr1 的初始地址,以便在函数结束时返回(虽然在此代码中未实际返回)。void* ret = arr1;assert(arr1 && arr2);//使用 char* 类型强制转换,使得可以逐字节复制数据。//每次循环将 arr2 当前指针所指向的字节值复制到 arr1,然后两个指针都向前移动一个字节。while (num--) {*(char*)arr1 = *(char*)arr2;arr1=(char*)arr1+1;arr2=(char*)arr2+1;}//可省略,只是为了还原原函数的返回值return ret;
}
int main() {int arr[] = { 1,2,2,4 };int arr1[2] = { 0 };//注意这里的自定义memcpy不能够复制自身,但是在这个编译器的标准库函数memcpy函数可以,但是其他编译器不一定可以哦my_memcpy(arr1,arr,2*sizeof(int));int sz = sizeof(arr1) / sizeof(arr1[0]);for (int i = 0; i < sz; i++) {printf("%d ", arr1[i]);}return 0;
}
代码解释:
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
(代码注释)
四.memmove函数
memmove
是 C 标准库中的一个函数,用于在内存区域之间复制数据。它与memcpy
类似,但memmove
能够安全地处理源和目标内存区域重叠的情况(比如以下代码的例子),而memcpy
不能。
#include<stdio.h>
#include<string.h>void* my_memmove(void* dest, const void* src, size_t num) {// 存储目标地址,方便后续返回void* ret = dest;if (dest < src) {// 前 -> 后复制while (num--) {*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}} else {// 后 -> 前复制while (num--) {*((char*)dest + num) = *((char*)src + num);}}return ret;
}int main() {int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };my_memmove(arr + 2, arr, sizeof(int) * 5);for (int i = 0; i < 10; i++) {printf("%d ", arr[i]);}return 0;
}
代码解释:
- 返回值:标准库的
memmove
函数返回dest
的地址,因此我们也应该返回dest
。- 前向复制:当
dest
地址小于src
,需要从前往后复制,以避免覆盖源数据。- 后向复制:当
dest
地址大于或等于src
,为了避免重叠问题,我们从后往前复制数据。
五.strncpy函数
strncpy
是 C 标准库中的一个字符串处理函数,定义在<string.h>
头文件中。它用于将一个字符串的指定长度部分复制到另一个字符串中。
#include <stdio.h>
//char* dest:目标字符串指针,用于存储复制后的字符串。
//const char* src:源字符串指针,要复制的字符串。
//size_t n:要复制的最大字符数。
char* my_strncpy(char* dest, const char* src, size_t n) {size_t i;for (i = 0; i < n && src[i] != '\0'; i++) {dest[i] = src[i];}// 如果 src 的长度小于 n,填充剩余部分为 '\0'for (; i < n; i++) {dest[i] = '\0';}return dest;
}int main() {char dest[10];my_strncpy(dest, "Hello", 10);printf("%s\n", dest); // 输出: Helloreturn 0;
}
代码解释:
- 第一个
for
循环:将src
的字符逐个复制到dest
中,直到n
个字符或遇到源字符串的末尾('\0'
)。- 第二个
for
循环:如果src
的长度小于n
,则在dest
的剩余部分填充'\0'
。
六.strcat函数
strcat
函数是 C 标准库中的一个字符串处理函数,功能是将源字符串src
追加到目标字符串dest
的末尾。目标字符串dest
必须有足够的空间来容纳源字符串src
和终止字符\0
。
#include <stdio.h>
//dest 是目标字符串,字符将追加到它的末尾。
//src 是源字符串,来自它的前 n 个字符会被复制。
//n 是指定要复制的字符数。
char* my_strncat(char* dest, const char* src, size_t n) {char* original_dest = dest;// 移动到 dest 字符串的末尾while (*dest) {dest++;}// 复制 src 的前 n 个字符到 destwhile (n-- && *src) {*dest++ = *src++;}// 添加终止符*dest = '\0';//返回起始地址return original_dest;
}int main() {char dest[20] = "Hello";my_strncat(dest, " World", 3);printf("%s\n", dest); // 输出: Hello Woreturn 0;
}
代码解释:
移动
dest
指针:
while (*dest)
这部分将dest
指针移动到目标字符串的末尾,因为字符串以\0
结尾,所以遇到\0
时停止。复制
src
字符串的前n
个字符:
- 通过
while (n-- && *src)
,逐个字符复制源字符串的前n
个字符,直到n
变为 0 或者源字符串的末尾\0
。添加终止符:
- 最后添加一个
\0
来终止目标字符串。返回值:
- 返回原始的
dest
地址,因为dest
在过程中被修改(移动到了字符串末尾),所以要保留原始的起始地址。
七.atoi函数
atoi
(ASCII to Integer)函数是标准 C 库函数,用于将字符串转换为整数。它从字符串的开头提取整数值,忽略前导空格,直到遇到一个非数字字符为止。函数声明在<stdlib.h>
头文件中。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <limits.h> // 用于 INT_MAX 和 INT_MINint my_atoi(const char* str) {int sign = 1; // 标志符号,默认正数long result = 0; // 存储结果,用 long 来处理可能的溢出int i = 0;// 1. 跳过字符串前面的空白字符while (str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r' || str[i] == '\v' || str[i] == '\f') {i++;}// 2. 处理正负号if (str[i] == '-' || str[i] == '+') {if (str[i] == '-') {sign = -1; // 如果是负号,sign = -1}i++;}// 3. 处理数字字符while (str[i] >= '0' && str[i] <= '9') {result = result * 10 + (str[i] - '0'); // 将字符转换为整数并累加到结果// 4. 处理溢出问题if (result > INT_MAX) {if (sign == 1) {return INT_MAX; // 正溢出}else {return INT_MIN; // 负溢出}}i++;}return (int)(result * sign); // 返回转换后的整数,带符号
}int main() {char str1[] = " -12345";char str2[] = "4193 with words";char str3[] = "words and 987";char str4[] = "-91283472332";printf("String: '%s' -> Integer: %d\n", str1, my_atoi(str1)); // 输出 -12345printf("String: '%s' -> Integer: %d\n", str2, my_atoi(str2)); // 输出 4193printf("String: '%s' -> Integer: %d\n", str3, my_atoi(str3)); // 输出 0printf("String: '%s' -> Integer: %d\n", str4, my_atoi(str4)); // 输出 INT_MIN (-2147483648)return 0;
}
代码解释:
跳过空白字符
- 使用
while
循环跳过空白字符(空格、换行、制表符等)。这些字符在C
语言中有多种表示形式,包括' '
,'\t'
,'\n'
,'\r'
,'\v'
,'\f'
。处理正负号
- 如果遇到正负号(
'+'
或'-'
),相应地设置sign
的值为 1 或 -1。- 默认情况下,
sign
的初值为 1(正数)。处理数字字符
- 将连续的数字字符逐个转换为整数,并逐步累加到
result
变量中。每次新数字str[i]
加入结果时,执行result = result * 10 + (str[i] - '0')
,其中(str[i] - '0')
是将字符数字转换为对应的整数。处理溢出
- 如果
result
大于INT_MAX
,根据sign
值判断是正溢出还是负溢出,并返回INT_MAX
或INT_MIN
。- 使用
long
类型的result
来确保不会在计算过程中发生溢出。返回结果
- 最后,返回带符号的整数值
result * sign
。
ps:
- 溢出处理:如果数字超出
int
类型的范围,即大于INT_MAX
(2147483647) 或小于INT_MIN
(-2147483648),返回相应的最大或最小值。 - 非数字字符处理:当遇到第一个非数字字符时,停止转换并返回当前已转换的整数。
- 空字符串处理:在本例中,没有特殊处理空字符串。如果输入字符串为空或全是非数字字符,返回值为
0
。
八.strlen函数
strlen
函数是 C 语言中的标准库函数,用于计算并返回一个以空字符'\0'
结尾的字符串的长度。该长度不包括字符串的终止符'\0'
,仅包含字符串中的实际字符数。
#include<stdio.h>
#include<assert.h>
#include<string.h>
//注意arr不能写为arr[],因为你要传进来数组的首元素
size_t my_strlen(const char* arr) {//方法一size_t count = 0;assert(arr != NULL);//注意解引用while (*arr) {count++;arr++;}return count;//方法二(指针-指针等于元素的个数)/*char* start = arr;assert(arr != NULL);while (*arr) {arr++;}return arr - start;*///方法三(递归)//记得解引用/*if (*arr == '\0') {return 0;}else {return my_strlen(arr + 1) + 1;}*/}
int main() {char arr[] = { "abcdef" };size_t len =my_strlen(arr);printf("%zd", len);return 0;
}
代码解释:
方法一(迭代法):
- 使用
while
循环遍历字符串的每个字符,直到遇到字符串的结束符'\0'
。- 每次循环增加
count
计数器,最后返回count
。方法二(指针运算法):
- 首先保存原始指针
start
,然后移动指针arr
直到'\0'
。- 返回
arr
与start
之间的差值,即为字符串的长度。方法三(递归法):
- 使用递归调用自身,每次传入下一个字符的指针。如果遇到
'\0'
返回0
,否则返回my_strlen(arr + 1) + 1
。