strlen函数
- 求的是字符串的长度,统计的是字符串中\0之前的字符个数
- 返回值是size_t,是无符号的
- 无符号数相减也是无符号数,所以打印的是>
除非转化为int类型
模拟strlen的效果
不创建count,使用递归的方式去模拟
my_strlen("abcdef")=1+my_strlen("bcdef")
my_strlen("abcdef")=1+1+my_strlen("cdef")
*s已经是首元素地址了
所以1+my_strlen(s+1)——s+1是第二个元素——1+第二个元素到/0的长度
strcpy的使用和模拟实现<string.h>
strcpy(目的地,原地址)
目的地必须是可以被修改的,且足够大
#define _CRT_SECURE_NO_WARNINGS 1
#include<string.h>
#include<stdio.h>
#include<assert.h>
char * my_strcpy(char* dest,const char* src)
{
assert(src != NULL);
assert(dest != NULL);
char* ret = dest;
while(*dest++ =*src++)//当*src=/0时,跳出循环。*p指针是指向一块地址,p是改变指向哪块地址
{
;
}
return ret;
}
int main()
{
char arr[] = "hello";
char arr1[20] = "xxxxxxxxxxxxxxxx";
char * re=my_strcpy(arr1, arr);
printf("%s\n", re);
printf("%s", arr1);
return 0;
}
strncpy的模拟实现
在strcpy的基础上加上num即可
num为0就跳出循环
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, char* src,size_t num)
{
char* re = dest;
assert(dest && src);
while (num--)
{
*dest++ = *src++;
}
return re;
}
int main()
{
char arr[] = "hello";
char arr1[20] = "****************";
size_t num = sizeof(arr1) / sizeof(arr1[0]);
char* ret = my_strncpy(arr1, arr,num);
printf("%s\n", ret);
printf("%s", arr1);
return 0;
}
strcat的使用和模拟实现
- 哪个是dest(目标),在声明的时候要明确其内存大小arr[20]
- 源字符必须包含\0
- 目标字符必须包含\0,足够大,可修改
- 找到目标空间的\0,拷贝数据,拷贝到遇到源字符的\0后停下来
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
char *my_strcat(char *dest,const char * src)
{
assert(dest && src);
//函数也是返回目标的源地址
char* ret = *dest;
//首先找到目标空间的/0,也就是找到其末尾
while (*dest != '\0')
dest++;
//跳出循环的时候是/0的位置
//拷贝
//先拷贝后++
while (*dest++ = *src++)
;//空语句
return ret;
}
int main()
{
//明确内存大小
char arr[20] = "hello ";
char arr1[] = "pby";
//strcat(arr, arr1);
my_strcat(arr, arr1);
printf("%s", arr);
return 0;
}
不可以这样写,arr2=arr1代表的是首元素的地址,就是一个常量的值
但是该代码 无法自己给自己拷贝
会陷入死循环,因为在拷贝的过程中,两个数组是相同的,arr1的/0已经拷贝成了a,arr1拷贝完f后没有\0来停止循环,所以会进入死循环
strncat
也是多了一个长度的参数,可以指定追加多少长长度的字符串
找到字符串第一个出现的/0后追加,并且会追加/0
如果长度超过字符的长度,它并不会自己多追加\0,追加完所有的字符串长度后就不会再追加了
模拟实现strncat
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, char* src, size_t num)
{
assert(dest && src);
char* ret = dest;
while (*dest != '\0')
{
dest++;
}
while (num--)
{
*dest++ = *src++;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
char* ret = my_strncat(arr1, arr2, sizeof(arr2)/sizeof(arr2[0]));
printf("%s\n", ret);
return 0;
}
strcmp
比较字符串内容
相同返回0
arr1>arr2返回1
arr2<arr1返回-1
vs返回的是0,-1,1,但是规定返回值其实是>0,<0,0
一个一个的比较ASCII值
如果比较到\0会怎么比较:
这个比较的时候,是比较\和e,\的ASCII值为0
所以在判断的时候if语句是>0,<0,=0的条件
strmcy模拟实现
- 相等的时候往后走
- 如果不相等就if语句去判读
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
int my_strmcy(const char * str1, const char * str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
str1++;
str2++;
if (*str1 == '/0')
{
return 0;
}
}
//大于会返回大于0的数,小于会返回小于0的数
return *str1 - *str2;
/*if (*str1 > *str2)
{
return 1;
}
else
{
return -1;
}*/
}
int main()
{
char arr[] = "abq";
char arr2[] = "abcdef";
int ret = my_strmcy(arr, arr2);
printf("%d", ret);
return 0;
}
strncmp
指定长度的比较
strcpy和strncpy比较
只拷贝长度为3的字符,所以只拷贝到了abc,并且没有拷贝/0,只拷贝了3个
如果是拷贝长度为8,比字符串的长度更长,他会凑满8个,后面两个拷贝2个\0
strstr的使用
- char * strstr (const char * str1,const char * str2);
- 返回str2在str1中第一次出现的位置,没有出现的话返回空指针。
- 字符串比较匹配不包含\0字符,以\0作为结束标志
strstr模拟实现
- 我们需要一个指针变量,记录起始位置和结束位置,否则无法知道从哪开始匹配成功的
- 还需要两个指针变量,记录起始位置位置。因为在匹配的过程中位置会发生变化
- 指针cur存放的是当前匹配的起始位置,判断起始位置是否为/0后进入while循环,进入while循环后,将其起始位置赋给s1,将字符串2赋给s2去匹配,如果s1=s2就++,继续匹配下一个地址的内容,如果匹配不成功,则跳出while循环。跳出while循环后,cur++使得起始位置+1,继续重新匹配
- 但是同时s1和s2不能等于='\0',因为如果是最后匹配成功了,但是因为没有前面的条件无法跳出循环。所以设置该条件是为了使得s1和s2还有继续匹配的寄回
- 如果匹配到s2='\0',那就说明找到了,返回cur起始位置
- 如果匹配到起始位置cur都为0了,也就是跳出循环了,那说明匹配完了,找不到了
- 特殊场景:如果str2为空,则直接返回str1
- 最后返回类型需要强制类型转换为(char * ),因为该类型是const char *,需要将其转换为const char *
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
char* my_strstr(char* str1, char* str2)
{
const char * s1 = NULL;
const char * s2 = NULL;
const char * cur = str1;
while (*cur)
{
s1 = cur;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char *)cur;
}
cur++;
}
return NULL;
}
int main()
{
char arr1[] = "abcqqqcp";
char arr2[] = "qqc";
char *ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("没有找到");
}
else
{
printf("%s\n", ret);
}
return 0;
}
strtok的使用
char * strtok (char * str,const char * sep);
- 传NULL也会找到arr2,他会保存刚刚标记的地址,然后在标记的地址开始找下一个标记的位置
- 因为我们是知道传的数组是有三段的,所以我们调用了三次strtok,但是正常情况下我们是不知道数组到底是什么样子的,所以我们需要灵活变换
- 我们添加一个for循环,该循环里面调用了一次strtok后,会判断ret是否为空,如果为空就跳出循环,如果不为空,就继续调用strtok
- 分隔符无顺序可言,写前写后都一样
strerror的使用
char * strerror ( int errnum );
可以把参数部分错误码对应的错误信息的字符串地址返回来
perror
有能力直接打印错误信息。先打印传给perror的字符串,再打印冒号,再打印空格,最后打印错误码对于的错误信息
可以给空字符串,但是不能不给