C语言进阶字符函数和字符串函数

Posted Huang_ZhenSheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言进阶字符函数和字符串函数相关的知识,希望对你有一定的参考价值。

目录

1.strlen:

求字符串长度的三种方法:

 2.strcpy: 

 strcpy 函数的模拟实现

2-1 strncpy

模拟实现strncpy

3.strcat

模拟实现strcat 

3-1 strncat:

 模拟实现strncat

4.strcmp

         模拟实现strcmp 

4-1 strncmp 

 模拟实现strncmp

5.strstr

模拟实现strstr函数(字符串查找算法)

6.strtok

7.strerror

8.内存函数

8.1 memcpy

模拟实现memcpy

8.2 memmove

 模拟实现memove

8.3 memmcmp

8.4 memset


1.strlen:

作用:求字符串长度(不包含\\0)

求字符串长度的三种方法:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
//普通的方法 计数器
int my_strlen(const char* str)
{
	int count = 0;
	assert(str != NULL);
	while (*str != '\\0')
	{
		str++;
		count++;
	}
	return count;
}
int main()
{
	char arr[] = "abc";
	//char arr[] = { 'a', 'b', 'c' };
	int len = my_strlen(arr);//对于strlen,看什么时候遇到'\\0'
	printf("%d\\n",len);
	return 0;
}
//函数递归的版本
int my_strlen(char* str)
{
	if (*str != '\\0')
	{
		return 1 + my_strlen(str+1);
	}
	else
	{
		return 0;
	}
}
int main()
{
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\\n", len);
	return 0;
}
//指针-指针的方法
int my_strlen(char* str)
{
	char* start = str;
	while (*str != '\\0')
	{
		str++;
	}
	return str - start;
}
int main()
{
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\\n", len);
	return 0;
}

1.字符串已经 '\\0' 作为结束标志,strlen函数返回的是在字符串中 '\\0' 前面出现的字符个数(不包含 '\\0' )。
2.参数指向的字符串必须要以 '\\0' 结束。
3.注意函数的返回值为size_t,是无符号的( 易错 )

第三点: 输出的结果:“>”

int main()
{
	if (strlen("abc") - strlen("abcdef") > 0)
	{
		printf(">\\n");
	}
	else
	{
		printf("<=\\n");
	}
	return 0;
}

 2.strcpy: 

作用:拷贝字符串

1.源字符串必须以 '\\0' 结束。
2.会将源字符串中的 '\\0' 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。

 strcpy 函数的模拟实现

2-1 strncpy

作用:将source所指向的字符串中num个字符串拷贝到destination所指向的字符串中

模拟实现strncpy

#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;
	while (num && *dest && *src)
	{
		*dest = *src;
		dest++;
		src++;
		num--;
	}
	while (num)
	{
		*dest = '\\0';
		dest++;
		num--;
	}
	return ret;
}
int main()
{
	char arr1[] = "aaaaaaaaaa";
	char arr2[] = "bbb";
	my_strncpy(arr1, arr2, 4);
	printf("%s", arr1);
	return 0;
}

3.strcat

作用:将source所指向的字符串追加到destination所指向的字符串后

源字符串必须以 '\\0' 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。 

模拟实现strcat 

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest,const char* src)
{
	char* ret = dest;
	//1.找到目标字符串中的\\0
	assert(src && dest);
	while (*dest != '\\0')
	{
		dest++;
	}
	//2.源数据追加过去,包含\\0
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s",arr1);
	return 0;
}

做不到  字符串自己给自己追加,\\0被改变了,找不到结束的标志\\0

3-1 strncat:

作用:在destination所指向的字符串末尾加上num个source所指向的字符串的字符

 模拟实现strncat

char* my_strncat(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;
	while (*ret)
	{
		ret++;
	}
	while (num--)
	{
		*ret = *src;
		ret++;
		src++;
		if (*src == '\\0')//若num大于str2的字符串长度
		{
			return dest;
		}
	}
	*ret = '\\0';
	return dest;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	my_strncat(arr1, arr2, 1);
	printf("%s",arr1);
	return 0;
}

4.strcmp

作用:比较两个字符串是否相等,若字符串相同则返回0

模拟实现strcmp 

#include<stdio.h>
#include<assert.h>
int main()
{
	int ret = strcmp("abbb", "abp");
	printf("%d\\n",ret);
	return 0;
}

