C语言的字符函数和字符串函数使用和模拟实现

strlen函数

  1. 求的是字符串的长度,统计的是字符串中\0之前的字符个数
  2. 返回值是size_t,是无符号的
  3. 无符号数相减也是无符号数,所以打印的是>

除非转化为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的使用和模拟实现

  1. 哪个是dest(目标),在声明的时候要明确其内存大小arr[20]
  2. 源字符必须包含\0
  3. 目标字符必须包含\0,足够大,可修改
  4. 找到目标空间的\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模拟实现

  1. 相等的时候往后走
  2. 如果不相等就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的使用

  1. char * strstr (const char * str1,const char * str2);
  2. 返回str2在str1中第一次出现的位置,没有出现的话返回空指针。
  3. 字符串比较匹配不包含\0字符,以\0作为结束标志

strstr模拟实现

  1. 我们需要一个指针变量,记录起始位置和结束位置,否则无法知道从哪开始匹配成功的
  2. 还需要两个指针变量,记录起始位置位置。因为在匹配的过程中位置会发生变化
  3. 指针cur存放的是当前匹配的起始位置,判断起始位置是否为/0后进入while循环,进入while循环后,将其起始位置赋给s1,将字符串2赋给s2去匹配,如果s1=s2就++,继续匹配下一个地址的内容,如果匹配不成功,则跳出while循环。跳出while循环后,cur++使得起始位置+1,继续重新匹配
  4. 但是同时s1和s2不能等于='\0',因为如果是最后匹配成功了,但是因为没有前面的条件无法跳出循环。所以设置该条件是为了使得s1和s2还有继续匹配的寄回
  5. 如果匹配到s2='\0',那就说明找到了,返回cur起始位置
  6. 如果匹配到起始位置cur都为0了,也就是跳出循环了,那说明匹配完了,找不到了
  7. 特殊场景:如果str2为空,则直接返回str1
  8. 最后返回类型需要强制类型转换为(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);

  1. 传NULL也会找到arr2,他会保存刚刚标记的地址,然后在标记的地址开始找下一个标记的位置
  2. 因为我们是知道传的数组是有三段的,所以我们调用了三次strtok,但是正常情况下我们是不知道数组到底是什么样子的,所以我们需要灵活变换
  3. 我们添加一个for循环,该循环里面调用了一次strtok后,会判断ret是否为空,如果为空就跳出循环,如果不为空,就继续调用strtok
  4. 分隔符无顺序可言,写前写后都一样

strerror的使用

char * strerror ( int errnum );

可以把参数部分错误码对应的错误信息的字符串地址返回来

perror

有能力直接打印错误信息。先打印传给perror的字符串,再打印冒号,再打印空格,最后打印错误码对于的错误信息

可以给空字符串,但是不能不给

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值