字符串函数和内存函数(下) (字符串查找strstrstrtok,错误信息报告strerror,字符操作内存操作函数memcpy、memmove、memset、memcmp)

目录

一、字符串查找

1) strstr  - 在字符串中查找字符串的位置

1.1使用 

1.2模拟实现strstr

2) strchr - 在字符串中找一个字符 第一次出现 的位置

 3)strrchr - 在字符串中找一个字符 最后一次出现 的位置

2、strtok - 分隔字符串

1)普通使用 

 2)循环使用

二、错误信息报告

1)strerror - 返回错误码,所对应的错误信息(不打印)

 1.1错误代码所指内容

1.2常用例子

2. perror - 打印报错码的信息(结合了 printf + strerror 的功能)

三、字符操作   

1)字符分类函数:判断是否为这类字符,是则返回一个非0的数字,否则返回0

 2)字符转换:大小写字母转换

四、内存操作函数  (任何数据类型都可以操作)

1、memcpy  - 内存数据拷贝函数

1)使用 

 2)模拟实现memcpy

2、memmove - 源空间和目标空间出现重叠时的memcpy

1)使用 

2)模拟实现memmove

3、memcmp - 内存数据比较

4、memset - 内存数据设置


一、字符串查找

1) strstr  - 在字符串中查找字符串的位置

char * strstr ( const char *str1, const char * str2);
在 字符串1 中,找 字符串2 第一次出现的位置 。
如果找到就返回该位置的指针。找不到就返回空指针。

1.1使用 


int main()
{
	char arr1[] = "abcdebcdf";
	char arr2[] = "bcd";
	char* p = strstr(arr1, arr2);

	if (p == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", p);//bcdebcdf
		//返回的是,arr2字符串第一次出现的地址,所以打印字符串%s
		//得到bcdebcdf
	}
	return 0;
}

1.2模拟实现strstr

char* my_strstr(const char* str1, const char* str2)
{
	char* s1 = NULL;
	char* s2 = NULL;
	char* cp = str1;
	
	while (*cp)
	{
		s1 = cp;
		s2 = (char*)str2;

		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}

		if (*s2=='\0')
		{
			return cp;
		}
	
		//*s1 != *s2 不相等,则cp++
		cp++;
	}
	return NULL; //当遍历完arr1都没有找到arr2 的字符串,则返回空指针(找不到)
}
int main()
{
	char arr1[] = "abcdebcdf";
	char arr2[] = "bcd";
	int* p = my_strstr(arr1, arr2);

	if (p == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", p);//bcdebcdf
		//返回的是,arr2字符串第一次出现的地址,所以打印字符串%s
		//得到bcdebcdf
	}
	return 0;
}

2) strchr - 在字符串中找一个字符 第一次出现 的位置

与strstr相似的函数  
在字符串中找一个字符 第一次 出现的位置
 


int main()
{
	char arr1[] = "abcdebcdf";
	int* p = strchr(arr1, 'd'); //在字符串 abcdebcdf 中字符 d,第一次出现的位置

	if (p == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", p);//debcdf

	}
	return 0;
}

 3)strrchr - 在字符串中找一个字符 最后一次出现 的位置

在字符串中找一个字符 最后一次 出现的位置


int main()
{
	char arr1[] = "abcdebcdf";
	int* p = strrchr(arr1, 'c'); //在字符串 abcdebcdf 中字符 d,最后一次 出现的位置

	if (p == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", p);//cdf

	}
	return 0;
}

2、strtok - 分隔字符串

* char* strtok(char* str, const char* sep);
  • sep参数是个字符串,定义了用作分隔符的字符集合
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。

1)普通使用 

分割akai@163.com(随便起的邮箱名,无实际意义)

int main()
{
	char arr1[] = "akai@163.com";
	char arr2[20] = { 0 };
	strcpy(arr2, arr1);//因为strtok函数会改变原字符串,所以我们要拷贝一个,来进行分割操作
	const char* sep = "@.";//创建指向分隔符的指针
	
	//第一次字符串起始是arr2
	char* str= strtok(arr2, sep);//strtok返回的是记录下来的指针位置,所以要用一个指针变量来接收
	printf("%s\n", str);//akai

	//第二次分割的字符串起始是NULL
	str = strtok(NULL, sep);//因为第一次分割后,第一个分割符被替换成了NULL,且该位置被保存
	printf("%s\n", str);//163

	//之后的分割同理第二次
	str = strtok(NULL, sep);
	printf("%s\n", str);//com

	return 0;
}

 2)循环使用

