C语言---字符函数和字符串函数

谢谢观看!希望以下内容帮助到了你,对你起到作用的话,可以一键三连加关注!你们的支持是我更新地动力。
因作者水平有限,有错误还请指出,多多包涵,谢谢!


一、字符分类函数

  C语言中有⼀系列的函数是专门做字符分类的,也就是⼀个字符是属于什么类型的字符的。这些函数的使用都需要包含⼀个头文件是 ctype.h。比如:

  • 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:任何可打印字符,包括图形字符和空白字符

  由于这些函数的用法类似,我们就讲其中的islower

int islower(int c);//可以传递字符,也可以传递ASCII码值,因为字符本质在内存中存放的是acsll码值,
//所以用int c来接收参数。
//通过返回值(类型是int)来说明是否是⼩写字⺟,如果是⼩写字⺟就返回⾮0的整数,如果不是⼩写字⺟,则返回0。
#include<stdio.h>
#include<ctype.h>
int main()
{
	int ret;
	ret = islower('a');
	printf("%d\n", ret);//结果为2。因为islower是判断字符是否为小写字符,是就返回大于0的数

	ret = islower('A');
	printf("%d\n", ret);//结果为0。因为字符A是大写字符,所以返回0
	return 0;
}

  下面我们来做个练习,实际运用一下:写一个代码,将字符串中的小写字母转大写,其他字符不变

  思路:将字符串存放在字符数组中,然后遍历数组的每一个元素,遍历元素时,要判断该元素是否为小写字母,如果是小写字母就将其转化为大写字母,其他字符不变。

int main()
{
	char arr[] = "I am a Student.";

	int i = 0;
	while (arr[i] != '\0')
	{
		if (islower(arr[i]))
		{
			arr[i] -= 32;//小写字母的ASCII码值 - 32 = 大写字母的ASCII码值
		}
		i++;
	}
	printf("%s\n", arr);
	return 0;
}

二、字符转换函数

  C语言中提供了2个字符转换函数:

  • int tolower ( int c ); 将参数传进去的大写字母转小写
  • int toupper ( int c ); 将参数传进去的小写字母转大写

  有了字符转换函数,我们就可以对第一节的练习进行修改了。

int main()
{
	char arr[] = "I am a Student.";

	int i = 0;
	while (arr[i] != '\0')
	{
		if (islower(arr[i]))
		{
			arr[i] = toupper(arr[i]);
		}
		i++;
	}
	printf("%s\n", arr);
	return 0;
}

三、strlen的使用和模拟实现

  strlen函数的形参部分:

size_t strlen ( const char * str );

  strlen函数的基本用法:

int main()
{
	char arr[] = "abcdefghijklmnopqrstuvwxyz";
	printf("%zd\n",arr);//26
	return 0;
}

  使用strlen函数的注意事项

  • 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
  • 参数指向的字符串必须要以 ‘\0’ 结束。
  • 注意函数的返回值为 size_t,是无符号的( 易错 )
  • strlen的使用需要包含头文件
  • 学会strlen函数的模拟实现

  对没有遵循注意事项的进行解析代码:
  部分一:参数指向的字符串没有要以 ‘\0’ 结束。

int main()
{
	char arr[] = {'a','b','c'};
	printf("%zd\n",strlen(arr));//结果为随机值
	//因为strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )
	//因为字符数组中没有\0字符,所以当统计到字符c时,不会停止统计。
	return 0;
}

  部分二:注意函数的返回值为 size_t,是无符号的( 易错 )。

int main()
{
	if(strlen("abc") - strlen("abcdef") > 0)
	{
		printf(">\0");//打印结果为>
	}
	else
	{
		printf("<\0");
	}
	return 0;
}

  这时就疑惑非常大了,strlen("abc")计算结果为3strlen("abcdef")计算结果为63-6=-3是负数,怎么可能是>0呢?

  其实这就和函数的返回类型有关了,因为函数的返回值为 size_t,是无符号整型,可能是短整型,也可能是长整型,反正一定是无符号,即把符号位当作数值位。那么虽然3-6=-3看起来是负数,但size_t - size_t的类型还是size_t,写成-3的原码、反码、补码。补码就是数据在内存中的存放形式,由于类型是size_t,没有符号位,即就是将补码写成真值,是一个非常大的数字。

  那么上面的代码就达不到我们想要比较一下两个字符串的长度,这就需要强制类型转化成int整型。

