c语言语法的学习——字符串

本文详细介绍了C语言中的字符串处理方法,包括字符串的存储形式、指针与数组表示的区别、常用字符串函数如gets()、fgets()、puts()等的功能及用法注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c语言语法的学习——字符串

精华提取

1.用双括号括起来的内容被视为指向该字符串存储位置的指针。并且字符串常量属于静态存储类别,这说明在函数中使用字符串常量,该字符串只会存储一次,在整个程序的生命周期依然存在。

字符串在数组的存储方式:

在这里插入图片描述

2.字符串的表示有两种方法,1.指针表示方法 2.数组表示方法

#define MAG "我宣布一个事"
#define num 81
#include <stdio.h>
int main(void)
{
	char ch[num] = "我是一个傻逼";//这是数组表示方法
	 const char * p = "没毛病,兄弟们";//这是指针表示方法
	 //char *p= "没毛病,兄弟们";是错误的,不知道为什么?——闪光点解决了。
	 puts("虎哥发言");
	 puts(ch);
	 puts(p);
	 ch[1] = 'i';
	 puts(ch);
	return 0;
}

两者的选择:

数组表示是:字符串由于是静态存储类别,所以存储到静态存储区里面,当程序开始执行的时候,为数组开辟一个内存空间,用数组 名表示那个内存空间的地址,此时程序中字符串有两个副本,一个是在静态存储区里面的原来的字符串,一个是在数组里面的副本。

——将静态存储区的字符串拷贝给数组中

数组表示法——由于数组名是一个地址常量,所以不能进行递增运算,但是可以进行字符串值得改变。

指针表示是:由于只是将地址拷贝给指针,所以不能改变指针指向的值——字符串,但是可以改变指针本身。

——只是把字符串的地址拷贝给指针,与在静态存储区中字符串的地址相同。

3.

int (*p)[2]//他的意思就是设置一个指针指向内含2个int类型的数组
int * p[2]//由于[]优先级高,所以意思是p是一个内含2个指针元素的数组,其中每一个元素都是指向int的指针

这两者的区别以及联系

int (*p)[2]——它的应用主要是为了平替二维数组名,

#include <stdio.h>
//10.16就是二维数组的初始化 
//闪光点:没有闪光点 
int main(void)
{
	int a[3][2]={{2,3},{2,5},{2,6}};
	int (*pz)[2];//pz指向一个内含两个int类型值的数组
	//这里pz2的取值关键就是,一会代码敲出来就知道了。 
	pz=a; 
	printf("pz是%p, pz+1是%p\n",pz,pz+1);
	printf("pz[0]是%p,pz[0]+1是%p\n",pz[0],pz[0]+1);//pz[0]
	printf("*pz对应的值是%p,*pz对应的值加1是%p\n",*pz,*pz+1);//*pz
	printf("pz[0][0]是%p,pz[0][0]+1是%p\n",pz[0][0],pz[0][0]+1);//pz[0][0]
	printf("*pz[0]是%p,*pz[0]+1是%p\n",*pz[0],*pz[0]+1);//*pz[0]
	printf("**pz是%d,**pz+1是%d\n",**pz,**pz+1);//**pz
	//pz[2][1]
	
	
	
	return 0;
}

int * p[2]——它的主要作用就是为了表示字符串的初始化,因为每一个被引号包括的都是指向引号内容的指针。由于这一个特性,才可以用于表示二维字符串。

#define  LINES 5
#define ROWS 60
#include <stdio.h>
int main(void)
{
	const char* mytalent[LINES]=//注意这和之前指向二维数组的指针不一样.不能用到数字上面
	{
		"Adding numbers swiftly",
		"Multiplying accurately",
		"Stashing data",
		"Following instructions to the letter",
		"Understanding the C language"


	};
	char yourtalent[LINES][ROWS] =
	{
		"Walking in a straight line",
		"Sleeping", 
		"Watching television",
		"Mailing letters", 
		"Reading email"

	};
	int i;
	printf("%-36s %-25s\n", "mytalent","yourtalent");
	for (i = 0; i < LINES; i++)
	{
		printf("%-36s,%-25s\n", mytalent[i], yourtalent[i]);

	}
 
	return 0;
}

字符串函数

