字符函数和字符串函数

0.前言

c语言中对字符和字符串的处理很频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串或者字符数组中。
字符串常量适用于那些对它不做更改的字符串函数。

1.函数介绍

1.1 strlen

size_t my_strlen(const char* str)//自己模拟实现strlen,这个函数只计算长度,不会修改字符串,所以可以使用const限制一下,使函数更加稳定。
{
	int count = 0;
	while (*str++)
	{
		count++;
	}
	return count;
}

int main()
{
	char arr[] = "abcdefg";
	printf("%d", my_strlen(arr));
	return 0;
}
//另一种方法就是用两个指针指向

求字符串长度的,统计的是字符串中 \0 之前出现的字符个数。
注意函数的返回值 size_t 是无符号整型
无符号数一定大于0.

1.2 strcpy

char* my_strcpy(char* p1,const char* p2)//自己模拟实现strlen
{
	char* ret = p1;
	while (*p1++ = *p2++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr[10] = "xxxxxxxxx";
	char arr2[] = {'b', 'i', '\0', 't'};
	printf("%s", my_strcpy(arr, arr2));
	return 0;
}

参数是目标空间的地址和被复制字符串的地址。
把被复制字符串的数据拷贝到目标空间中
拷贝数据的时候,遇到 \0 才停止,所以被拷贝字符串必须含有 \0 。
目标空间必须足够大,确保能够放下字符串。
目标空间可变。
函数中如果有不需要变化的,可以在前面加上const增强函数的 的稳定性。
链式访问——一个函数的返回值作为另一个函数的参数。
回调函数——将一个函数的地址作为参数传入另一个函数。然后再另一个函数中被调用。
常量字符串是不能被修改的 : char* p = “abcdef”;//常量字符串abcdef

1.3 strcat

char* mt_strcat(char* p1,const char* p2)
{
	char* ret = p1;
	while (*p1++)//寻找目标函数的末尾的\0
	{
		;
	}
	while (*p1++ = *p2++)//开始从目标字符串结尾追加
	{
		;
	}
	return ret;
}

int main()
{
	char arr[20] = "abcdefg";
	char arr2[] = "word";
	printf("%s\n", mt_strcat(arr, arr2));
	return 0;
}

字符串追加函数
把源头的数据追加到目标后面去。

1.4 strcmp

int my_strcmp(const char* p1,const char* p2)
{
	
	while (*p1 == *p2)
	{
		if (*p1 == '\0')
		{
			return 0;
		}
		p1++;
		p2++;
	}
	return *p1 - *p2;
}
int main()
{
	char arr1[] = "abcdefg";
	char arr2[] = "abcd";
	printf("%d", my_strcmp(arr1, arr2));
	return 0;
}

对比的两个字符串都要有 \0 .

长度不受限制的字符串函数:
strcpy strcat strcmp
长度受限的字符串函数:
strncpy strncat strncmp

1.5 strncpy

char* my_strncpy(char* p1,const char* p2, int a)
{
	char* ret = p1;
	while (a)
	{
		a--;
		*p1++ = *p2++;
		if (*p2 == '\0')
		{
			while (a)
			{
				a--;
				*p1++ = '\0';
			}
			return ret;
		}
	}
	return ret;
}
int main()
{
	char arr1[] = "abcdefg";
	char arr2[] = "word";
	printf("%s", my_strncpy(arr1, arr2, 4));
	return 0;
}

1.6 strncat

在追加完之后,这个函数会主动在最后放上一个 \0.
模拟思路分析:
首先这个函数中有一个整型可以控制追加的字符个数,然后在追加完了,还会在末尾补上一个 \0。它的返回值则是目标字符串的首字母地址。
首先是通过接收的参数,利用循环找到目标字符串中\0的地址,然后再利用循环使源字符串追加到目标字符串上,同时这个循环的条件为控制追加字符个数的整型。

char* my_strncat(char* p1, char* p2, int a)
{
	char* ret = p1;
	while (*p1)
	{
		p1++;
	}
	while (a)
	{
		*p1++ = *p2++;
		a--;
	}
	*p1 = '\0';
	return ret;
}
int main()
{
	char arr1[20] = "abcdefg\0xxxxxx";
	char arr2[] = "word";
	printf("%s", my_strncat(arr1, arr2, 3));
	return 0;
}

1.7 strncmp

int my_strncmp(char* p1, char* p2, int a)
{
	while (*p1 == *p2)
	{
		a--;
		p1++;
		p2++;
	}
	return *p1 - *p2;
}

int main()
{
	char arr1[20] = "abcdefg";
	char arr2[] = "abadg";
	int ret = my_strncmp(arr1, arr2, 4);
	if (ret > 0)
		printf("arr1>arr2\n");
	else if(ret<0)
		printf("arr1<arr2\n");
	else
		printf("arr1=arr2\n");
	printf("%d", ret);

	return 0;
}

比较两个字符串的大小,首先是找到两个字符串的首字符的地址,然后进行比较,比较一次,控制次数的整形减一。

1.8 strstr

char* my_strstr(char* p1, char* p2)
{
	char* a = p1;
	char* b = p2;
	//首先,开始上面的比较两个是否相同,相同一起比较下一个不相同,上面的加一
	while (*p1 != '\0')
	{
		if (*p1 == *p2)
		{
			a = p1;
			while (*p1++ == *p2++)
			{
				if (*p2 == '\0')
				{
					return a;
				}
				if (*p1 == '\0')
				{
					return NULL;
				}
			}
			p1 = a + 1;
			p2 = b;
		}
		else
		{
			p1++;
		}
	}
	return NULL;
}

int main()
{
	char arr1[] = { "aabcabcddfg" };
	char arr2[] = { "abcddf" };
	char* p = my_strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("不存在\n");
	}
	else
	{
		printf("%s\n", p);
	}
	return 0;
}