int main()
{
	if((int)strlen("abc") - (int)strlen("abcdef") > 0)
	{
		printf(">\0");
	}
	else
	{
		printf("<=\0");//打印结果为<
	}
	return 0;
}

  但其实最简单的是,不要将它们作差去比较大小,直接放二边比较就可以了

int main()
{
	if(strlen("abc") > strlen("abcdef"))
	{
		printf(">\0");
	}
	else
	{
		printf("<=\0");//打印结果为<
	}
	return 0;
}

  在上面我们对strlen函数的用法进行了解释,但对于学习strlen函数,重要的是模拟实现strlen函数。

  方法一:计数器的方式

//计数器⽅式
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
	int count = 0;
	assert(str != NULL);//判断指针str是否为NULL(空指针),是空指针就不可以直接使用str,不为空,才可以解引用操作等
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}

int main()
{
	char arr[] = "abcdef";
	printf("%zd\n",my_strlen(arr));//结果为6
	return 0;
}

  方法二:指针 - 指针

size_t my_strlen(const char * str)
{
	char * start = str;
	assert(str != NULL);//在对指针解引用操作之前,断言一下指针不为NULL
	while(*str != '\0')
	{
		str++;
	}
	return str - start
}

int main()
{
	char arr[] = "abcdef";
	printf("%zd\n",my_strlen(arr));//结果为6
	return 0;
}

  方法三:递归的方式(不能创建临时变量),递归的思想是大事化小,递归下去,在回归。

#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
	assert(str != NULL);
	if(*str != '\0')
		return 1+my_strlen(str+1);
	else
		return 0;
}

int main()
{
	char arr[] = "abcdef";
	printf("%zd\n",my_strlen(arr));//结果为6
	return 0;
}

四、strcpy函数的使用和模拟实现

  strcpy函数的参数部分:

char* strcpy(char * destination, const char * source );//destination目的地,source源头,将源头的数据,复制到目的地的,包涵结束的\0字符也会被拷贝过去。

  strcpy函数的基本用法:

int main()
{
	char arr1[] = "hello world";
	char arr2[20] = {0};
	strcpy(arr2,arr1);
	printf("%s",arr2);//结果为:hello world
	return 0;
}

  使用strcpy函数的注意事项

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。
  • 学会模拟实现。

  对没有遵循注意事项的进行解析代码:
  部分一:目标空间没有足够的大

int main()
{
	char arr1[] = "hello world";
	char arr2[] = { 0 };//其实你想将元素全部存放成0,但是由于没有给数组arr2元素个数,所以arr2只有一个元素,元素为0,应该改为char arr2[20] = {0};
	strcpy(arr2, arr1);
	printf("%s", arr2);//会报错
	return 0;
}

  部分二:源字符串没有以 ‘\0’ 结束

char arr1[] = {'a','b','c','d'};
char arr2[20] = {0};
strcpy(arr2,arr1);//想一想如果要将arr1的内存复制到arr2中,那么也就需要知道数组arr1中有多少个元素,如果没有\0,那么元素就随机了,会复制arr1中没有的元素到arr2中
printf("%s",arr2);

  部分三:目标空间是不可以修改的

char arr1[] = "hello world";
char * p = "xxxxxxxxxxxxxxxxxxxxx";//常量字符串是不能被修改的
strcpy(p,arr1);//报错
printf("%s\n",p);

  在上面我们对strcpy函数的用法进行了解释,但对于学习strcpy函数,重要的是模拟实现strcpy函数。

//返回值类型是char*,是为了实现链式访问
//strcpy函数返回的是目标空间的起始位置
char* my_strcpy(char* dest,const char* src)
{
	char* dest_start = dest;
	assert(dest && src);
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;//这里处理的是将\0复制给dest
	return dest_start;//返回目标空间的起始地址
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	char* pstr = my_strcpy(arr2, arr1);
//三种打印形式是一样的意思
	printf("%s\n",arr2);
	printf("%s\n",pstr);
	printf("%s\n",my_strcpy(arr2, arr1));
	return 0;
}

  我们可不可以将\0a,b,c,d,e,f放在一起复制给dest,而不是分开的,看下面的代码:

//返回值类型是char*,是为了实现链式访问
//strcpy函数返回的是目标空间的起始位置
char* my_strcpy(char* dest,const char* src)
{
	char* dest_start = dest;
	assert(dest && src);
	while (*dest ++= *src++)//拷贝过去字符后,判断表达式的值,当\0拷贝过去后,判断为假,停止循环
	                        //虽然++的优先级高于*,但是这里的++是后置++,加1的效果是延后产生的
	{
		;
	}
	*dest = *src;//这里处理的是将\0复制给dest
	return dest_start;//返回目标空间的起始地址
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	char* pstr = my_strcpy(arr2, arr1);
//三种打印形式是一样的意思
	printf("%s\n",arr2);
	printf("%s\n",pstr);
	printf("%s\n",my_strcpy(arr2, arr1));
	return 0;
}

五、strcat函数的使用和模拟实现

  strcat函数的参数部分:

char* strcat(char * destination, const char * source );//将source的数据,追加到destination的数据末尾

  strcpy函数的基本用法:

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	strcat(arr1,arr2);//字符串追加
	printf("%s",arr1);//结果为:hello world
	return 0;
}

  使用strcat函数的注意事项

  • 源字符串必须以 ‘\0’ 结束。
  • 目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • 字符串自己给自己追加,如何?(不能,会破坏\0,不满足原字符串和目的字符串都要要\0)

  对没有遵循注意事项的进行解析代码:
  部分一:目标空间没有足够的大,不能容纳下源字符串的内容

int main()
{
	char arr1[7] = "hello ";//目标空间就7个字节大小,都已经放入了数据,此时追加world,是不能的,程序会报错
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

  其他错误的部分和上面函数的分析是一样的

  在上面我们对strcat函数的用法进行了解释,但对于学习strcat函数,重要的是模拟实现strcat函数。

char* my_strcat(char* dest,const char* src)
{
	assert(dest && src);
	char* dest_start = dest;
	//1. 找目标空间的\0
	while (*dest != '\0')
		dest++;
	//2. 拷贝(和函数strcpy的一样)
	while (*dest++ = *src++)
		;//表示空语句

	return  dest_start ;
}

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";

	my_strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

  补充知识

  • 0 — 数字0
  • ‘0’ — 数字字符0 — 本质是字符 —ASCII值是48
  • ‘\0’ — 字符\0 — \ddd(ddd表示1~3个8进制数字)---- \0的ASCII值是0
  • NULL ---- 也是0,是赋值给指针变量的

六、strcmp函数的使用和模拟实现

  strcat函数的参数部分:

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

  strcpy函数的基本用法

int main()
{
	char arr1[] = "abp";
	char arr2[] = "abcdef";
	printf("%d\n", strcmp(arr1, arr2));//结果为: 1,因为比较的不是字符串的长度,而是字符串对应的ASCII值
	
	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	printf("%d\n", strcmp(arr1, arr2));//结果为0
	
	char arr1[] = "abcdef";
	char arr2[] = "abp";
	printf("%d\n", strcmp(arr1, arr2));//结果为-1

	return 0;
}

  使用strcmp函数的标准规定

  • 第一个字符串大于第二个字符串,则返回⼤于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字
  • 那么如何判断两个字符串? 比较两个字符串中对应位置上字符ASCII码值的大小

  在上面我们对strcmp函数的用法进行了解释,但对于学习strcmp函数,重要的是模拟实现strcmp函数。

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)//思路是把两个字符串相同的字符就不管,一直到比较到字符不相同就可以比较出字符串的大小
	{
		if (*str1 == '\0')
		{
			return 0;
		}
		str1++;
		str2++;
	}
	//写法1
	if (*str1 > *str2) 
		return 1;
	else
		return -1;

	//写法二
	//return (*str1 - *str2);
}
int main()
{
	char arr1[] = "abq";
	char arr2[] = "abcdef";
	printf("%d\n", my_strcmp(arr1, arr2));
	return 0;
}

  在上面的介绍中,我们新学习了strcpystrcatstrcmp三个字符串函数,它们是属于长度不受限制的字符串函数,因为在使用它们的时候是需要传递两个字符串的首元素地址,它们就会对整个字符串进行操作。

  那么让我们再来学习一下,长度不受限制的字符串函数,strncpystrncatstrncmp3个字符串函数,与原来的比,不同在于多了一个nn就表示在对字符串进行追加、复制、比较时,可以指定追加的字符数n,复制的个数n,和比较n个字符。因为这样可以灵活的符合需求。