如果分割的部分过多,那么一次一次打印就过于麻烦,于是有了这样的循环切割
分割 192.168.1.1 或者 akai@163.com


int main()
{
	//char arr1[] = "192.168.1.1";
	char arr1[] = "akai@163.com";
	char arr2[20] = { 0 };
	strcpy(arr2, arr1);

	//const char* sep = ".";//分隔符
	const char* sep = "@.";
	char* str = NULL;

	for (str = strtok(arr2, sep); str != NULL; str = strtok(NULL, sep))
	{
		printf("%s\n", str);
	}

	return 0;
}

二、错误信息报告

1)strerror - 返回错误码,所对应的错误信息(不打印)

char * strerror ( int errnum );
返回值为错误信息的指针

 1.1错误代码所指内容


int main()
{
	//每个错误码都对应着一个错误信息,但是需要通过指针来访问
	//因为strerror的返回值是指针
	printf("%s\n", strerror(0));//No error
	printf("%s\n", strerror(1));//Operation not permitted
	printf("%s\n", strerror(2));//No such file or directory
	printf("%s\n", strerror(3));//No such process
	printf("%s\n", strerror(4));//Interrupted function call

	return 0;
}

1.2常用例子

#include <errno.h>
int main()
{
	//打开文件
	//打开文件的时候,如果文件的打开方式是"r"
	//文件存在则打开成功,文件不存在打开失败
	//打开文件失败的话,会返回NULL
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		//因为正在编辑的这个test.c文件的路径下,没有test.txt,所以打不开
		printf("打开文件失败,原因是:%s\n", strerror(errno));//这样就能看到这个保存信息了
		return 1;
	}
	//读写文件
	//...
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

2. perror - 打印报错码的信息(结合了 printf + strerror 的功能)

 与strerror 很相似的函数 

但是这个perror更省事,省去了额外的printf打印


int main()
{
	//打开文件
	//打开文件的时候,如果文件的打开方式是"r"
	//文件存在则打开成功,文件不存在打开失败
	//打开文件失败的话,会返回NULL
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("打开文件失败");//这个更方便
		//相当于 printf + strerror
		//printf("打开文件失败,原因是:%s\n", strerror(errno));

		return 1;
	}
	//读写文件
	//...
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

三、字符操作   

1)字符分类函数:判断是否为这类字符,是则返回一个非0的数字,否则返回0

iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'
isdigit 十进制数字 0~9 字符
isxdigit 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母a~z或A~Z
isalnum 字母或者数字,a~z,A~Z,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符
int main()
{
	//
	//printf("%d\n", iscntrl(6));

	//isspace 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'
	//char ch = '\f';
	//printf("%d\n", isspace(ch));

	//isdigit 十进制数字 0~9 字符
	//char ch = '7';
	//printf("%d\n", isdigit(ch));

	//isxdigit 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
	//char ch = 'f';
	//printf("%d\n", isxdigit(ch));

	//islower
	//char ch = 'k';
	//printf("%d\n", islower(ch));

	//isupper
	//char ch = 'L';
	//printf("%d\n", isupper(ch));

	//isalpha 字母a~z或A~Z (包含isupper、islower)
	//char ch = 'c';
	//printf("%d\n", isalpha(ch));

	//ispunct 标点符号(punctuation) 任何不属于数字或者字母的图形字符
	//char ch = '?';
	//printf("%d\n", ispunct(ch));
	只能判断英文的非数字或者字母的图形字符(例如?),中文的会报错(例如:?)

	//isgraph 任何图形字符
	//char ch = '1';// ~ ` A a 1 空格
	//printf("%d\n", isgraph(ch));

	//isprint 任何可打印字符,包括图形字符和空白字符
	//char ch = 'a';// ~ ` A a 1 ()
	//printf("%d\n", isprint(ch));

	return 0;
}

 2)字符转换:大小写字母转换

int tolower ( int c );
int toupper ( int c )

toupper 将英文字符转为大写
tolower 将英文字符转为小写


int main()
{
	char arr1[20] = "HellO BiT";
	char arr2[20] = "NihaO BiT";
	int i = 0;
	while(arr1[i])
	{
		printf("%c",toupper(arr1[i]));
		i++;
	}

	printf("\n");
	i = 0;
	while (arr1[i])
	{
		printf("%c", tolower(arr2[i]));
		i++;
	}

	return 0;
}

 