1.gets()函数

gets()函数,读取整行输入,直至遇到换行符,然后丢弃换行符,存储其余字符,并在这些字符的末尾添加一个空字符使其变成一个c字符串。很无脑,但是有缺陷。就是容易报错,并且新的标准 不允许使用这个函数,所以就不说明gets()函数的用法

2.fgets()函数
char *fgets(char *s, int size, FILE *);//函数原型,输入:第一个输入的是字符串对应的地址(也可以说成为指针),第二个输入就是获得字符的最大数量,size。fgets()函数将读入size-1个字符,或者读到第一个换行符。第三个输入是基本写代码就是stdin.
//输出1.输出就是返回指向char的指针,如果一切顺利,将返回输入的第一个参数。如果遇到文件的结尾,那就那就输出空指针。

用法注意:

1.如果fgets()函数读到一个换行符,会把它存储到字符串中。

[^1.通过fgets()函数输入apple pie,apple pie\n\0被存储在数组中。2.通过fgets()函数输入straweety shortcake,strawberry shortcake,超过了大小的限制,所以fgets()只读入了13个字符,数组中存储内容为strawberry sh\0]:

参考代码:

#include <stdio.h>
#define size 5

int main(void)
{
	char h[size];
	char* p;
	puts("请输入一串字符放到数组里面");
	p=fgets(h,size,stdin);
	printf("%p\n", p);
	puts(h);


	return 0;
}
3.puts()函数
 int puts(const char *str) //输入:字符串或者是指针,亦或是代表字符串的地址
     //当puts
     //输出:

用法注意:

puts()会显示字符串的时候会自动在末尾添加一个换行符。当遇到空字符的时候就停止输出。

参考代码:

#define MDN "l am a foolish man"
#define num 100
#include <stdio.h>
int main(void)
{
	char ch[100] = "hata you";
	const char* p = "l love you zhang";
	puts(ch);
	puts(MDN);
	puts(p);
	//puts(ch[2]);//为什么这样就不会运行
	puts(&ch[2]);//这样就运行了.所以这个就判断puts()输入的参数
	puts(p + 2);
	return 0;
}
4.fputs()函数

函数原型

Int fputs (const char *str, FILE *stream)
    //输入多加了stdout
    //输出和puts()函数基本一致,就是参考上面puts()函数。

用法注意:

没什么注意的,和puts()函数功能一致,但是fputs函数不会在输出的末尾添加换行符。其他没什么注意的。

参考代码:

#include <stdio.h>
#define lines 10

int main(void)
{
	char ch[lines];
	puts("请输入一串字符串,直到你输入空行结束");

	while ((fgets(ch, lines, stdin) != NULL) && ch[0] != '\n')
	{
		fputs(ch, stdout);
	}
	puts("done");

	return 0;
}
5.putchar以及getchar函数

函数原型

int getchar(void)//getchar()的函数原型

int putchar(int char)//putchar()的函数原型

用法注意:

1.getchar函数只能接受单个字符,输入数字也按字符处理。输入多于一个字符时,只接收第一个字符。getchar()可以接受单个字符,包括空格,制表符,以及换行符。

getchar函数的返回值是用户输入的第一个字符的ASCII码, 如出错返回 - 1, 且将用户输入的字符回显到屏幕.

[^getchar有一个int型的返回值.当程序调用getchar时.程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中).当用户键入回车之后, getchar才开始从stdin流中每次读入一个字符.getchar函数的返回值是用户输入的第一个字符的ASCII码, 如出错返回 - 1, 且将用户输入的字符回显到屏幕.如用户在按回车之前输入了不止一个字符, 其他字符会保留在键盘缓存区中, 等待后续getchar调用读取.也就是说, 后续的getchar调用不会等待用户按键, 而直接读取缓冲区中的字符, 直到缓冲区中的字符读完为后, 才等待用户按键.]:

6.strlen()函数

函数原型

unsigned int strlen(const char *str);//
//输入:代表字符串的指针或者是字符串对应的地址
//输出字符串的长度。
//size_t strlen(const char* s);
//该函数返回s字符串中的字符数,不包括末尾的空字符

用法注意:

没有------记得区分sizeof()函数

参考代码:

#include <stdio.h>
#include <string.h>
void fit_char(char* ch, int size);
#define MG 80
int main(void)
{
	char ch[MG] = "i am a iron man,but l like you zhang";
	puts(ch);
	fit_char(ch, 5);
	puts(ch);
	puts(ch + 2);
	puts(ch);



	return 0;
}
void fit_char(char* ch, int size)//得到一串字符串,如果超出范围,就把他舍弃掉
{
	while (strlen(ch) > size)
		ch[size] = '\0';

}
7.strncat()来代替strcat()函数

函数原型

char* strcat(char* restrict s1, const char* restrict s2);
该函数把s2指向的字符串拷贝至s1指向的字符串末尾。s2字符串的第1个字符将覆盖s1字符串末尾的空字符。该函数返回s1。
char* strncat(char* restrict s1, const char* restrict s2, size_t n);
该函数把s2字符串中的n个字符拷贝至s1字符串末尾。s2字符串的第1个字符将覆盖s1字符串末尾的空字符。不会拷贝s2字符串中空字符和其后的字符,并在拷贝字符的末尾添加一个空字符。该函数返回s1。
    
8.strncmp()来代替strcmp()函数

函数原型:

int strcmp(const char* s1, const char* s2);
如果s1字符串在机器排序序列中位于s2字符串的后面,该函数返回一个正数;如果两个字符串相等,则返回0;如果s1字符串在机器排序序列中位于s2字符串的前面,则返回一个负数。
int strncmp(const char* s1, const char* s2, size_t n);
该函数的作用和strcmp()类似,不同的是,该函数在比较n个字符后或遇到第1个空字符时停止比较。

参考代码

#include <stdio.h>
#include <string.h>
#define SIZE 6
#define key "astro"
char* get_s(char* s, int size);
int main(void)
{
	const char* p[SIZE] = {

		"astronomy", "astounding",
		  "astrophysics", "ostracize",
		  "asterism", "astrophobia"
	};
	int astronum = 0;
	int i;
	//while (strncmp(p[i], "astro", 5)==0)//如果终止判断条件让我堵塞住了
	//{
	//	astronum++;
	//}
	//if(strncmp(p[i],"astro",5))
	//以上的解决方法竟然是for 循环
	for (i = 0; i < SIZE; i++)
	{
		if (strncmp(p[i], key, 5) == 0)
		{
			printf("Found: %s\n", p[i]);
			astronum++;

		}

	}
	printf("和astro重叠的单词有%d个", astronum);

	return 0;
}
char* get_s(char* s, int size)
{
	char* p;
	int i = 0;
	p = fgets(s, size, stdin);
	if (p)
	{

		while (p[i] != '\n' && p[i] != '\0')
			i++;
		if (p[i] == '\n')
			p[i] = '\0';
		else
			while (getchar() != '\n')
				continue;
		return p;
	}
}
9.strncpy()代替strcpy()函数

函数原型:

char* strcpy(char* restrict s1, const char* restrict s2);
该函数把s2指向的字符串(包括空字符)拷贝至s1指向的位置,返回值是s1。
char* strncpy(char* restrict s1, const char* restrict s2, size_t n);
该函数把s2指向的字符串拷贝至s1指向的位置,拷贝的字符数不超过n,其返回值是s1。该函数不会拷贝空字符后面的字符,如果源字符串的字符少于n个,目标字符串就以拷贝的空字符结尾;如果源字符串有n个或超过n个字符,就不拷贝空字符。xxxxxxxxxx char* strcpy(char* restrict s1, const char* restrict s2);该函数把s2指向的字符串(包括空字符)拷贝至s1指向的位置,返回值是s1。char* strncpy(char* restrict s1, const char* restrict s2, size_t n);该函数把s2指向的字符串拷贝至s1指向的位置,拷贝的字符数不超过n,其返回值是s1。该函数不会拷贝空字符后面的字符,如果源字符串的字符少于n个,目标字符串就以拷贝的空字符结尾;如果源字符串有n个或超过n个字符,就不拷贝空字符。数返回s1。

问题注意