七、 strncpy 函数的使用

  strncpy函数的参数部分:

//strncpy函数
char* strcpy(char * destination, const char * source ,size_t num);//num表示最大从source拷贝到destination的个数
//strcpy函数
char* strcpy(char * destination, const char * source );

  strncpy函数的基本用法:

int main()
{
	char arr1[]   = "abcdef";
	char arr2[20] = "xxxxxxxx";
	strcpy(arr2,arr1,3);
	printf("%s\n",arr2);//结果为abcxxxxx
	return 0;
}

  使用strncpy函数的标准规定

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

  注意事项:需要从source中复制大于source空间的个数,不够的会补\0字符

int main()
{
	char arr1[]   = "abcdef";
	char arr2[20] = "xxxxxxxxx";
	strcpy(arr2,arr1,8);//由于arr1的字符个数为7个,abcdef\0,由于小于8,所以补一个\0,即拷贝内容为abcdef\0\0
	printf("%s\n",arr2);//
	return 0;
}

八、 strncat 函数的使用

  strncat函数的参数部分:

//strncat函数
char* strncat(char * destination, const char * source ,size_t num);
//strcat函数
char* strcat(char * destination, const char * source ;

  strncat函数的基本用法:

int main()
{
	char arr1[20] = "abcdef";
	char arr2[20] = "xxxxxxxxx";
	strncat(arr1,arr2,3);//字符串从\0字符开始追加3个字符,然后补一个\0到末尾
	printf("%s",arr1);//结果为:abcdefxxx
	return 0;
}

  使用strncat函数的标准规定

  • 将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加一个 \0 字符
  • 如果source指向的字符串的长度小于num的时候,只会将字符串中到\0 的内容追加到destination指向的字符串末尾

九、strncmp 函数的使用

  strncmp函数的参数部分

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

  strncmp函数的基本用法:

int main()
{
	char arr1[20] = "abcdef";
	char arr2[20] = "abcq";
	int ret = strncmp(arr1,arr2,3);//字符串从\0字符开始追加3个字符,然后补一个\0到末尾
	printf("%d\n",ret);
	return 0;
}

  比较str1和str2的前num个字符,如果相等就继续往后比较,最多比较num个字母,如果提前发现不一样,就提前结束,大的字符所在的字符串大于另外一个。如果num个字符都相等,就是相等返回0.


十、strtok 函数的使用

  strtok函数的参数部分

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

  strtok函数的基本用法:

int main()
{
	char arr[] = "zpengwei@yeah.net";
	char buf[256] = { 0 };//因为函数strtok会改变字符串原本的内容,所以弄一个临时拷贝后,再用strtok函数进行分割
	strcpy(buf, arr);//zpengwei\0yeah\0net
	char* sep = "@.";


	char* ret = strtok(buf, sep);//只需要执行一次,含有buf的strtok
	printf("%s\n", ret);//zpengwei

	ret = strtok(NULL, sep);//如果第一个参数是NULL,那么会从上面记住的位置(被改为了\0)开始向后分割
	printf("%s\n", ret);//yeah

	ret = strtok(NULL, sep);//如果第一个参数是NULL,那么会从上面记住的位置(被改为了\0)开始向后分割
	printf("%s\n", ret);//net

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

  上面讲的是strtok函数的基本用法是怎么回事的,但一般不是这么用。

int main()
{
	char arr[] = "zpengwei@yeah.net";
	char buf[256] = { 0 };//因为函数strtok会改变字符串原本的内容,所以弄一个临时拷贝后,再用strtok函数进行分割
	strcpy(buf, arr);//zpengwei\0yeah\0net
	char* sep = "@.";
	char* ret = NULL;
	for(ret = strtok(buf,sep);ret != NULL; ret = strtok(NULL,sep))//初始化部分只会执行一次strtok(buf,sep)
	{
		printf("%s\n",ret);
	}
	return 0;
}

  通过上面的了解,我们可能会对strtok函数的用法感到有点奇怪,因为第一次只需要传入指向需要分割的字符串的首元素的地址即可,后面就只需要传入NULL空指针就可以将字符串分割开,想一想,它应该是有记忆功能,不然当变量出了函数就会被销毁,所以应该有static修饰的变量(处在静态区,出函数也不会被销毁)。


十一、strstr函数的使用和模拟实现

  strstr函数的参数部分

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

  strstr函数的功能:在str1中找str2这个字符串,第一次出现的位置。如果找到了,就返回这个第一次出现的起始地址;如果找不到,就返回NULL

  strstr函数的基本用法:

int main()
{
	char arr[] = "abcdefabcdef";
	char* p = "efab";
	char * ret = strstr(arr,p);
	if(ret == NULL)
	{
	printf("不存在\n");
	}
	else
	{
	printf("存在\n");
	printf("%s",ret);//efabcdef
	//这个函数返回的是第一次找到的字符串,然后从找到的字符串的起始地址,那么打印字符串用%s的话,就是从传入的地址开始,到\0字符前。
	}
	return 0 ;
}

  在上面我们对strstr函数的用法进行了解释,但对于学习strstr函数,重要的是模拟实现strstr函数。

const char* my_strstr(const char * str1,const char* str2)
{
	assert(str1 && str2);
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cur = str1;

	//特殊情况:str2指向的是空字符串"",直接返回str1
	if(*str2 == '\0')
		return str1;
	
	while(*cur != '\0')
	{
		s1 = cur;
		s2 = str2;
		while(*s1 != '\0' && *s2 != '\0' && *s1 == *s2)//也可以写成(*s1  && *s2  && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if(*s2 == '\0')
			return cur;
		cur++;
	}
	return NULL;
}


int main()
{
	char arr[] = "abcdefabcdef";
	char* p = "efab";
	const char * ret = my_strstr(arr,p);
	if(ret == NULL)
	{
	printf("不存在\n");
	}
	else
	{
	printf("存在\n");
	printf("%s",ret);//efabcdef
	//这个函数返回的是第一次找到的字符串,然后从找到的字符串的起始地址,那么打印字符串用%s的话,就是从传入的地址开始,到\0字符前。
	}
	return 0 ;
}

十二、strerror函数的使用

  strerror函数的参数部分

char* strerror ( int errnum );//strerror 函数可以把参数部分错误码(数字)对应的错误信息的字符串地址返回来。
//一个错误码对应一个错误信息,这个信息是字符串。

  补充知识:在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用一个全局的变量errno来记录程序的当前错误码,只不过程序启动的时候errno0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在errno中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回

  strerror函数的基本用法:

int main()
{
	int i = 0;
	for (i = 0;i <= 10;i++)
	{
		printf("%d: %s\n"strerror(i));
	}
	return 0;
}

在这里插入图片描述

int main ()
{
 FILE * pFile;
 pFile = fopen ("unexist.ent","r");
 if (pFile == NULL)
 printf ("文件打不开的原因是: %s\n", strerror(errno));
 //文件打不开的原因是: No such file or directory
 return 0;
}

  上面讲了strerror函数,那么让我们再来了解一下和strerror函数类似的函数perror

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");//"r" - 表示只读,以读文件的形式,来打开文件,
	//如果文件不存在,就打开失败,然后返回空指针
	if (pf == NULL)
	{
		printf("打开文件失败的原因是:%s\n", strerror(errno));
		perror("打开文件失败的原因是");
		//perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。
	}
	return 0;
}

在这里插入图片描述
  

  通过上面的代码图片可以看到,perror函数打印完参数部分的字符串后,再打印一个冒号和一个空格,再打印错误信息。


  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值