字符函数和字符串函数的使用

字符函数和字符串函数的使用

  1. 求字符串长度 strlen
  2. 长度不受限制的字符串函数 strcpy strcat strcmp
  3. 长度受限制的字符串函数介绍
    strncpy strncat strncmp
  4. 字符串查找 strstr strtok
  5. 错误信息报告 strerror
  6. 内存操作函数memcpy memmove memset memcmp

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

strlen

size_t strlen(const char* str)

字符串已经’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含’\0’);参数指向的字符串必须要以’\0’结束注意函数的返回值为size_t,是无符号的学会strlen函数的模拟实现,size_t是unsigned int 是无符号的整数

strlen深入理解

size_t strlen(const char* str);
//size_t 就是unsigned int是一个无符号的数字
//
int main()
{
    
    
	if (strlen("abc") - strlen("abcdef") > 0)
	{
    
    
		printf("hehe\n");
	//结果肯定是hehe因为size_t是一个无符号的数字,所以无符号减去无符号得到的一定是一个无符号的数
	//一定是要给大于0的数字 -3被当作无符号数就是3 所以结果是hehe
	}
	else
	{
    
    
		printf("haha\n");
	}
	return 0;
}

下面代码是模拟实现strlen

size_t strlen(const char* str);
size_t 就是unsigned int是一个无符号的数字
int	 my_strlen(const char* str)//常量字符串不能改变
{
    
    
	int count = 0;
	assert(str != NULL);//保证指针有效性
	while (*str != '\0')
	{
    
    
		count++;
		str++;
	}
	return count;
}
int main()
{
    
    
	int arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

strcpy 字符串拷贝

strcpy的参数是:

char* strcpy(char* destination, const char * source);
desitination是目的地,source是源头
1:源字符串必须以'\0'结束
2:会将源字符串中的'\0'拷贝到m目标空间
3:目标空间必须足够大,以确保能存放源字符串
4:目标空间必须可变
5:学会模拟实现

strcpy的用法

int main()
{
    
    
	char arr1[] = "abcdefghi";
	char arr2[] = "bit";
	strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

模拟实现strcpy

char* my_strcpy(char* dest,const  char* src)
{
    
    
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	//拷贝src指向的字符串到dest指向的空间,包含'\0'
	while (*src != '\-')
	{
    
    
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src; //这里是将arr2的'\0'拷贝过去
	return ret;//返回目的空间的起始位置
}
int main()
{
    
    
	char arr1[] = "abcdefghi";//这是目的地必须足够大
	char arr2[] = "bit";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

strcat 字符串追加

char * strcat (char* destination, const char * source);
字符串追加

1.源字符串必须以 '\0'结束
2.目标空间必须有足够的大,能容纳下源字符串的内容
3.目标空间必须可修改
4.字符串自己给自己追加如何
自己给自己追加要使用strncat

strcat的用法是什么

int main()
{
    
    
	char arr1[30] = "hello";
	char arr2[] = "world";
	strcat(arr1, arr2);//strcat 将arr2中的内容,追加到arr1的后面去
	printf("%s\n", arr1);
	return 0;
}

模拟实现strcat

char* my_strcat(char* arr1,const char* arr2)
{
    
    
	char* ret = arr1;
	assert(arr1 != NULL);
	assert(arr2 != NULL);
	//1.找到目的字符串'\0'
	while (*arr1 != '\0')
	{
    
    
		arr1++;
	}
	while (*arr2 != '\0')
	{
    
    
		*arr1 = *arr2;
		arr1++;
		arr2++;
	}
	*arr1 = *arr2;
	return ret;//返回arr1
}
int main()
{
    
    
	char arr1[30] = "hello";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s\n",arr1);
	return 0;
}

strcmp 字符串比较

int strcmp(const char * str1,const char* str2);参数

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

strcmp的用法是什么

int main()
{
    
    
	char* p1 = "asbc";
	char* p2 = "def";
	int ret = strcmp(p1, p2);
//这里是按照字符串的ASCII码值来进行比较的a的ASCIl值在字符串最小Z的ASCII码值最大
	printf("%d\n", ret);//-1

	if (strcmp(p1, p2) > 0)
	{
    
    
		printf("p1>p2\n");
	}
	else if (strcmp(p1, p2) == 0)
	{
    
    
		printf("p1======p2\n");
	}
	else if (strcmp(p1, p2) < 0)
	{
    
    
		printf(" p1<p2\n");
	}
	return 0;
}

模拟实现strcmp

int	my_strcmp(char* p1,char* p2)
{
    
    
	assert(p1 != NULL);
	assert(p2 != NULL);
	while (*p1 == *p2)
	{
    
    
		if (*p1 == '\0')
		{
    
    
			return 0;
		}
		p1++;
		p2++;
	}
 return (*p1-*p2)
 }
 int main()
{
    
    
	char* p1 = "abcdef";
	char* p2 = "abcdds";
	int ret = my_strcmp(p1, p2);
	if (ret == 1)
	{
    
    
		printf("p1>p2\n");
	}
	else if (ret == -1)
	{
    
    
		printf("p1==p2\n");
	}
	else
	{
    
    
		printf("p1<p2\n");
	}
	return 0;
}

strncpy

char* strncpy(char* strDest,const char* strSource,size_t num); num单位是字节

拷贝num个字符从源字符串到目标空间
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,知道num个

strncpy的用法

int main()
{
    
    
	char arr1[10] = "abcdef";
	char arr2[] = "hello bit";
	strncpy(arr1, arr2, 4);
	printf("%s\n", arr1);
	return 0;
}

strncat

参数
char * strncat(char * destination, const char * source,size_t num);//追加

strncat的用法

int main()
{
    
    
	char arr1[30] = "hello\0xxxxaxx";
	char arr2[] = "world";
	strncat(arr1, arr2, 3);
	/*
	这里将arr2的前三个字符追加上去
	w追加到\0处
	o追加到x出
	r追加到x出
	但是追加完了之后还是会补上一个\0的
	所以结果会是hellowor
	r的后面会自己补上要给\0的
	如果你的个数比字符串还长,那么是会把字符串追加完了之后加上一个\0就完了
	*/
	printf("%s\n", arr1);
	return 0;
}

strncmp

参数是:int strncmp(const char * str1,const char * str2, size_t num);

int main()
{
    
    
	//strncmp - 字符串比较
	const char* p1 = "abcdef";
	const char* p2 = "abcdqwer";
	int ret = strncmp(p1, p2, 6);
	//比较字符串中几个字符
	printf("%d\n", ret);
	return 0;
}

strstr 找子字符串, 查找字符串

参数是: char* strstr(const char* ,const char*);

strstr的用法

int main()
{
    
    
	char* p1 = "abcdefsss";
	char* p2 = "def";
	char* ret = strstr(p1, p2);
	/*
	要去p1指向的字符串里面找p2指向的字符串存不存在,也就是在p1里面找p2存不存在
	如果存在返回 返回存在的首字符的地址,如果不存在,返回NULL空指针
	*/
	if (ret == NULL)
	{
    
    
		printf("子串不存在\n");
	}
	else
	{
    
    
		printf("%s\n", ret);//defsss
		//按照返回首字符的地址进行打印该地址开始到后面的字符
	}
	return 0;
}

注意平时看英文文档时

看文档时:NULL–空指针
NUL/Null 表示’\0’

模拟实现strstr

char* my_strstr(const char* p1,const char* p2)
{
    
    
	assert(p1 != NULL);
	assert(p2 != NULL);
	char *s1 = p1;
	char *s2 = p2;
	char *cur = p1;
	if (*p2 == '\0')
	{
    
    
		return p1;
	}
	while (*cur)
	{
    
    
		s1 = cur;
		s2 = p2;
		while ((*s1 != '\0')&&(*s2 != '\0')&&(*s1 ==*s2))
		{
    
    
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
    
    
			return cur;//找到子串
		}
		cur++;
	}
	return NULL;//找不到子串
}
int main()
{
    
    
	char * p1 = "abbbcdef";
	char * p2 = "bbc";
	char * ret = my_strstr(p1, p2);
	if (ret == NULL)
	{
    
    
		printf("子串不存在\n");
	}
	else
	{
    
    
		printf("%s\n",ret);
	}
	return 0;
}
模拟实现my_strstr
char* my_strstr(const char* p1,const char* p2)
{
    
    
	assert(p1 != NULL);
	assert(p2 != NULL);
	char* s1 = p1;
	char* s2 = p2;
	char* cu = p1;
	if (*p2 == '\0')
	{
    
    
		return p1;
	}
	while (*cu)
	{
    
    
		s1 = cu;
		s2 = p2;
		while ((*s1 != '\0') && (*s2 != '\0')&&(*s1 == *s2))
		{
    
    
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
    
    
			return cu;
		}
		cu++;
	}
	return NULL;
}
int main()
{
    
    
	char* p1 = "abbbcdef";
	char* p2 = "bbc";
	char* ret = my_strstr(p1, p2);
	if (ret == NULL)
	{
    
    
		printf("没有找到子串\n");
	}
	else
	{
    
    
		printf("%s\n", ret);
	}
	return 0;
}

strtok 字符串切割打印

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

分隔符理解

192.168.31.121 //这里的分隔符就是 .
192.168.31.121 - strtok
[email protected] //这里的分隔符就是@和.
zpw bitdu tech

strtok的使用

int main()
{
    
    
	char arr[] = "[email protected]";
	char* p = ("@.");
	char buf[1024] = {
    
     0 };
	strcpy(buf,arr);
	//切割buf中的字符串
	char* ret =strtok(arr, p);
	printf("%s\n", ret);//zpw
	ret = strtok(NULL, p);
	printf("%s\n", ret);//bitdu
	ret = strtok(NULL, p);
	printf("%s\n", ret);//tech
	return 0;
}

自己实现strtok

 //自己实现strtok 字符串切割打印s
int main()
{
    
    
	char arr[] = "[email protected]";
	char* p = ("@.");
	char buf[1024] = {
    
     0 };
	strcpy(buf, arr);
	//切断buf中的字符串
	char* ret = NULL;
	for (ret = strtok(buf, p); ret != NULL;ret = strtok(NULL,p))
	{
    
    
		printf("%s\n", ret);
	}
	return 0;
}

strerror

errno是一个全局的错误码变量
当c语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值到errno中
strerror
参数 char * strerror(int errnum);
返回错误码 所对应的错误信息
0 No error
1 Operation not permitted
2 No such file or directory

int main()
{
    
    
	//	错误码	错误信息
	char* str = strerror(errno);//1 2 3 ......
	printf("%s\n", str);
	return 0;
}
int main()
{
    
    
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		printf("%s\n", strerror(errno));//打开上面文件如果有就会显示成功,如果没有就会显示错误信息
	}
	else
	{
    
    
		printf("open file success\n");
	}
	return 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				任何可打印字符,包括图形字符和空白字符

下面是具体的使用实例

#include<ctype.h>
int main()
{
    
    
	char ch = '@';
	//int ret = islower(ch); 判断是不是小写字母,如果是返回不为0的数,如果不是返回0
	int ret = isdigit(ch);//判断是不是数字,如果是返回不为0的数,如果不是返回0
	printf("%d\n", ret);
	return 0;
}

字符转换函数 tolower toupper

int tolower(int c);//转小写字母   将所有字母转为小写字母
int toupper(int c);//转大写字母	将所有字母转为大写字母
int main()
{
    
    
	//char ch = tolower('Q');
	//putchar(ch);//结果是Q	
	char ch = toupper('s');
	putchar(ch);//结果是S
	return 0;
}
int main()
{
    
    
	char arr[] = "I AM A Student";
	int i = 0;
	while (arr[i])
	{
    
    
		if (isupper(arr[i]))//如果它是大写
		{
    
    
			arr[i] = tolower(arr[i]);//将大写转化为小写,并返回去
		}
		i++;
	}
	printf("%s\n", arr);//结果是:	i am a student
	return 0;
}

内存操作函数 memcpy memmove memcmp memset

memcpy 内存拷贝

memcpy - 内存拷贝 void* -通用类型的指针 -无类型指针

void * mencpy( void * destination, const void * source, size_t num );

  • destination 目的地
  • source 源头
  • num多少字节

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

下面是memcpy的用法

struct S
{
    
    
	char name[20];
	int age;
};
int main()
{
    
    
	int arr1[] = {
    
     1, 2, 3, 4, 5 };
	int arr2[5] = {
    
     0 };
	//memcpy(arr2 , arr1 , sizeof(arr1));
	//拷贝整型数组,将arr1的内容拷贝到arr2里面去

	struct S arr3[] = {
    
     {
    
    "张三",20}, {
    
    "李四",30} };
	struct S arr4[3] = {
    
     0 };
	memcpy(arr4, arr3, sizeof(arr3));
	return 0;

模拟实现memcpy

void* my_memcpy(void* dest,const void* src, size_t num)//unsigned int 就是size_t
{
    
    
	assert(dest != NULL);
	assert(src  != NULL);
	char* ret = dest;
	while (num--)
	{
    
    
		*(char*)dest = *(char*)src;
		++(char*)dest;
		++(char*)src;
	}
	return ret;
}
struct S
{
    
    
	char name[20];
	int age;
};
int main()
{
    
    
	int arr1[] = {
    
     1, 2, 3, 4, 5 };
	int arr2[5] = {
    
     0 };
	//memcpy(arr2 , arr1 , sizeof(arr1));
	//拷贝整型数组,将arr1的内容拷贝到arr2里面去
	struct S arr3[] = {
    
     {
    
     "张三", 20 }, {
    
     "李四", 30 } };
	struct S arr4[3] = {
    
     0 };
	//my_memcpy(arr4, arr3, sizeof(arr3));
	memcpy(arr2 , arr1 , sizeof(arr1));
	return 0;
}
C语言标准
1:memcpy 只要处理 不重叠的内存拷贝就可以
2:memmove 处理重叠内存的拷贝 

memmove

参数 void * memmove( void * destination, const void * source, size_t num);
1.和memcpy的差别就是memmove函数处理的源内存块和目标n内存块是可以重叠的
2.如果源空间和目标空间出现重叠,就得使用memmove函数处理

memmove进行模拟实现

void* my_memmove(void* dest, const void* src,size_t count)
{
    
    
	void* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	if (dest < src)
	{
    
    
		//前 -》后 从源头前面向目标前面移动
		while (--count)
		{
    
    
			*(char*)dest = *(char*)src;
			++(char*)dest;
			++(char*)src;
		}
	}
	else
	{
    
    
		while (--count)
		{
    
    
			//后->前 从源头后面向目标后面移动
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	return ret;
}
int main()
{
    
    
	int arr[] = {
    
     1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	memmove(arr+4, arr+2, 20);
	return 0;
}

memcmp 内存比较

参数 int memcmp(const void* ptr1, const void* ptr2, size_t num);
返回值 >0 <0 ==

int main()
{
    
    
	int arr1[] = {
    
     1, 2, 3, 4, 5 };
	int arr2[] = {
    
     1, 2, 5, 4, 3 };
	int ret = memcmp(arr1, arr2, 9);
	printf("%d\n", ret);
	return 0;
}

memset - 内存设置

void * memset( void* dest, int c, size_t count); count的单位是字节
dest 目的地要把那一块的空间进行设置
c 就是你要设置的字符是什么
count 你要设置多少个字符

int main()
{
    
    
	char arr[10] = "";
	memset(arr, '#', 10);//将arr里面全部放成##########
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_52495715/article/details/120895732