strncpy(target, source, n)把source中的n个字符或空字符之前的字符(先满足哪个条件就拷贝到何处)拷贝至target中。因此,如果source中的字符数小于n,则拷贝整个字符串,包括空字符。但是,strncpy()拷贝字符串的长度不会超过n,如果拷贝到第n个字符时还未拷贝完整个源字符串,就不会拷贝空字符。所以,拷贝的副本中不一定有空字符。

鉴于此,该程序把n设置为比目标数组大小少1(TARGSIZE-1),然后把数组最后一个元素设置为空字符:
 strncpy(qwords[i], temp, TARGSIZE - 1);
qwords[i][TARGSIZE - 1] = '\0';


参考代码:


8.sprintf()函数

// sprintf()函数声明在stdio.h中,而不是在string.h中。该函数和printf()类似,但是它是把数据写入字符串,而不是打印在显示器上。因此,该函数可以把多个元素组合成一个字符串。sprintf()的第1个参数是目标字符串的地址。其余参数和printf()相同,即格式字符串和待写入项的列表。
// 
// 
// 
//闪光点:sprintf()函数,和printf()函数的用法一样,先格局自己设置的格式获取输入,然后把他们组合成一个字符串,最后输出到前一个变量。然后注意的是,sprintf的第一个参数应为目标字符串的地址。
// 
//sprintf(formal, "%s,%-19s:&%6.2f\n", last, first, prize);这个sprintf()函数的意思就是将last按照%s的格式,first按照-19s的格式,prize按照%6.2f的格式输入到formal中,

#include <stdio.h>
#include <string.h>
#define MAX 20

char* get_s(char* ch, int size);


int main(void)
{
	char first[MAX];
	char last[MAX];
	char formal[2 * MAX + 10];
	double prize;
	puts("enter your first name");
	get_s(first, MAX);
	puts("enter your last name");
	get_s(last, MAX);
	puts("enter your first name");
	scanf("%lf",& prize);
	sprintf(formal, "%s,%-19s:&%6.2f\n", last, first, prize);
	puts(formal);
	return 0;
}
char* get_s(char* ch, int size)
{

	char* retu;
	int i = 0;
	retu = fgets(ch, size, stdin);
	if (retu)
	{
		while (ch[i] != '\n' && ch[i] != '\0')
			i++;
		if (ch[i] == '\n')
			ch[i] = '\0';
		else
			while (getchar() != '\n')
				continue;
	}

	return retu;
}

8.其他库函数的函数原型

char* strcpy(char* restrict s1, const char* restrict s2);
该函数把s2指向的字符串(包括空字符)拷贝至s1指向的位置,返回值是s1。
char* strncpy(char* restrict s1, const char* restrict s2, size_t n);
该函数把s2指向的字符串拷贝至s1指向的位置,拷贝的字符数不超过n,其返回值是s1。该函数不会拷贝空字符后面的字符,如果源字符串的字符少于n个,目标字符串就以拷贝的空字符结尾;如果源字符串有n个或超过n个字符,就不拷贝空字符。
char* strcat(char* restrict s1, const char* restrict s2);
该函数把s2指向的字符串拷贝至s1指向的字符串末尾。s2字符串的第1个字符将覆盖s1字符串末尾的空字符。该函数返回s1。
char* strncat(char* restrict s1, const char* restrict s2, size_t n);
该函数把s2字符串中的n个字符拷贝至s1字符串末尾。s2字符串的第1个字符将覆盖s1字符串末尾的空字符。不会拷贝s2字符串中空字符和其后的字符,并在拷贝字符的末尾添加一个空字符。该函数返回s1。
int strcmp(const char* s1, const char* s2);
如果s1字符串在机器排序序列中位于s2字符串的后面,该函数返回一个正数;如果两个字符串相等,则返回0;如果s1字符串在机器排序序列中位于s2字符串的前面,则返回一个负数。
int strncmp(const char* s1, const char* s2, size_t n);
该函数的作用和strcmp()类似,不同的是,该函数在比较n个字符后或遇到第1个空字符时停止比较。
char* strchr(const char* s, int c);
如果s字符串中包含c字符,该函数返回指向s字符串首次出现的c字符的指针(末尾的空字符也是字符串的一部分,所以在查找范围内);如果在字符串s中未找到c字符,该函数则返回空指针。
char* strpbrk(const char* s1, const char* s2);
如果s1字符中包含s2字符串中的任意字符,该函数返回指向s1字符串首位置的指针;如果在s1字符串中未找到任何s2字符串中的字符,则返回空字符。
char* strrchr(const char* s, char c);
该函数返回s字符串中c字符的最后一次出现的位置(末尾的空字符也是字符串的一部分,所以在查找范围内)。如果未找到c字符,则返回空指针。
char* strstr(const char* s1, const char* s2);
该函数返回指向s1字符串中s2字符串出现的首位置。如果在s1中没有找到s2,则返回空指针。
size_t strlen(const char* s);
该函数返回s字符串中的字符数,不包括末尾的空字符
典型例题:
11.9该程序读取输入行,删除存储在字符串中的换行符,如果没有换行符,那么删除剩下的所有行,然后原样输出
闪光点:太多闪光点了,但是不知道怎么总结,见285页的有意思的那一行。
// 感觉挺厉害的
// 1.字符串结束的标志是'\0'.enter输出的是换行符号。fgets()函数却是保留换行符。
// 假设是一个数组要存储ch;fgets(ch,MAX,stdin), 并且此时从键盘输入的是dsfas.但是经过fgets()函数存到数组里面是dsfas\n\0.

