文章目录
实现strlen()的三种方法
size_t my_strlen(char* arr)
{
法1
//int count = 0;
//while (*arr)
//{
// count++;
// arr++;
//}
//return count;
//法2
//if (*arr)
// return 1 + my_strlen(arr + 1);
//else
// return 0;
//法3
//char* p = arr;
//while (*arr)
//{
// arr++;
//}
//return arr - p;
}
test1()
{
char arr1[] = "abcdef";
int len =my_strlen(arr1);
printf("%d", len);
}
int main()
{
test1();
}
比较简单,要注意的是法3中,指针-指针算的是指针之间的元素个数
实现字符串拷贝strcpy()
#include <assert.h>
char * my_strcpy(char*dest,const char*source)
{
assert(dest&&source);
char* p = dest;
while (*dest++ = *source++)
{
;
}
return p;
}
test2()
{
char arr1[] = "abcdef";
char arr2[20] = "xxxxxxxxxxxxx";
my_strcpy(arr2,arr1);
printf("%s", my_strcpy(arr2, arr1));
}
int main()
{
/*test1();*/
test2();
}
实现讲解以及注意事项
- 源字符串必须以\0结束,意味着arr1数组不能没有只有a,b,c,d,e,f,必须包含\0
- 拷贝时会将源字符串中的\0拷贝到目标空间
- 目标空间必须足够大
- 目标空间必须可变,意味着不能给一个char*p来接收"xxxxxxxx",因为此时该字符串为常量字符串,不可被更改
- 由于源字符串不需要被修改,所以加上const更安全
实现字符串追加strcat()
#include <assert.h>
char* my_strcat(char* dest, const char* source)
{
assert(dest&&source);
char* p = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *source++)
{
;
}
return p;
}
test3()
{
char arr1[] = "abcdef";
char arr2[20] = "xxx\0xxxxxxxxxx";
printf("%s", my_strcat(arr2, arr1));
}
int main()
{
/*test1();*/
/*test2();*/
test3();
}
实现讲解以及注意事项
- 源字符串会找到目标字符串中的\0,并由此进行追加
- 源字符串和目标字符串都必须有\0
- 目标空间必须可更改
- 函数实现其实就是给目标字符串遍历找到\0+strcpy
- 不可以实现自己给自己追加,因为当自己给自己追加时,会把源字符串原来的\0覆盖掉,这样就会无限追加下去
- 使用strcat不可以进行自我追加
实现字符串比较strcmp()
int my_strcmp(char* str1, char* str2)
{
while (*str1 == *str2)
{
if (*str1== '\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
test4()
{
char arr1[] = "abcdefg";
char arr2[20] = "abcdefg";
printf("%d", my_strcmp(arr1, arr2));
}
int main()
{
/*test1();*/
/*test2();*/
/*test3();*/
test4();
}
实现讲解以及注意事项
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
strncpy
如图可见,strncpy会将arr1的前5个字节拷贝到arr2中,不会把\0也拷贝进去,如果拷贝10个字节,将arr1的内容拷贝过去后,剩下的补\0
strncat
如图,strncat进行追加时会追加\0,并且可以实现自己给自己追加
strncmp
如图,即使是比较10个字节,还是比较到不同的字符截止,或到\0截止
strstr()
char* my_strstr(char* str1, char* str2)
{
char* p = str1;
char* s2 = str2;
while (*p)
{
str1 = p;
s2 = str2;
while (*str1&&*s2&&*str1 == *s2)
{
str1++;
s2++;
}
if (*s2 == '\0')
{
return p;
}
p++;
}
return NULL;
}
int main()
{
char arr1[] = "aabbabcdefaa";
char arr2[] = "abcdef";
char* p = my_strstr(arr1,arr2);
if (p == NULL)
{
printf("找不到");
}
else
printf("%s", p);
}
实现讲解以及注意事项
在arr1中找arr2,找到了则返回arr1对应的地址,找不到则返回NULL
strtok
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abc'dwadfa;dadwdaw";
char sp[] = "';";
char* p = NULL;
//printf("%s\n",p);
//p = strtok(NULL, sp);
//printf("%s\n", p);
//p = strtok(NULL, sp);
//printf("%s\n", p);
//p = strtok(NULL, sp);
//printf("%s\n", p);
for (p = strtok(arr1, sp); p != NULL;p = strtok(NULL,sp))
{
printf("%s\n",p);
}
}
实现讲解以及注意事项
函数的第一个参数是指定一个字符串,它包含有sp组成的多个分割符
第二个参数为一个包含分隔符字符串
第一次传被查找的字符串地址arr1,找到下一个标记即分隔符,将标记置为\0,返回标记的字符串的首元素地址,并保存这个标记的地址,下一次传NULL,从上一个保存的标记的地址之后继续查找,当查找时,找不到后面标记时,返回空指针
strerror
FILE*pf = fopen("test.txt", "r");
if (pf == NULL)
{
printf("%s", strerror(errno));
//perror("打开文件失败");
return 1;
}
fclose(pf);
pf = NULL;
若打开文件失败,返回NULL,当函数调用失败会将一个错误码放在errno中,strerror会将errno翻译成错误信息,返回错误信息的首地址,perror相当于strerror+printf()
memcpy
void* my_memcpy(void* s2, const void* s1, int num)
{
void* ret = s2;
while (num--)
{
*(char*)s2 = *(char*)s1;
s2 = (char*)s2 + 1;
s1 = (char*)s1 + 1;
}
return ret;
}
int main()
{
double arr1[] = { 1.1,2.3,4.4 };
double arr2[10] = { 0.0 };
double*p = (double*)my_memcpy(arr2, arr1, 24);
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%lf\n", p[i]);
}
return 0;
}
(char)s2 = (char)s1;
s2 = (char*)s2 + 1;
s1 = (char*)s1 + 1;
对于这一块代码,由于强制类型转换时临时的,也就是说* (char*)s2 = * (char*)s1;这个表达式完了之后,s2,s1又是void *
类型,需要再次强转,我们尽量不要对强转的变量进行++,–操作,容易出错,所以换了另一种写法
memcpy是内存块拷贝,可以拷贝任意类型,遇到\0也不会停止
第一个参数是目的地,第二个是源头,第三个是拷贝多少个字节
不能拷贝本身
它的缺陷是不能完成对自身的拷贝
memmove
void* my_memmove(void* s2,void* s1,int num)
{
void* ret = s2;
if (s2 < s1)
{
while (num--)
{
*(char*)s2 = *(char*)s1;
s2 = (char*)s2 + 1;
s1 = (char*)s1 + 1;
}
}
else
while (num--)
{
*((char*)s2 + num) = *((char*)s1 + num);
}
}
int main()
{
int arr1[] = { 1,2,4,5,7,8,9,10 };
my_memmove(arr1, arr1+2, 12);
int i = 0;
for(i =0; i < sizeof(arr1)/sizeof(arr1[0]);i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
当source>dest时,为了防止sorce中的数据被覆盖,采用从前向后开始拷贝
当sorce<dest时,采用从后向前拷贝
memmove的优势就是可以进行自身的字符串拷贝
memcmp
int main()
{
int arr1[] = {2,2,4,6,4};
int arr2[] = {2,2,4,6,5};
int ret = memcmp(arr1, arr2, 17);
printf("%d", ret);
return 0;
}
比较两个内存块大小,在vs环境下为小端存储,第17个字节以十六进制显示为arr1位04,arr2为05,所以打印-1
memset
int main()
{
int arr1[] = { 2,2,4,6,4 };
int ret = memset(arr1,1,sizeof(arr1));
int i = 0;
for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
{
printf("%p ", arr1[i]);
}
return 0;
}
memset是将arr1数组的前sizeof(arr1)个字节的数据改为1
它是一个字节一个字节改的,如上图