C语言中没有string类型,字符串通常放在常量字符串或字符数组中,下面来介绍一些常用的字符串相关的操作函数。
strlen
strlen用来求一个字符串的长度,其函数原型如下:
size_t strlen ( const char * str );
使用strlen需要注意以下几点:
①strlen求的是字符串中\0前面的字符个数(不包括\0),所以字符串必须\0结尾
②strlen返回值类型是size_t,也就是unsigned int,是无符号整型,如果两个strlen相减是不能得到负数的。
下面用两种方法来模拟实现一下strlen:
//方法1,常规方法
int My_Strlen(char *str)
{
int num = 0;
while (*str != '\0')
{
num++;
str++;
}
return num;
}
//方法2,递归
int My_Strlen_1(char *str)
{
if (*str != '\0')
{
return My_Strlen_1(str + 1) + 1;//这里不能用str++,因为后置++是先执行再++,会死循环,++str也不推荐,虽然可以实现,但是str也被改变了
}
return 0;
}
strcpy
strcpy用于拷贝源空间的字符串到目标空间,其函数原型如下:
//source是源字符串首地址,Destination是目标字符串首地址,返回的是目标字符串的首地址
char* strcpy(char * destination, const char * source);
使用该函数需要注意以下几点:
①源字符串必须以\0结尾。
②该函数会把源字符串中\0之前的字符连同\0一起拷贝到目标地址。
③目标空间必须足够大,保证能存放源字符串
④目标空间必须是可变的,不能是常量字符串。
下面来模拟实现一下strcpy:
/*
* @brief 拷贝字符串初阶代码
* @param dest: 要拷贝的目标地址
* @param src: 要拷贝的源地址
*/
void my_strcpy(char *dest, char *src)
{
while (*src != '\0') // 判断scr还没有结束
{
*dest = *src; // 把src中的字符复制到dest中
dest++;
src++;
}
*dest = *src; // strcpy会把\0也一起拷贝
}
/*
* @brief 改进的字符串拷贝函数
* @param dest: 要拷贝的目标地址
* @param src: 要拷贝的源地址
* @return char*: 返回目标空间的起始地址,也就是最初的dest
*/
// 增加返回值是为了实现链式访问,函数的返回值可以作为其他函数的参数
char *my_strcpy_01(char *dest, const char *src) // 在源地址加入const是为了防止写函数时while等号两边写反,如果加上const,写反会报错
{
char *ret = dest;
assert(dest && src); // 增加断言,防止输入参数误传为NULL,如果误传会报错
while (*dest++ = *src++) ;// 较上述代码有所简化,当*src为\0时,赋值后表达式会为0,会跳出循环
return ret;
}
strcat
strcat用于在目标字符串后追加源字符串,其函数原型如下:
//source是源字符串地址,destination是目标字符串地址,返回的是目标字符串地址
char * strcat ( char * destination, const char * source );
使用该函数需要注意以下几点:
①源字符串必须以\0结尾。
②目标空间必须足够大,保证能存放源字符串
③目标空间必须是可变的,不能是常量字符串。
下面举一个使用示例:
int main()
{
char arr[20] = "hello ";
strcat(arr,"world");
printf("%s\n",arr);//会打印hello world
}
下面来模拟实现一下strcat:
/*
* @brief 字符串追加函数
* @param destination:目标字符串地址
* @param source:源字符串地址
* @return char*:返回目标字符串地址
*/
char *my_strcat(char *destination, const char *source)
{
assert(destination && source);//断言防止输入NULL
char *dest = destination;
while (*destination++) ;// 先找出目标字符串的末尾,也就是\0
destination--; // 此时destination就是\0的位置
while (*destination++ = *source++) ;// 然后与字符串拷贝同理
return dest;
}
strcmp
strcmp用于比较两个字符串是否相等,比较的是每一个字符的ASCII码值的大小,其函数原型如下:
//str1是第一个字符串的地址,str2是第二个字符串的地址,
//如果第一个字符串大于第二个字符串,返回大于0的数,如果小于,返回小于0的数,如果等于,返回0
int strcmp ( const char * str1, const char * str2 );
下面举一个例子:
int main()
{
char arr1[10] = "abc";
char arr2[20] = "abc";
//这样比较两个字符串是否相等是不对的,因为arr1和arr2是数组名,就是数组首元素的地址,直接用等号比比的是地址的大小,而不是两个字符串相比
if(arr1 == arr2)
printf("arr1 == arr2\n");
else
printf("arr1 != arr2\n");
//判断两个字符串是否相等应该用下面的方法,并且strcmp比较的不是字符串的长度,而是ASCII码,abc是比abbbbbbb要大的
if(strcmp(arr1,arr2) > 0)
printf("arr1 > arr2\n");
else if(strcmp(arr1,arr2) < 0)
printf("arr1 < arr2\n");
else
printf("arr1 == arr2\n");
}
下面来模拟实现一下strcmp:
/*
* @brief 字符串比较函数,如果str1>str2,输出正数,反之输出负数,相等输出0,比较的不是长度,是ASCll码
* @param str1:
* @param str2:
* @return int:
*/
int my_strcmp(const char *str1, const char *str2)
{
assert(str1 && str2);
// 遍历两字符串,如果找到不相等的退出循环,输出不相等字符串的差,如果两字符串都相等*str1=*str2会为\0,输出差值为0
while ((*str1 == *str2) && (*str1))
{
str1++;
str2++;
}
return *str1 - *str2;
}
strncpy
strncpy是长度受限制的字符串拷贝函数,可以指定要拷贝字符的个数,如果源字符串的长度小于要拷贝的个数,就在后边补\0,函数原型如下:
//destination是目标字符串地址,source是源字符串地址,num是要拷贝的字符个数,返回的是目标字符串地址
char * strncpy ( char * destination, const char * source, size_t num );
#include <stdio.h>
#include <string.h>
int main()
{
// 代码1
char arr[10] = "abcdef";
char a[] = "hello";
strncpy(arr, a, 3);
printf("%s\n", arr);//会打印heldef,只拷贝了三个字符,后面的不变
strncpy(arr, a, 5);
printf("%s\n", arr);//会打印hellof,只拷贝了五个字符,没有拷贝到\0,后面的不变
strncpy(arr, a, 6);
printf("%s\n", arr);//会打印hello,拷贝到了\0
return 0;
}
strncat
strncat用于在目标字符串的结尾(第一个\0)处追加源字符串的前num个字符,并且会在后面加上一个\0,其函数原型如下:
//destination是目标字符串地址,source是源字符串地址,num是要追加的字符个数,返回的是目标字符串地址
char * strncat ( char * destination, const char * source, size_t num );
strncmp
strncmp用来比较两个字符串的前num个字符,其函数原型如下:
//str1是第一个字符串的地址,str2是第二个字符串的地址,num是要比较的字符个数
//如果str1>str2,返回正数,反之返回负数,相等返回0
int strncmp ( const char * str1, const char * str2, size_t num );
strstr
strstr用于在一个字符串中查找另一个字符串,其函数原型如下:
//在字符串str1中查找字符串str2的位置,如果找到了,返回str2在str1中的起始地址,没找到返回NULL
char * strstr ( const char *str1, const char * str2);
int main()
{
char email[] = "abc@godfather.com";
char str[] = "godfather";
char* ret = strstr(email,str);
if(ret == NULL)
printf("未找到字符串\n");
else
printf("%s\n",ret);//在email中能找到str,ret会返回g的地址,会打印godfather.com
return 0;
}
下面来模拟实现一下strstr:
/*
* @brief 在字符串str1中查找字符串str2
* @param str1:
* @param str2:
* @return char*: 返回str2在str1中的位置,如果没找到就返回NULL
*/
char *my_strstr(const char *str1, const char *str2)
{
assert(str1 && str2);
const char *s1 = str1;
const char *s2 = str2;
const char *ret = str1; // ret是str1中向后走的指针
while (*ret)
{
s1 = ret;
s2 = str2;
while (*s1 && *s2 && (*s1 == *s2)) // 如果找到相等的字符就向后查找,如果遇到不相等或某个字符串遇到\0就退出循环
{
s1++;
s2++;
}
if (*s2 == '\0') // 如果退出循环时s2遇到了\0,就说明找到了字符串,返回此时str1中的起始地址
{
return (char *)ret;
}
ret++; // 如果没找到就令str1的移动指针++,向后寻找
}
return NULL; // 如果遍历完还是没找到就返回NULL
}