目录
一.strlen---求字符串长度
(1)strlen函数介绍
(2)自己动手实现strlen函数的三种方法
1.计数器的方法
2.递归
3.指针-指针
(3)注意strlen的返回值类型
二.strcpy---长度不受限制的字符串函数
(1)strcp函数介绍
(2)自己动手实现strcpy函数
(3)注意事项
三.strcat---长度不受限制的字符串函数
(1)strcat介绍
(2)自己动手实现strstr函数
(3)注意事项
四.strcmp---长度受限制的字符串函数
(1)strcmp函数介绍
(2)自己动手实现strcmp函数
(3)注意事项
五.strncpy---长度受限制的字符串函数
(1)strncpy函数介绍
六.strncat---长度受限制的字符串函数
(1)strncat介绍
七.strncmp---长度受限制的字符串函数
(1)strncmp介绍
八.strstr-查找字符串
(1)strstr函数介绍
(2)自己动手实现strcmp函数
举例
int len = strlen("abcdef");
不妨先模拟一下这个字符串的内存布局:
"abcdef"字符串是以'\0'作结尾的("abcdef"是有7个字符串)
strlen函数会计算'\0'之前的字符串,,然后计算个数,以size_t(unsigned int)的形式返回出去
下面打印出它的返回值
我们看下错误写法
char arr[] = { 'a','b', 'c', 'd', 'e', 'f' };
int len=strlen(arr);
我们先看下结果
为什么是19,而不是6呢?
事实上,arr数组这种创建方式不以'\0'结尾,那为什么在19停止了呢?这个随机值,可能从头往后数数了19个,才发现了'\0'
不妨画图假设看看!!('x'为任意字符)
int my_strlen(char* str) {
int count = 0;
while (*str!='\0')
{
count++;
str++;
}
return count;
}
int my_strlen(char *str) {
if (*str!='\0')
{
return 1 + my_strlen(str + 1);
}
else {
return 0;
}
}
int my_strlen(char* str) {
int count = 0;
while (*str!='\0')
{
count++;
str++;
}
return count;
}
实现代码
int main() {
char arr[] = "bit";
int len = my_strlen(arr); //arr是数组,数组传参,传过去的不是整个数组,而是第一个元素的地址
printf("len=%d\n", len);
return 0;
}
int main() {
// 3 - 6 =-3(3)
if (strlen("abc")-strlen("abcdef")>0)
{
printf("正\n");
}
else
{
printf("负\n");
}
return 0;
}
上述代码会返回 正 ,由于strlen返回类型是size_t=unsigned int,所以以上3-6=-3中的-3会转换成正3
源字符串必须以'\0'结束
会将源字符串中的'\0'拷贝到目标空间
目标空间必须足够大,以确保能存放源字符串
目标空间必须可变
举例
char arr1[]="abcdefghi";
char arr2[]="bit";
strcpy(arr1,arr2);//第一个参数是目的地,第二个参数是源头
printf("%s\n", arr1);
看下内存布局
可以看出,拷贝过去的时候'\0'也过去了!!
打印出arr1
char* my_strcpy(char* dest, const char* src) {
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
//拷贝src指向的字符串到dest指向的空间,包含'\0'
while (*dest++ = *src++)
{
}
//返回目的空间的起始地址
return ret;
}
代码实现
int main() {
char arr1[] = "abcdefghi";
char arr2[] = "bit";
my_strcpy(arr1, arr2); //第一个参数目的地,第二个源头
printf("%s\n", arr1);
return 0;
}
下面arr2后面不是以'\0'结尾,而strcpy需要'\0',这样可能会存在越界访问,这样是错误的
int main() {
char arr1[] = "abcdefghi";
//错误的写法
char arr2[] = { 'b','i','t' };
strcpy(arr1,arr2); //第一个参数目的地,第二个源头
printf("%s\n", arr1);
return 0;
}
下面arr1指针指向的是常量字符串,常量字符串不能被改,运行会导致程序崩溃
int main() {
char *arr1 = "abcdefghi";
char arr2[] = "bit";
my_strcpy(arr1, arr2); //第一个参数目的地,第二个源头
printf("%s\n", arr1);
return 0;
}
下面arr1字符串比arr2字符串小,使用函数,函数会发现目的地arr1大小不足,导致程序崩溃
int main() {
char arr1[] = "bit";
char arr2[] = "abcdefghi";
strcpy(arr1,arr2); //第一个参数目的地,第二个源头
printf("%s\n", arr1);
return 0;
}
长度不受限制,只受'\0'的限制, arr[5]的空间不够,但是也让"hello world"字符串拷贝过去了!!会导致代码的不安全
int main() {
char arr1[5] = "abc";
char arr2[] = "hello world";
strcpy(arr1, arr2); //没拷贝斜杠0
printf("%s", arr1);
return 0;
}
字符串拼接
原字符串必须有'\0'
目标空间必须有足够大,能容纳下源字符串的内容
目标空间可修改
举例:
char arr1[30] = "hello"; //arr1数组的创建需要足够大
char arr2[] = "world"; //arr2后面需要有'\0'strcat(arr1, arr2);//第一个参数目的地,第二个源头
printf("%s\n", arr1);
打印出结果
用以下代码看看运行后的内存布局:
char arr1[30] = "hello\0xxxxxxxxx";
char arr2[] = "world";strcat(arr1, arr2);//第一个参数目的地,第二个源头
printf("%s\n", arr1);
strcat使用之前 arr1 strcat使用后
从上面可以看出,原头的'\0'也跟着拼接了上去.而且目的地后面的'\0'被覆盖掉了!!
char* my_strcat(char*dest, const char*src) {
assert(dest&&src);
char* ret = dest;
//1.找到目的字符串的'\0'
while (*dest != '\0')
{
dest++;
}
//2.追加
while (*dest++ = *src++)
{
}
return dest;
}
代码实现
int main() {
char arr1[30] = "hello";
char arr2[] = "world";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
目标空间不够大,造成越界访问
char arr1[] = "hello";
char arr1[30] = "hello\0xxxxxxxxx";strcat(arr1, arr2);
自己给自己追加的错误
char arr1[30] = "hello";
strcat(arr1, arr1);
字符串比较函数
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
在Vs2017的编译环境下,
大于是返回1,等于是0,小于是-1
字符串比较的是字符的ASCII码
举例:
char* p1 = "abcdef";
char* p2 = "abcdeg";
int ret = strcmp(p1, p2);
printf("%d\n", ret);
由于p1和p2前面"abcde"相等,所以比较"f"和"g",由于"f"的ASCII值小于"g"的值,所以返回的是-1
char* p1 = "abcdef";
char* p2 = "abcd";
int ret = strcmp(p1, p2);
printf("%d\n", ret);
由于p1和p2前面"abcd"相等,p2后面'\0'跟p1的'e'进行比较,e大于'\0',所以返回值是1
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;
}
else
{
return -1;
}
}
代码实现
int main() {
char* p1 = "abc";
char* p2 = "abcd";
int ret = my_strcmp(p1, p2);
printf("ret=%d\n", ret);
return 0;
}
linux系统返回的是ASCII的差值
动手实现一个函数,模拟linux系统下,strcmp的返回值
int my_strcmp(const char* str1, const char* str2) {
assert(str1&&str2);
//比较
while (*str1 == *str2)
{
if (*str1 == '\0')
{
return 0;//相等
}
str1++;
str2++;
}
return (*str1 - *str2);
}
int main() {
char* p1 = "abc";
char* p2 = "abcd";
int ret = my_strcmp(p1, p2);
printf("ret=%d\n", ret);
return 0;
}
两个常量字符串不能用==来做比较,因为这比的是两个字符串的首地址
//错误比较
//if ("abcdef"=="abcdeg")
使用跟strcpy相似,增加第三个参数,第三个就是指定拷贝的字符个数
举例:
char arr1[5] = "abc";
char arr2[] = "hello world";
strcnpy(arr1, arr2,4); //没拷贝斜杠0
printf("%s", arr1);
内存布局:
使用前 使用后
可以看到,'\0'没有被增加上去
测试下另一段代码
char arr1[10] = "abcdef";
char arr2[] = "abc";
strncpy(arr1, arr2,6);
printf("%s", arr1);
内存布局:
使用前 使用后
可以看到,"abc"拷贝过去后,剩余的部分用了'\0'进行的代替.
也是跟strcat类似,增加第三个参数,,第三个就是指定追加的个数
//char arr1[30] = "hello\0xxxxxxxxxxxxx";
//char arr1[30] = "hello";
char arr2[] = "world";
strncat(arr1, arr2, 3);
printf("%s",arr1);
内存布局:
使用前 使用后
追加成功!!
测试下另一段代码
char arr1[30] = "hello\0xxxxxxx";
char arr2[] = "world";
strncat(arr1, arr2, 3);
printf("%s",arr1);
内存布局:
使用前 使用后
可以看到,追加过去后,后面会增加'\0'。
举例:
也是跟strcmp类似,增加第三个参数,,第三个就是指定比较字符的个数
const char* p1 = "abcdef";
const char* p2 = "abcdqwe";
int ret=strncmp(p1, p2, 5);
printf("%d\n", ret);
打印出来
第一个参数是被查找的字符串,第二个参数是要查找的子串
举例:
char* p1 = "defsda";
char* p2 = "def";
char* ret=strstr(p1, p2);
if (ret == NULL)
printf("子串不存在");
else
printf("%s\n", ret);
输出:
可以看到,输出的是def字符串+后面的字符串
测试下另一段代码:
char* p1 = "defsdefss";//这个字符有两个子串def
char* p2 = "def";
char* ret=strstr(p1, p2);
if (ret == NULL)
printf("子串不存在");
else
printf("%s\n", ret);
输出
可以看出,strstr这个函数查找的是第一个子串!!
//strstr-查找字符串
char* my_strstr(const char* p1,const char* p2) {
assert(p1!=NULL);
assert(p2 != NULL);
char* s1 = NULL;
char* s2 = NULL;
char* cur = (char*)p1;
if (*p2=='\0')
{
return (char*)p1;
}
while (*cur)
{
s1 = cur;
s2 = (char*)p2;
while ((*s1!='\0')&&(*s2!='\0')&&(*s1==*s2))
{
s1++;
s2++;
}
if (*s2=='\0')
{
return cur;
}
if (*s1=='\0')
{
return NULL;
}
cur++;
}
return NULL;//找不到子串
}
代码实现
int main() {
char* p1 = "defsdefss";
char* p2 = "def";
char* ret = my_strstr(p1, p2);
if (ret == NULL)
printf("子串不存在");
else
printf("%s\n", ret);
return 0;
}