在C语言中,字符串是以字符数组组成的,以空字符‘\0’为终止符号,一种数据存储方式。
字符串的常用操作如下:
- strlen:计算字符串长度
- strcpy:复制字符串
- strcat:字符串连接
- strcmp:字符串比较
- strstr:查找子串在字符串中第一次出现的位置
- memcpy:从母串复制n个字符到子串
- memmove:处理同一个数组的复制问题(重叠问题)
接下来,用C语言来模拟实现以上的函数功能;
1、strlen函数
strlen函数是C语言中标准库中的一个字符串处理函数,用于计算一个字符串的长度(不包括字符串末尾的空字符 '\0')。
代码实现:
size_t my_strlen(const char* str)
{
int count = 0;
assert(str);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
size_t n = my_strlen(arr);
printf("%d\n", n);
return 0;
}
其中,const char *str
是要计算长度的字符串。
函数返回一个 size_t
类型的无符号整数,表示字符串的长度。
2、strcpy函数
strcpy函数是C语言标准库中的字符串处理函数之一,用于将一个字符串复制到另一个字符串中。
使用该函数时要注意以下几点:
- 目标字符串dest必须足够大以容纳源字符串src,否则会出现溢出问题。
- 源字符串src必须是一个以'\0'结尾的字符串。
- 函数返回的指针指向目标字符串dest的起始地址。
代码实现:
char* my_strcpy(char* arr,const char* ret)
{
assert(arr);
assert(ret);
char* tem = arr;
while (*ret != '\0')
{
*arr = *ret;
ret++;
arr++;
}
*arr = *ret; //注意\0的复制
return tem;
}
int main()
{
char arr1[] = "abcdef";
char arr2[20] = { 0 }; //注意数组有足够大小
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
其中,arr为目标字符串(即复制后的字符串),ret为源字符串(即待复制的字符串)。该函数会将ret字符串中的每个字符复制到arr中,直到遇到字符串结束符'\0'为止。函数返回一个指向目标字符串的指针。
3、strcat函数
strcat函数是C语言中一个字符串操作函数,用于将一个字符串连接到另一个字符串的末尾。
使用strcat函数时,需要注意以下几点:
-
目标字符串必须有足够的空间来存储源字符串连接后的结果。
-
目标字符串必须以'\0'结尾,否则连接后的结果可能不是预期的。
-
源字符串和目标字符串不应该有重叠部分,否则会导致不可预测的结果。
代码实现:
char* my_strcat(char* arr1, const char* arr2)
{
if (arr1 == NULL && arr2 == NULL)
{
printf("tempy!/n");
return NULL;
}
char* A = arr1; //保存指针
while (*arr1 != '\0')
arr1++;
while (*arr2 != '\0')
*arr1++ = *arr2++;
*arr1 = '\0'; //注意 '\0'
return A;
}
int main()
{
char arr1[30] = "Hello "; //存放数组足够大
char arr2[10] = "world!";
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
其中,arr1是目标字符串,arr2是要连接到目标字符串的源字符串,函数的返回值是连接后的目标字符串的指针。
4、strcmp函数
strcmp函数是C语言中的字符串比较函数,用于比较两个字符串的大小。
strcmp函数的实现原理是,逐个比较两个字符串的字符,如果发现不同的字符,则返回它们的ASCII码之差。如果发现两个字符串相等,则在比较到字符串结尾的'\0'时返回0。如果一个字符串比另一个字符串短,但在其前面的字符相同,则返回长度的差值。
比较可能出现的结果:
- 若s1和s2相等,则返回0。
- 若s1大于s2,则返回大于0的整数。
- 若s1小于s2,则返回小于0的整数。
代码实现:
int my_strcmp(const char* arr1, const char* arr2)
{
if (arr1 == NULL && arr2 == NULL) //是否为空指针
return 0;
while (*arr1 == *arr2)
{
if (*arr1 == '\0')
return 0;
arr1++;
arr2++;
}
if (*arr1 > *arr2)
return 1;
else
return -1;
}
int main()
{
char arr1[10] = "abcdey";
char arr2[10] = "abcdey";
int A = my_strcmp(arr1, arr2);
if (A > 0) //判断结果
printf("arr1>arr2\n");
else if (A < 0)
printf("arr1<arr2\n");
else
printf("arr1 = arr2\n");
return 0;
}
5、strstr函数
strstr函数是一个C标准库函数,用于在一个字符串中搜寻另一个字符串的位置。
strstr函数只返回子串的开头位置指针。
代码实现:
int my_strstr(const char* arr1, const char* arr2)
{
if (arr1 == NULL && arr2 == NULL)
return -1;
const char* new1 = arr1; //用来代替arr1移动
const char* new2 = arr2;
const char* new3 = arr1; //保存母串的初始位置
while (*new3)
{
new1 = new3; //从初始位置+1,再次遍历
new2 = arr2; //重置子串
while (*new1 != '\0' && *new2 != '\0' && *new1 == *new2)
{
new1++;
new2++;
}
if (*new2 == '\0') //子串走到底了
return 1;
new3++; //母串+1
}
return -1; //没有找到
}
int main()
{
char arr1[30] = "hello world!";
char arr2[10] = "worldo";
int A = my_strstr(arr1, arr2);
if (A > 0)
printf("find!\n");
else
printf("no find!\n");
return 0;
}
上面的代码与原函数有些差异,只能用来查找是否有子串存在,其实只要把返回类型修改和保存一下就能实现原函数的功能。
其中,arr1表示要搜索的字符串,arr2表示要查找的字符串。
6、memcpy函数
memcpy函数是C语言中的标准库函数,用于将指定长度的数据从源地址复制到目标地址。
注意:使用memcpy函数时需要留意内存的重叠问题,如果源地址和目标地址有重叠,那么结果可能会出现错误。可以使用memmove函数来避免这个问题。
代码实现:
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;//保持目标地址
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret; //返回目标地址
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 20);
for (int i = 0; arr2[i] != 0; i++)
printf("%d ", arr2[i]);
return 0;
}
7、memmove函数
memmove函数是C语言的标准库函数之一,用于将一段内存块中的数据按字节级别复制到另一个内存块中。与memcpy函数类似,但memmove函数也可以处理重叠的内存块,即源内存块和目标内存块可以有部分重叠。
代码实现:
void* my_memmove(void* dest,const void* arr1, int size)
{
if (dest == NULL)
{
printf("error!\n");
return NULL;
}
void* ret = dest; //保存目标地址
if (dest < arr1) //当子串起始位置大于复制位置时,从前往后复制
{
while (size--)
{
(*(char*)dest) = (*(char*)arr1);
dest = (char*)dest + 1;
arr1 = (char*)arr1 + 1;
}
}
else //反之,从后往前复制
{
while (size--)
{
*((char*)dest + size) = *((char*)arr1 + size);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 1, arr, 20); //arr是复制的子串起始位置 ,arr+1 是复制的位置
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}