在一个字符串中找另一个字符串是否存在。
如果存在,返回字串所在的起始地址,不存在返回空指针。

1.9 strtok

char * strtok (char * str, constchar * sep );

  1. sep参数是个字符串,定义了用作分隔符的字符集合
  2. strtok函数会找到str中的下一个标记,并将其改成’ \0 ',返回一个指向这个标记的指针,strtok真的会改变这个字符串,所以strtok切分的字符串一般都是临时拷贝出来的可修改的字符串。
  3. 函数的第一个参数不为null,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  4. strtok函数中的第一个函数为null,函数将在同一个字符串中被保存的位置开始,查找下一个标记
  5. 如果字符串中不存在更多标记,则返回NULL 指针。
int main()
{
	char arr[] = "weisiyuan@hongxiaozi.com";//这里的@和.就是分隔符,就是上述sep的字符串中的字符
	char arr2[200] = { 0 };
	strcpy(arr2, arr);//将用到的字符串拷贝出来,因为strtok真的会更改字符串
	const char* p = "@.";
	char * str = NULL;
	for(str = strtok(arr, p); str!= NULL; str = strtok(NULL, p) )
	{// 起始, 判断, 改变
		printf("%s\n", str);
	}
 	return 0;
}

1.10 strerror 和 errno

char * strerror ( int errno)//把错误码转换成错误信息

int main()
{
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));
	//记录错误码的变量 errno;
	//#include <errno.h>
	FILE* pf = fopen("test.txt", "r");
	if(pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	// 读文件
	 
	fclose(pf);
	pf = NULL;
	return 0;
}

2.1 memcpy //内存拷贝

void my_memcpy( void * des, const void * source, size_t num);

void* my_memcpy(void * p1, const void* p2, size_t i)
{
	void* ret = p1;
	while (i--)//挨个字节递减,直到i变为0
	{
		*(char*)p1 = *(char*)p2;
		((char*)p1)++;//先将无类型的指针转换成字符指针,再+1
		((char*)p2)++;
	}
	return ret;
}

int main()
{
	int arr[20] = { 0 };
	int arr2[20] = { 1,2,3,4,0,6,7,8,9,10 };
	int* a = (int *)my_memcpy(arr, arr2, 24);
	int i = 0;
	while (*a)
	{
		printf("%d", *a);
		a++;
	}
	return 0;
}

2.2 memmove

void* memmove(void * destination , void * source, size_t num);
//重叠内存的拷贝,也就是源空间和目标空间出出现重叠,就得使用memmove函数处理。

void* my_memmove( void* str, void* dec, size_t num)//重叠内存的拷贝
{
	void* aka = str;

	if (str > dec)
	{
		while (num--)
		{
			*((char*)str+num) = *((char*)dec+num);
		}
	}
	else
	{
		while (num--)
		{
			*(char*)str = *(char*)dec;
			str = (char*)str + 1;
			dec = (char*)dec + 1;
		}
	}
	return aka;
}

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,0};
	int * p = (int*)my_memmove(arr,arr+1, 20);

	int i = 0;
	while (*p)
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

2.3 memset

void memset (void * dest , int c, size_t count)
以字节为单位,修改
c是你想修改的值,count代表你想修改多少个字节。

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,0 };
	memset(arr, 0, 20);
	int* p = arr;
	//20个字节,也就是5个整型,可以将前五个元素改成0,
	return 0;
}

字符函数

int main()
{
	char ch = 'a';
	int ret = isdigit(ch);
	pritnf("%d\n", ret);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值