【C语言进阶】带你轻松玩转字符、字符串函数

本章重点:

        重点介绍处理字符和字符串的库函数的使用和注意事项

目录

前言

一、字符串函数存在的意义

二、函数介绍

2.1 strlen

2.2 strcpy

2.3 strcat

2.4 strcmp

2.5 strncpy

2.6 strncat

2.7 strcmp

2.8 strstr

2.9 strtok

2.10 strerror

2.11 memcpy

2.12 memmove

2.13 memcmp

三、字符函数

3.1字符分类函数

3.2 字符转换函数 

总结


前言

我们在之前C语言初阶的时候,用到了strlen之类的字符串函数我们也知道字符串函数的头文件为<string.h>在这里我们继续向大家介绍其他字符串函数,以及模拟实现这些字符串函数

字符串函数有很多种,我们接下来介绍的是比较常用的几种函数。

一、字符串函数存在的意义

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的。

1.字符串通常放在常量字符串中或者字符数组中。

2.字符串常量 适用于那些对它不做修改的字符串函数

二、函数介绍

2.1 strlen

size_t strlen ( const char * str );          求得字符串长度

函数特性:

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

代码实现:

 模拟strlen函数:


#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strlen1(const char* src) {
	assert(src);//断言
	int count = 0;
	while (*src++) {
		count++;
	}
	return count;
}
//使用递归的方法
int my_strlen2(const char* src) {
	if (*src==0) {
		return 0;
	}
	else {
	/*	src++;*/
		return 1 + my_strlen2(++src);
	}
}
//使用指针-指针   (得到是之间的元素个数)
int my_strlen3(const char* src) {
	char* ret = src;
	while (*src) {
		src++;
	}
	return src - ret;
}
int main()
{
	char arr[] = "abcdef";
	int len = my_strlen3(arr);
	printf("%d\n", len);
	return 0;
}

2.2 strcpy

char* strcpy(char * destination, const char * source );    

拷贝函数,将source内容拷贝到destination上。

函数特性:

1.源字符串必须以 '\0' 结束。   (src有'\0')
2.会将源字符串中的 '\0' 拷贝到目标空间。        ('\0'会拷贝到dest上)
3.目标空间必须足够大,以确保能存放源字符串。        (dest要足够大,大于等于src)
4.目标空间必须可变                (strcpy函数修改的是dest,所以dest能被修改)

代码演示:

模拟strcpy函数:

#include<stdio.h>
#include<string.h>
#include<assert.h>
char *my_strcpy(char* dest, const char* src) {
	assert(dest && src);
	char* ret = dest;
	while (*dest++ = *src++) {
		;
	}
	return ret;
}
int main()
{
	char arr1[10] = "123456789";
	char arr2[] = "abcdef";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

2.3 strcat

char * strcat ( char * destination, const char * source );

覆盖destination上的' \0 '上继续加上source的内容  ,追加字符串函数

函数特性:

1.源字符串必须以 '\0' 结束。    (这是因为strcat之后,dest的'\0'被src第一个元素覆盖)
2.目标空间必须有足够的大,能容纳下源字符串的内容。 (dest大于等于src+dest空间)
3.目标空间必须可修改。        (dest是会被改变的)

函数实现:

 模拟strcat函数:

#include<stdio.h>
#include<string.h>
#include<assert.h>
char*my_strcat(char* dest, const char* src) {
	assert(dest && src);
	//断言
	//我们需要的是找到dest的'\0'位置,在这个后面开始赋值
	char* ret = dest;
	while (*++dest) {  //找'\0'的时候 先++ ,这样避免算进去'\0'
		;
	}
	while (*dest++ = *src++) {
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world!";
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

这边还有一个问题,供大家思考,如果是字符串自己给自己追加,会发生什么?

所以我们得出结论,字符串不能自己追加自己,会死循环 !!!

2.4 strcmp

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

strcmp函数:是对字符串进行比较的函数。

第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字

代码演示:

模拟strcmp函数

#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* dest, const char* src) {
	assert(dest && src);//断言
	while (*dest++ == *src++&&*dest!='\0'&&*src!='\0') {
		//要保证的是,出来之后的dest和src的地址,是起码有一方到'\0'的地址
		//所以  *dest!='\0'&&*src!='\0'  
		//这样就可以停止了,对这样的进行判断
		;
	}
	if (*dest < *src) {
		return -1;
	}
	else if (*dest > *src) {
		return 1;
	}
	else  {
		return 0;
	}
}
int main()
{
	char arr1[]="abcdef";
	char arr2[] = "abc";
	char arr3[] = "abc";
	char arr4[] = "a";
	int num1=my_strcmp(arr1, arr2);
	printf("%d\n", num1);

	int num2 = my_strcmp(arr3, arr2);
	printf("%d\n", num2);
	
	int num3 = my_strcmp(arr4, arr2);
	printf("%d\n", num3);
	return 0;
}

2.5 strncpy

char * strncpy ( char * destination, const char * source, size_t num );

与strcpy函数相比,多个n,表示多个参数num,意味拷贝num个字节的数据

代码演示:

 代码演示:

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src,size_t num) {
	assert(dest && src);
	char* ret = dest;
	int count = 0;
	while (*dest++ = *src++) {
		count++;
		if (count == num) {
			break;
		}
	}
	return ret;
}
int main()
{
	char arr1[10] = "123456789";
	char arr2[] = "abcdef";
	my_strncpy(arr1, arr2,3);
	printf("%s\n", arr1);
	return 0;
}

对于这样的限制字节的字符串函数,模拟实现,只需要在相应的位置上加上num的限制即可

2.6 strncat

char * strncat ( char * destination, const char * source, size_t num );

代码演示:

 模拟实现strncat:

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strncat(char* dest, const char* src,size_t num) {
	assert(dest && src);
	//断言
	//我们需要的是找到dest的'\0'位置,在这个后面开始赋值
	char* ret = dest;
	while (*++dest) {  //找'\0'的时候 先++ ,这样避免算进去'\0'
		;
	}
	int count = 0;
	while (*dest++ = *src++) {
		count++;
		if (count == num) {
			break;
		}
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world!";
	my_strncat(arr1, arr2,3);
	printf("%s\n", arr1);
	return 0;
}

2.7 strcmp

int strncmp ( const char * str1, const char * str2, size_t num );

代码演示:

模拟strncmp:

#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strncmp(const char* dest, const char* src,size_t num) {
	assert(dest && src);//断言
	int count = 0;
	while (*dest == *src && *dest != '\0' && *src != '\0') {
		//要保证的是,出来之后的dest和src的地址,是起码有一方到'\0'的地址
		//所以  *dest!='\0'&&*src!='\0'  
		//这样就可以停止了,对这样的进行判断
		count++;
		if (count == num) {
			break;
		}
		dest++;
		src++;
	}
	if (*dest < *src) {
		return -1;
	}
	else if (*dest > *src) {
		return 1;
	}
	else {
		return 0;
	}
}
int main()
{
	char arr1[]="abcdef";
	char arr2[] = "abc";
	char arr3[] = "abc";
	char arr4[] = "a";
	int num1=my_strncmp(arr1, arr2,1);
	printf("%d\n", num1);

	int num2 = my_strncmp(arr3, arr2,1);
	printf("%d\n", num2);
	
	int num3 = my_strncmp(arr4, arr2,1);
	printf("%d\n", num3);
	return 0;
}

2.8 strstr

char * strstr ( const char *str1, const char * str2);

strstr函数,是在str1主串中,查找是否存在子串str2,如果存在返回在str1主串中的位置(指针)

代码实现:

模拟实现strstr函数:

​

//模拟实现strstr
char *my_strstr(const char* str1, const char* str2) {
	assert(str1 && str2);//断言
	char* s1 = str1;
	char* s2 = str2;
	char* cp = str1;//创建三个指针
	//第一个指针s1表示的是str1,
	//第二个指针s2表示的是str2,只是不断移动s1和s2
	//第三个指针cp 是负责记录每一次循环的初始位置的
	while (*s1) {
		s1 = cp;
		//变化cp
		while (*s1 == *s2&&*s1!='\0'&&*s2!='\0') {
			s1++;
			s2++;
		}
		if (*s2 == '\0') {
			return cp;
		}
		s2 = str2;
		cp++;
	}
	return cp;
}

int main()
{
	char arr1[] = "abcabcdef";
	char arr2[] = "abcd";
	char *p=my_strstr(arr1, arr2);
	printf("%s\n", p);
	return 0;
}

​

2.9 strtok

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

函数特性:

1.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时    拷贝的内容并且可修改。)
2.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在     字符串中的位置。
3,strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一 个标记。
4.如果字符串中不存在更多的标记,则返回 NULL 指针

代码演示:

2.10 strerror

char * strerror ( int errnum );

strerror函数:返回错误码,所对应的错误信息,错误码存储在errno上,且需要头文件<errno.h>

代码演示:

perror()函数和printf......strerror(errno) 是一样的作用,所以可以使用perror()来输出错误信息,fopen()是打开文件的函数,fclose()函数是关闭文件的函数 