四、内存操作函数  (任何数据类型都可以操作)

以下内存操作函数,是通过调用函数方式,调试观察现象
主函数如下:
int main()
{
	//test_memcpy();
	//test_my_memcpy();
	//test_memmove();
	//test_my_memmove();
	//test_memcmp();
	test_memset();
	return 0;
}

1、memcpy  - 内存数据拷贝函数

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的

1)使用 

test_memcpy()//调试观察
{
	//mempcy函数返回的是目标空间的起始地址

	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 20);//拷贝前五个整型,4*5=20字节

	float arr3[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
	float arr4[8] = { 0 };
	//把arr1中的前3个数据拷贝到arr2中
	memcpy(arr4, arr3, 12);//3*4=12

}

 2)模拟实现memcpy


#include<assert.h>
void* my_memcpy(void* dest, const void* src,size_t num)//拷贝时,源字符串是不能被改变的,加上const
{
	assert(dest && src);//断言,是否为有效指针

	void* ret = dest;//记录目的字符串的起始值,方便最后的返回
	while (num--)
	{
		*(char*)dest = *(char*)src;//先对指针强制类型转换为char*,一个字节一个字节拷贝
		dest = (char*)dest+1;//指针+1,也要强制类型转换
		src = (char*)src+1;

	}
	return ret;
}
void test_my_memcpy() //调试查看
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	//把arr1中的前5个数据拷贝到arr2中
	my_memcpy(arr2, arr1, 20);
}

2、memmove - 源空间和目标空间出现重叠时的memcpy

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理

C语言:memcpy拷贝不重叠的内存
重叠的就交给memmove
能力:memmove > memcpy

1)使用 


test_memmove()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	// 想通过my_memcpy(arr1+2, arr1, 20);//无法实现
	//   实现       1 2 1 2 3 4 5 8 9 10
	
	//当操作同一组数据,且源数据和目的数据有交集时,可以通过memmove来实现
	memmove(arr1 + 2, arr1, 20); 

	//my_memcpy(arr1+2, arr1, 20); 
	
	//本应该报错的,但是因为vs的优化,使得memcpy与memmove作用相同
	// 但是不能保证其他编译器也可以这样正常运行,所以建议用memmove
	//memcpy(arr1, arr1 + 2, 20);
	//memcpy(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}

}

2)模拟实现memmove


void* my_memmove(void* dest,const void* src,size_t num)
{
	assert(dest && src);
	void* ret = dest;
	//当dest<src时,应该从前往后移动
	if(dest<src)
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	//当dest>src时,应该从后往前移动
	else
	{
		while (num--)//num=20
		{
			//num=19  - 此时正好指向最后一个数据的最后一个字节
			//从这个位置开始,往前移动
			*((char*)dest+num) = *((char*)src+num);

		}
	}

	return ret;
}
test_my_memmove()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };

	my_memmove(arr1 + 2, arr1, 20);
	//my_memmove(arr1, arr1+2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}

}

3、memcmp - 内存数据比较

int memcmp ( const void * ptr1,const void * ptr2,size_t num );
比较多少个字节的字符,
>,返回一个>0的数
相同,返回0
<,返回一个<0的数


test_memcmp()
{
	int arr1[] = { 1,2,3,4 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
	int arr2[] = { 1,2,3,5 };//01 00 00 00 02 00 00 00 03 00 00 00 05 00 00 00
	
	int ret = memcmp(arr1, arr2,12);//比较前3个数据,是相同的;返回0
	printf("%d\n", ret);

	ret = memcmp(arr1, arr2, 13);//比较前3个数据+1个字节,刚好小端存储的第13个字节为04 05
	//4<5,返回一个小于 0 的数
	printf("%d\n", ret);
}

4、memset - 内存数据设置

test_memset()
{
	char arr[] = "hello_bit";
	memset(arr,6, 5);//将前5个块,设置为6
	//6 6 6 6 6 _ b i t

	错误示范
	//int arr[10] = { 0 };
	01 01 01 01
	00000001000000010000000100000001 - 16843009
	//memset(arr, 1, sizeof(arr));//这种写法无法将数据的每个元素设置为1
	//int i = 0;
	//for (i = 0; i < 10; i++)
	//{
	//	printf("%x ", arr[i]);
	//}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值