#include <stdio.h>
#define MAX 10
int main(void)
{
	int i;
	char ch[MAX];
	puts("请输入一串字符串");
	while (fgets(ch, MAX, stdin) != NULL && ch[0] != '\n')//fgets()会保留'\n '\0
	{
		i = 0;
		while (ch[i] != '\n' && ch[i] != '\0')
			//判断
			i++;//就这个就很优秀。
		if (ch[i] == '\n')
			ch[i] = '\0';
		else
			while (getchar() != '\n')
				continue;
		puts(ch);
		//fputs(ch, stdout);//这个函数不会换行
	}

	puts("结束了 ");
	return 0;
}
	/*fgets(ch, MAX, stdin);*/
	//for (i = 0; i < MAX; i++)
	//{
	//	if (ch[i] == '\n')
	//		ch[i] = '\0';
	//	if (ch[MAX - 1] != '\n')//如果没有换行付,那就删除剩下的所有元素
	//		continue;
	//}

2.字符串标准输入,模板

这一节引用最多的get_s()函数,所以写在这里以便于复制
char* get_s(char* ch, int size)
{

	char* retu;
	int i = 0;
	retu = fgets(ch, size, stdin);
	if (retu)
	{
		while (ch[i] != '\n' && ch[i] != '\0')
			i++;
		if (ch[i] == '\n')
			ch[i] = '\0';
		else
			while (getchar() != '\n')
				continue;
	}

	return retu;
}

3.典型例题

//11.29.c
//问题描述:按照字母表顺序进行排序字符串的实际问题
//一般做法:读取字符串函数,排序字符串,打印出来
// 具体问题:输入二维数组,用指针来表示出来,然后进行排序,最后输出
// 
//闪光点:
//1.解决这个问题:
//while (chi < row && get_s(input[chi], line) != NULL && input[chi][0] != '\0')//卧槽尼玛,竟然是&&运算的,如果前一个运算表达式为假,后面就不用考虑。
//	//但是为什么while (chi < row  &&input[chi][0] != '\0'&& get_s(input[chi], line) != NULL )这样的话,必须要执行20次,很奇怪
//2.理解到了strcmp函数的两个参数的意义。不只是字符串,关键是指向字符串的指针。那为什么字符串也可以输入到strcmp函数里面呢?就是因为字符串也是指针。在一定方面来说。
// 
//
#include <stdio.h>
#include <string.h>
#define row 20
#define line 81
#define HALT ""
char* get_s(char * ch, int size1);
void charsort(char* p[], int size);
//主函数
int main(void)
{
	int chi=0;
	int cho;
	char input[row][line];
	char *ptr[row];
	printf("最多可以输入%d行的字符串\n",row);
	printf(" 如果想结束的话,那就换一行结束\n");
	//二维数组的输入,并且用指针表示出来
	while (chi < row  && get_s(input[chi], line) != NULL&&input[chi][0] != '\0' )//卧槽尼玛,竟然是&&运算的,如果前一个运算表达式为假,后面就不用考虑。
	//但是为什么while (chi < row  &&input[chi][0] != '\0'&& get_s(input[chi], line) != NULL )这样的话,必须要执行20次,很奇怪
	{
		ptr[chi] = input[chi];
		chi++;
	}

	//二维数组的排序

	charsort(ptr, chi);//这他妈的竟然合理了,我塔米牛逼

		//二维数组的输出
	puts("\n最后的结果是\n");
	for (cho = 0; cho < chi; cho++)
			puts(ptr[cho]);

	return 0;
}