int my_strcat(const char* str1,const char* str2)
{
	
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\\0')
		{
			return 0;
		}
		str1++;
		str2++;
	}
	return *str1 - *str2;
	/*if (*str1 > *str2)
	{
		return 1;
	}
	else
	{
		return -1;
	}*/
}
int main()
{
	char p[]= "abcdhf";
	char q[] = "abcdef";
	int ret = my_strcat(p,q);
	if (ret > 0)
	{
		printf("p > q");
	}
	else if (ret < 0)
	{
		printf("p < q");
	}
	else
	{
		printf("p  = q");
	}
	return 0;
}

标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字

4-1 strncmp 

 模拟实现strncmp

int my_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1 && str2);
	while ((*str1 == *str2) &&num)
	{
		str1++;
		str2++;
		num--;
		if (*str2 == '\\0' || num == 0)
		{
			return 0;
		}
	}
	if (*str1 > *str2)
		return 1;
	else
		return -1;
}
int main()
{
	char p[] = "aaaaaaaaaa";
	char q[] = "aaa";
	int ret = my_strncmp(p, q ,3);
	if (ret > 0)
	{
		printf("p > q");
	}
	else if (ret < 0)
	{
		printf("p < q");
	}
	else
	{
		printf("p  = q");
	}
	return 0;
}

长度不受限的字符串函数:strcpy,strcat,strcmp

长度受限制的字符串函数:strncpy,strncat,strncmp

5.strstr

作用:判断str2是否在str1中出现,即str2是否为str1的子串,若是,则返回str2在str1首次出现的字符地址,否则返回NULL

int main()
{
	char arr1[] = "abcdefabcdef";
	char arr2[] = "bcdg";
	char* ret = strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("没找到\\n");
	}
	else
	{
		printf("找到了:%s\\n",ret);
	}
	return 0;
}

模拟实现strstr函数(字符串查找算法)

#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cp = str1;
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		if (*str2 == '\\0')
		{
			return (char*)str1;
		}
		while (*s1 && *s2 && (*s1 == *s2))
		{
			s1++;
			s2++;
		}
		if (*s2 == '\\0')
		{
			return (char*)cp;
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abbbbbbcdefabcdef";
	char arr2[] = "";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("没找到\\n");
	}
	else
	{
		printf("找到了:%s\\n",ret);
	}
	return 0;
}

KMP--字符串算法!

6.strtok

int main()
{
	char arr[] = "abcdef@ghij.tech     hhhh ";
	char* p = "@. ";
	char tmp[30] = { 0 };
	strcpy(tmp, arr);
	char* ret = NULL;
	for (ret = strtok(tmp, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\\n",ret);
	}
	/*ret = strtok(tmp, p);
	printf("%s\\n",ret);

	ret = strtok(NULL, p);
	printf("%s\\n",ret);

	ret = strtok(NULL, p);
	printf("%s\\n",ret);*/
	return 0;
}

7.strerror

作用:返回错误码所对应的错误信息

#include<assert.h>
#include<errno.h>
int main()
{
	FILE * pf = fopen("test.txt","r");
	if (pf == NULL)
	{
		//printf("%s\\n",strerror(errno));
		perror("fopen");
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

              perror:1.首先把错误码转化为错误信息  2.打印错误信息(包含了自定义的信息)

8.内存函数

8.1 memcpy

模拟实现memcpy

void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	while (num --)// 4 3 2 1 
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 20);
	return 0;
}

memcpy函数应该拷贝不重叠的内存,memmove函数可以处理内存重叠的情况 

8.2 memmove

 模拟实现memove

void* my_memove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	if (dest < src)
	{
		//从前向后拷贝
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//从后向前拷贝
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}
int main()
{
	int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memove(arr1, arr1+2, 20);
	return 0;
}

8.3 memmcmp

作用:内存比较

举例: 

int main()
{
	float arr1[] = { 1.0, 2.0, 3.0, 4.0 };
	float arr2[] = { 1.0, 3.0 };
	int ret = memcmp(arr1, arr2, 8);
	printf("%d\\n",ret);
	return 0;
}

8.4 memset

函数的特点:以字节为单位设置内存的

内存设置函数

int main()
{
	int arr[10] = { 0 };
	memset(arr, 1, 20);//把arr这块空间的前20个字节全部设置成1
	return 0;
}

以上是关于C语言进阶字符函数和字符串函数的主要内容,如果未能解决你的问题,请参考以下文章

C语言进阶之旅(12)搞定字符串和内存函数

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针

C语言进阶字符函数和字符串函数