2.11 memcpy

内存操作函数

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

函数特征:

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

代码演示:

模拟实现:

//内存管理函数

//void * memcpy ( void * destination, const void * source, size_t num );

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

#include<assert.h>
//模拟实现memcpy内存管理函数
void* my_memcpy(void* dest, const void* src, int num) {
	assert(dest && src);//断言
	void* ret = dest;//返回这个地址
	while (num--) {
		//将src上面num个字节复制给dest对应的 位置
		//字节的话  需要强制类型转换成 char*类型
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

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

2.12 memmove

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

函数特性:

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

代码演示:

 模拟实现memmove函数:

void*my_memmove(void* dest, const void* src, int num) {
	  //使用memmove 主要是 处理重复的时候,如何复制的情况
	//主要是处理好边界问题
	//内存存储的时候,是低地址到高地址
	//当dest > src的时候,可以是后面先传递,之后传递前面的  后->前
	//当src < dest 的时候,发现前到后,后到前都可以,为了方便,我们统一使用前->后
	assert(dest && src);
	//断言
	void* ret = dest;
	if (dest < src) {
		while (num--) {
			//将src上面num个字节复制给dest对应的 位置
			//字节的话  需要强制类型转换成 char*类型
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else {
		while (num--) {//如果num=5
			*((char*)dest + num) = *((char*)src + num);
			//(char*)dest + num  表示在dest起始位置加上num个字节,得到dest之后的四个字节,为dest整体要移动的第五个位置,从0 1 2 3 4  正好五个		}

		}
	}
		return ret;
}
//memmove 函数
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "ccc";
	my_memmove(arr1, arr1+2, 3);
	printf("%s\n", arr1);
	return 0;
}

2.13 memcmp

int memcmp ( const void * ptr1,const void * ptr2,size_t num );

函数特性:

比较从ptr1和ptr2指针开始的num个字节

1.与strncmp函数类似,只是前者是只能用于字符串,后者memcmp可以用于任何类型的实参

2.num直接表示的是字节数,当ptr是整数数组的时候,就需要sizeof(ptr)当作num啦

代码实现:

三、字符函数

字符函数,包括字符分类函数,字符转换函数,头文件为<ctype.h>

3.1字符分类函数

字符分类函数:如果他的参数符合字符函数的要求就返回真,否则返回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任何可打印字符,包括图形字符和空白字符

代码演示(选择其中一个):

3.2 字符转换函数 

int tolower ( int c );        变小写
int toupper ( int c );        变大写

代码演示:

总结

        我们到这个地方就对于字符串函数、字符函数的基本上的函数有了大概的认识和了解,代码演示,以及模拟实现的一些字符串函数,这样希望对于小伙伴们,有所帮助,那么就点点关注,一键三连不迷路,这边预告,下一章节,咱来讲讲,关于结构体的相关知识。

  • 51
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 75
    评论
C语言数字转字符串函数是一种将数值类型的数据转换成字符串类型的数据的函数。在程序中,有时需要将数字类型的数据打印或者存储到文件或数据库中,此时就需要将数字类型的数据转换成字符串类型的数据。可以使用C语言中提供的sprintf、snprintf和itoa等函数实现数字转字符串的功能。 sprintf函数C语言标准库中的一个函数,可以将数字类型的数据按照指定的格式转换成字符串类型的数据。sprintf函数的使用方法与printf函数相似,除了输出的是字符串。例如,可以使用sprintf函数将整数变量i转换成对应的字符串s,如下面的代码: ``` int i = 1234; char s[10]; sprintf(s, "%d", i); ``` 在这个例子中,sprintf函数将整数变量i转换成10进制的字符串,并存储在字符数组s中。 snprintf函数C语言标准库中的另一个函数,与sprintf函数类似,也可以将数字类型的数据按照指定的格式转换成字符串类型的数据。snprintf函数有两个额外的参数,用于指定输出字符串的最大长度和输出格式。使用snprintf函数可以避免字符串缓冲区溢出的问题。 itoa函数是一个可以将整数类型的数据转换成字符串类型的数据的函数。itoa函数的使用方法相对简单,只需要传入一个整数和一个字符指针作为参数,itoa函数会将整数转换成字符串,并将结果存储到字符指针指向的缓冲区中。 总的来说,C语言提供了多种数字转字符串函数,可以根据不同的需求选择适合的函数。但需要注意的是,在使用数字转字符串函数时,要避免字符串缓冲区溢出的问题,以及注意输出格式的正确性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小王学代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值