//字符串排序函数
void charsort(char* p[], int size)
{
	//采用选择排序的方法。
	int top, seek;
	char* pt;
	for (top = 0; top < size - 1;top++)//假设二维数组有20个一维数组,为什么排序的第一个元素是0-18.原因是最后一个一维数组可以不用排序
	
		for (seek = top+1; seek < size; seek++)//seek=top+1.这里的思想很好,值得记住.因为如果还是从你开始的话,你重复了,虽然可以实行,但是效率太低.
		//这里有点不理解为什么p来代表
			if (strcmp(p[top], p[seek]) > 0)//按照字母表的顺序来排序
				int strcmp(const char* s1, const char* s2);关键是这个函数的两个参数支持指针,而p[top]以及p[seek]都是char *ptr[row];中的元素,都是指向char的指针
			{
				pt = p[top];
				p[top] = p[seek];
				p[seek] = pt;

			}
		
	
}


//字符串输入功能
char* get_s(char* chee, int size1)
{

	char* retu;
	int i = 0;

	retu = fgets(chee, size1, stdin);
	if (retu)
	{
		while (chee[i] != '\n' && chee[i] != '\0')
			i++;
		if (chee[i] == '\n')
			chee[i] = '\0';
		else
			while (getchar() != '\n')
				continue;
	}

	return retu;
}

4编译练习第三题

//3.设计并测试一个函数,从一行输入中把一个单词读入一个数组中,并丢弃输入行中的其余字符。该函数应该跳过第1个非空白字符前面的所有空白。将一个单词定义为没有空白、制表符或换行符的字符序列。
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define size 10
//1. 测试函数表明,当有子函数里面有多个return语句的时候,当输出一个return语句之后,子函数结束
char* getword(char* dest);
int main(void)
{
	char* p;
	char ch[size];
	puts("请输入一个单词");
	while (getword(ch) != NULL)
	{
		printf("result\n");
		puts(ch);
		printf("you can enter a word again\n");

	}
	printf("done\n");
	puts(ch);
	return 0;
}

char* getword(char* dest)
{
	int ch;
	int inputnum;//输入的数目个数
	while ((ch = getchar()) != EOF && isspace(ch))
	{
		continue;
	}//为了解决字符前面的空格
	if (ch == EOF)
		return NULL;
	else//现在这个位置上面只能是字符
	{
		*dest++ = ch;
	}
	while ((ch = getchar()) != EOF && !isspace(ch))
	{
		*dest++ = ch;
	}
	//这是遇到空白,或者遇到eof的时候才退出。
	*dest = '\0';
	//if (ch == EOF)//这两个如果应该是在判断循环结束之后,的判断条件
	//{
	//	return NULL;//我感觉这个写不写好像没有关系。是不是我的错觉
	//}
	//else
	//{
		while (getchar() != '\n')
			continue;
		return dest;
	/*}*/
}

5.设计并测试一个函数,从输入中获取n个字符(包括空白、制表符、换行符),把结果存储在一个数组里,它的地址被传递作为一个参数

// 
// 闪光点:str[i] = '\0';这个很关键。当我知道当数组存储一个字符串的时候,他的后面必须是'\0'。
//所以思考puts,以及fpus以及gets和fgets函数后面是否也要加上符号
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define size 10
void getnchar(char str[], int n);
int main(void)
{
	char p[size];
    getnchar(p, size);
	printf("下面是结果\n");
	puts(p);

	return 0;
}

void getnchar(char str[], int n)
{
	int i;
	for (i = 0; i < n - 1; i++)
	{
		str[i] = getchar();
		if (isblank(str[i]))
			break;
	}
	str[i] = '\0';
	return;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

正在变秃的程序猿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值