C/C++字符串输入输出和字符串函数基础学习

39 篇文章 14 订阅

字符串常量(字符串字面量)

用双括号括起来的内容称为字符串字面量,也叫做字符串常量。属于静态存储类别,如果在函数中使用字符串常量,该字符串只会被储存一次,在整个程序的生命周期内存在,计时函数被调用多次。被双引号括起来的内容被视为指向该字符串储存位置的指针。

/*
	输出结果:
	We,  0000000000404000,  t
	根据%s打印出We,根据%p转换说明打印出一个地址,因此"are"代表一个地址
	最后,*"the best"表示字符串所指向地址时储存的值,为该字符串的首字母 t 
*/
	printf("%s,  %p,  %c\n","We", "are", *"the best");

字符串数组和初始化

定义字符串数组时,必须让编译器知道需要多少空间。一种方法是用足够空间的数组储存字符串:

char m1[40] = "Limit yourself to one line's worth";

在指定数组大小时,要确保数组的元素至少比字符串的长度多1(为了容纳空字符),所有未被使用的元素都被自动初始化为0(这里的0指的是char形式的空字符,不是数字字符0)。
还可以让编译器确定数组的大小:

char m2[] = "If you can't think of anything,fake it.";

让编译器计算数组的大小只能用在初始化数组时,如果创建一个稍后再填充的数组,必须要在声明中指定大小:

//错误
char m3[];
m3 = "this is a test"; 
//正确
char m3[50];
m3[50] = "this is a test"; 

数组形式和指针形式

  • 初始化数组把静态存储区的字符串拷贝到数组中
  • 初始化指针只把字符串的地址拷贝给指针
#include<stdio.h>
#define MSG "I'm special"
int main(void){
	char arr[] = MSG;
	const char * pt = MSG;
	printf("address of \"I'm special\"   : %p \n", "I'm special");
	printf("             address of arr: %p \n", arr);
	printf("              address of pt: %p \n", pt);	
	printf("             address of MSG: %p \n", MSG);
	printf("address of \"I'm special\"   : %p \n", "I'm special");
	/*
	结果: 
		address of "I'm special"   : 0000000000404000
		             address of arr: 000000000024FE30
		              address of pt: 0000000000404000
		             address of MSG: 0000000000404000
		address of "I'm special"   : 0000000000404000
	分析:
		----pt和MSG的地址相同,而arr的地址不同,说明了此时字符串有两个副本,一个在静态内存中
			一个在arr数组中
		----编译器会把多次使用的相同字面量储存在一处或多处,当前编译器是都储存在一处。别的编译器可能在不同的位置上储存3个"I'm special" 
	*/
	return 0;
}

数组和指针的区别

char heart[] = "I love U";
const char * head = "I love her";

两者主要的区别是:数组名heart是常量,而指针名head是变量

// 指针数组,字符串数组
#include<stdio.h>
#define SLEN 40
#define LIM 5
int main(void){
	const char *m[LIM] = {
		"this is a test1",
		"this is a test2",
		"this is a test3",
		"this is a test4",
		"this is a test5"
	};
	char y[LIM][SLEN] = {
		"aaaaaaaaaaaaaa",
		"bbbbbbbbbbbbbb",
		"cccccccccccccc",
		"dddddddddddddd",
		"eeeeeeeeeeeeee"
	};
	int i;
	for(i = 0; i < LIM; i++)
		printf("%-36s    %-25s\n",m[i],y[i]);
	printf("\n某个字符:%c    %c\n",m[1][1],y[2][2]);
	printf("\nsizeof m = %u,   sizeof y = %u\n",sizeof m,sizeof y);
	/* 
	结果: 
		this is a test1                         aaaaaaaaaaaaaa
		this is a test2                         bbbbbbbbbbbbbb
		this is a test3                         cccccccccccccc
		this is a test4                         dddddddddddddd
		this is a test5                         eeeeeeeeeeeeee
		
		sizeof m = 40,   sizeof y = 200
	*/
	return 0;
} 

分析:
数组m和y都代表五个字符串,使用一个下标时都分别代表一个字符串,如m[1]和y[1];
使用两个下标时表示一个字符如 m[1][1],y[2][2],而且二者的初始方式也相同
区别:
1.数组m是一个内含五个指针的数组,在系统中占40个字节;而数组y为y[40][5]每个数组内有40个char类型的值,共占用200字节。
2.m中的指针指向初始化时所用的字符串常量的位置,而这些字符串常量被储存在静态内存中,而y数组中储存的是字符串常量的副本,所以每个字符串都被储存了两个;
综上所述,如果要用数组表示一系列待显示的字符串,请使用指针数组,它比二维字符串数组的效率高,但是,指针数组也有缺点:指针所指向的字符串常量不能更改,而二维字符串数组中的内容可以更改,所以,如果要更改字符串或者为字符串输入预留空间,不要使用指向字符串常量的指针 。

字符串输入

要做的第一件事就是分配空间

//错误示例
char *name;
scanf("%s",name);
//因为scanf()要把信息拷贝到参数指定的地址上,而此时参数是个未初始化的指针,name可能指向任何地方

gets()函数

#include<stdio.h>
int main(void){
	char words[2];
	
	puts("Enter a string, please.");
	gets(words);
	printf("Your string twice:\n");
	printf("%s\n", words);
	puts(words);
	puts("Done.");
	/*
		问题出现在gets()唯一的参数是words,它无法检测数组是否装得下输入行,gets()只知道数组开始处
		并不知道数组有多少个元素,如果输入的字符串过长,会导致缓冲区溢出。 
	*/	
	return 0;
} 

fgets()函数和fputs()函数

fgets()函数通过第二个参数限制读入的字符数来解决溢出的问题。该函数专门设计用于处理文件输入,所以一般情况下不太好用。fgets()和gets()的区别如下:

  • fgets()的第二个参数指明了读入字符的最大数量,如果该参数是n,那么fgets()将读入n-1个字符,或者读到遇到的第一个换行符为止。
  • fgets()的第三个参数指明要读入的文件,如果读入从键盘输入的数据,则以stdin作为参数
    与fputs()连用,fputs()的第二个参数指明它要写明的文件,如果要显示在计算机显示器上,则使用stdout作为参数。
  • puts()函数会在输出字符串末尾添加一个换行符,而fputs()不会。
  • fgets()函数会返回指向char的指针如果一切进行顺利,该函数返回的地址与传入的第一个参数相同。但是,如果函数读到文件末尾和错误的时候,它将返回一个特殊的指针:空指针。该指针保证不会指向有效的数据,在代码中,可以用0代替,在C语言中,用宏NULL代替。
#include<stdio.h>
#define STLEN 14
int main(void){
	char words[STLEN];
	puts("Enter a string, please.");
	fgets(words,STLEN,stdin);
	printf("**************fputs**************\n");
	fputs(words,stdout);
	puts("**************puts*******************");
	puts(words);
	puts("**************printf*******************");
	printf("%s",words);
	puts("Done!");
	/*当输入"test"时,小于STLEN,会读取换行符 
		Enter a string, please.
		test
		**************fputs**************
		test
		**************puts*******************
		test
	
		**************printf*******************
		test
		Done!
	  当输入"this is a test"时,长度大于STLEN,不会读取换行符
	  	Enter a string, please.
		this is a test
		**************fputs**************
		this is a tes**************puts*******************
		this is a tes
		**************printf*******************
		this is a tesDone!
		 
	*/
	return 0;
} 
#include<stdio.h>
#define STLEN 10
int main(void){
	char words[STLEN];
	int i; 
	
	puts("Enter strings (empty line to quit):");
	//如果按了回车,或者输入大于等于STLEN-1个字符就会进入循环
	//也就是说此时字符末尾一定是'\n'或者'\0' 
	while (fgets(words,STLEN,stdin) != NULL && words[0] != '\n'){
		i = 0;
		//通过循环一直跳到字符末尾 
		while(words[i] != '\n' && words[i] != '\0')
			i++;
		//如果是换行符就用'\0'替换 
		if(words[i] == '\n')
			words[i] = '\0';
		else //如果 word[i] == '\0',说明字符长度已经到了STLEN-1个,它之后的字符要忽略 
			while (getchar() != '\n')
				continue;
		puts(words);
	}	
	puts("Done!");
	return 0;
} 

空指针和空字符

  • 空字符(’\0’)是用于标记C字符串末尾的字符,对应的字符编码是0.
  • 空指针(或NULL)有一个值,该值不会与任何数据的有效值对应上,,通常函数使用它返回一个有效地址,表示某些特殊情况发生,例如遇到文件结尾或未能按预期执行。
    空字符是整数类型,而空指针是指针类型,它们都可以用 0 表示,但是从概念上看,是两个不同的0,空字符是一个字符,占1个字节,空指针是一个地址,通常占8个字节。
	printf("sizeof NULL = %u\n",sizeof NULL);
	printf("sizeof '\\0' = %u\n",sizeof '\0');
	结果:
		sizeof NULL = 8
		sizeof '\0' = 4

gets_s()函数

//用法
gets_s(word,STLEN);

与fgets()的区别:

  • gets_s()只从标准输入中读取数据,所以不需要第三个参数
  • 如果gets_s()读到换行符,会丢弃它而不是储存它
  • 如果gets_s()读到最大字符数都没有读到换行符,会执行以下几步:首先把目标数组中的首字符设置为空字符,读取并丢弃随后的输入,直至读到换行符或者文件结尾,然后返回空指针。

scanf()函数

scanf()更像是“获取单词”函数,而不是获取字符串函数。

#include<stdio.h>
int main(void){
	char name[11];
	char name1[11],name2[11];
	int count;
	scanf("%s",name);
	printf("Please enter 2 names .\n");
	count = scanf("%5s %10s",name1,name2);
	printf("I read the %d names %s 、 %s and %s.\n",count, name1, name2,name);
	
	return 0;
}

字符串输出

C有3个标准库函数用于打印字符串:put()、fputs()和printf()。

puts()函数

//使用puts()
#include<stdio.h>
#define DEF "I am a #define string."
int main (void){
	char str1[80] = "An array was initialized to me";
	const char * str2 = "A pointer was initialized to me.";
	/*
		puts()函数只需把字符串的地址作为参数传递给它即可,遇到空字符时就停止输出,所以要确保字符串中有空字符。 
	*/
	puts("I am argument to puts().");
	puts(DEF);
	puts(str1);
	puts(str2);
	puts(&str1[5]);
	puts(str2 + 4);
	
	return 0;
} 

fputs()函数

printf() 函数

自定义输入输出函数

//my_puts 用户自定义输出函数
#include<stdio.h>
void put1(const char *);
int put2(const char *);

int main(void){
	put1("If I had much money");
	put1(" as I could spend,\n");
	printf("I count %d characters.\n",
	put2("I never would cry old chairs"));
	return 0;
} 

void put1(const char * string){//不会改变字符串 
	while(*string) //与 *string != '\0'相同
		putchar(*string++); //先使用后自加 
}
int put2(const char * string){
	int count = 0;
	while(*string){
		putchar(*string++);
		count++;
	}
	putchar('\n');
	return count;
} 

字符串函数

C库提供了多个处理字符串的函数,ANSI C把这些函数的原型放在string.h头文件中。
常用的有:strlen() strcat() strcmp() strncmp() strcpy() 和strncpy()。

strlen()函数

用于统计字符串长度。

#include<stdio.h>
#include<string.h>
void fit(char *, unsigned int );

int main(void){
	char msg [] = "Thing should be as simple as possible,"" but not simpler.";
	printf("The length of msg: %d\n",strlen(msg)); 
	printf("%s\n",msg); 	
	puts(msg);
	fit(msg,38);
	puts(msg);
	puts("more:");
	puts(msg + 39);
	printf("%s\n",msg); 
	return 0;
}

void fit(char *string, unsigned int size){
	if(strlen(string) > size)
	//puts()和printf()函数会在空字符处停止输出,并忽略其余字符 
		string[size] = '\0';
}
//结果:
The length of msg: 55
Thing should be as simple as possible, but not simpler.
Thing should be as simple as possible, but not simpler.
Thing should be as simple as possible,
more:
but not simpler.
Thing should be as simple as possible,

strcat() 函数

strcat()函数用于拼接字符串,接收两个字符串作为参数,该函数把第二个字符串的备份附加在第一个字符串的末尾,并把拼接后形成的新字符串作为第一个字符串,第二个字符串不变。strcat()函数的类型是char *(即指向char的指针),返回第一个参数的地址。

#include<stdio.h>
#include<string.h>
#define SIZE 80
char * s_gets(char * st, int n);
int main(void){
	char flower[SIZE];
	char addon [] = "s smell like old shoes.";
	puts("What is your favorite flower");
	char * ch = s_gets(flower, SIZE);
	puts(ch);
	printf("%p\n",ch); 
	printf("%p\n",flower); 
	if(ch){
		strcat(flower,addon);
		puts(flower);
		puts(addon);
	}
	else{
		puts("End of file encountered!");
	}
	puts("bye");
	
	return 0;
}
char * s_gets(char * st, int n){
	char * ret_val;
	int i = 0;
	
	ret_val = fgets(st, n, stdin);//如果一切进行顺利,返回的是第一个字符的地址 ,遇到文件结尾或者错误时返回NULL 
	if(ret_val){//如果输入成功 
		while (st[i] != '\n' && st[i] != '\0')//跳转到字符串末尾 
			i++;
		if(st[i] == '\n')//替换掉换行符 
			st[i] = '\0';
		else//如果输入字符串超出字数,之后的字符就省略 
			while (getchar() != '\n')
				continue;
	} 
	return ret_val;//输入正常则返回字符串首字符地址 
}

strncat()函数

strcat()函数无法检查第一个数组是否能容纳第二个字符串。如果分配给第一个数组的空间不够大,多出来的字符溢出到相邻的存储单元时就会出问题。strncat()函数的第三个参数指定了最大添加字符数。例如,

strncat(bugs, addon, 13);
//把addon字符串的内容附加给bugs,在加到第13个时或遇到空字符时停止。因此第一个数组应该足够大。
#include<stdio.h>
#include<string.h>
#define SIZE 5
#define BUGSIZE 13 
char * s_gets(char * st, int n);

int main(void){
	char flower[SIZE];
	char addon [] = "s smell like old shoes.";
	char bug[BUGSIZE];
	int available;
	
	
	puts("What is your favorite flower");
	char * ch = s_gets(flower, SIZE);

	if((strlen(addon) + strlen(flower) + 1) <= SIZE)
		strcat(flower,addon);
	
	puts(flower);
	
	puts("What is your favorite bug?");
	s_gets(bug,BUGSIZE);
	available = BUGSIZE - strlen(bug) - 1;//算上了空字符串
	 
	strncat(bug, addon, available);
	puts(bug);
	
	
	return 0;
}
char * s_gets(char * st, int n){
	char * ret_val;
	int i = 0;
	
	ret_val = fgets(st, n, stdin);//如果一切进行顺利,返回的是第一个字符的地址 ,遇到文件结尾或者错误时返回NULL 
	if(ret_val){//如果输入成功 
		while (st[i] != '\n' && st[i] != '\0')//跳转到字符串末尾 
			i++;
		if(st[i] == '\n')//替换掉换行符 
			st[i] = '\0';
		else//如果输入字符串超出字数,之后的字符就省略 
			while (getchar() != '\n')
				continue;
	} 
	return ret_val;//输入正常则返回字符串首字符地址 
}

strcmp()函数

如果两个字符串参数相同,该函数就返回0,否则就返回非零值。
它比较的是字符串,而不是整个数组。

#include<stdio.h>
#include<string.h>
#define SIZE 40
#define ANSWER "Grant" 
char * s_gets(char * st, int n);

int main(void){
	char try[SIZE];

	puts("Who is buried in Grant's tomb?");
	s_gets(try,SIZE);
	while (strcmp(try, ANSWER) != 0){
		printf("%d\n",strcmp(try, ANSWER));
		puts("No,that is wrong.Try again.");
		s_gets(try,SIZE);
	}
	puts("That is right!");
	
	return 0;
}
char * s_gets(char * st, int n){
	char * ret_val;
	int i = 0;
	
	ret_val = fgets(st, n, stdin);//如果一切进行顺利,返回的是第一个字符的地址 ,遇到文件结尾或者错误时返回NULL 
	if(ret_val){//如果输入成功 
		while (st[i] != '\n' && st[i] != '\0')//跳转到字符串末尾 
			i++;
		if(st[i] == '\n')//替换掉换行符 
			st[i] = '\0';
		else//如果输入字符串超出字数,之后的字符就省略 
			while (getchar() != '\n')
				continue;
	} 
	return ret_val;//输入正常则返回字符串首字符地址 
}

strncmp()函数

strcmp()函数比肩字符串的字符,直到发现不同的字符为之,这一过程可能会持续到字符串的末尾。而strncmp()函数在比较字符串时,可以比较到字符不同的地方,也可以只比较第3个参数指定的字符数。

#include<stdio.h>
#include<string.h>
#define LISTSIZE 6
int main(void){
	
	const char * list[LISTSIZE] = {
		"astronomy","astounding",
		"astrophysics","ostracize",
		"asterism","astrophobia"
	};
	int count = 0;
	int i;
	
	for(i = 0; i < LISTSIZE; i++){
		//第三个参数的数字是指定用多少个第二的字符串的字符与第一个字符串作比较,如果为2则用“as"与第一个字符串作比较 
		if(strncmp(list[i],"astro",6) == 0){
			printf("Found:%s\n",list[i]);
			count++;
		}
	}
	printf("The list contained %d words beginning with astro.\n",count);
	
	return 0;
} 

strcpy()函数

strcpy()函数相当于字符串赋值运算符。
第一个参数是目标字符串,第二个参数是源字符串。

char target[20];
int x;
x = 4; //数字赋值
strcpy(target,"Hello!");//字符串赋值
target = "Clippers";//语法错误

程序员要确保目标数组有足够的空间容纳源字符串的副本,以下的代码有问题:

char * str:
strcpy(str,"Hi");//有问题

str未被初始化,所以该字符串可能被拷贝到任意地方。

-strcpy()的返回类型是char *,该函数返回的是第一个参数的值,即一个字符的地址。
第一个参数不必指向数组的开始,这个属性可用于拷贝数组的一部分。

#include<stdio.h>
#include<string.h>
#define SIZE 40
#define LIM 5 
char * s_gets(char * st, int n);

int main(void){
	char qwords[LIM][SIZE];
	char temp[SIZE];
	int i = 0;
	const char * orig = "beast";
	char copy[40] = "Be the best that you can be.";
	char *ps;
	
	puts(orig);
	puts(copy);
	ps = strcpy(copy + 7,orig);
	puts(copy);
	puts(ps);
	puts("***********************");
	
	
	printf("Enter %d words beginning with q:\n",LIM);
	while (i < LIM && s_gets(temp, SIZE)){
		if(temp[0] != 'q')
			printf("%s doesn't begin with q !\n",temp);
		else{
			strcpy(qwords[i], temp);
			i++;
		}
	}
	
	puts("Here ate the words accepted:");
	for(i = 0; i < LIM; i++){
		puts(qwords[i]);
	}
	
	
	return 0;
}
char * s_gets(char * st, int n){
	char * ret_val;
	int i = 0;
	
	ret_val = fgets(st, n, stdin);//如果一切进行顺利,返回的是第一个字符的地址 ,遇到文件结尾或者错误时返回NULL 
	if(ret_val){//如果输入成功 
		while (st[i] != '\n' && st[i] != '\0')//跳转到字符串末尾 
			i++;
		if(st[i] == '\n')//替换掉换行符 
			st[i] = '\0';
		else//如果输入字符串超出字数,之后的字符就省略 
			while (getchar() != '\n')
				continue;
	} 
	return ret_val;//输入正常则返回字符串首字符地址 
}

strncpy()函数

strcpy()和strcat()函数都有同样的问题,他们都不能检查目标空间是否有足够的容量容纳源字符串的副本。

字符串排序

//读入字符串并排序
#include<stdio.h>
#include<string.h>
#define SIZE 81 //限制字符串长度,包括\0
#define LIM 20 //可读入的最多行数 
#define HALT "" //空字符串停止输入
void ststr(char * st [], int num);//字符串排序函数
char * s_gets(char * st, int n);

int main(void){
	char input[LIM][SIZE];
	char *ptstr[LIM];//内含指针变量的数组,指针数组里面存储的是指针,每一个元素占8个字节 
	int ct = 0;
	int k;
	char * test[] = {"this","is","testing"};
	printf("%p\n",test[0]);
	printf("%p\n",test[1]);
	printf("%u\n",sizeof test);
	printf("Input up to %d lines, and I will sort them .\n",LIM);
	printf("To stop,press the Enter key at a line's start.\n");
	//输入行数小于LIM,输入没有错误,输入的首字符不是空字符,则循环输入 
	while (ct < LIM && s_gets(input[ct], SIZE) != NULL && input[ct][0] != '\0'){
		ptstr[ct] = input[ct];//把每一行的地址都传入ptstr 
		ct++; 
	}
	//输入完毕,进行排序
	ststr(ptstr,ct);
	for( k = 0; k < ct; k++)
		puts(ptstr[k]); 
	
	return 0;
}

void ststr(char *strings [], int num){
	char * temp;
	int top,seek;
	/*
		选择排序算法:
		第一个大循环:第一个元素分别和第二个,第三个。。。作比较,较大的元素放在第一位 做完一轮比较后, 第一个元素为最大的 
		第二个大循环:第二个元素分别与第三个第四个元素比较,较大的放在第二个元素上,比较结束后,第二大的元素位于排在第二
		。。。 
		在这里是排序指针,而不是字符串
	*/
	for(top = 0; top < num-1; top++)
		for(seek = top + 1; seek < num; seek++)
			if(strcmp(strings[top], strings[seek]) > 0){
				temp = strings[top];
				strings[top] = strings[seek];
				strings[seek] = temp;
			}
}

char * s_gets(char * st, int n){
	char * ret_val;
	int i = 0;
	
	ret_val = fgets(st, n, stdin);//如果一切进行顺利,返回的是第一个字符的地址 ,遇到文件结尾或者错误时返回NULL 
	if(ret_val){//如果输入成功 
		while (st[i] != '\n' && st[i] != '\0')//跳转到字符串末尾 
			i++;
		if(st[i] == '\n')//替换掉换行符 
			st[i] = '\0';
		else//如果输入字符串超出字数,之后的字符就省略 
			while (getchar() != '\n')
				continue;
	} 
	return ret_val;//输入正常则返回字符串首字符地址 
} 
 

ctype.h字符函数

C++中cin和cout

在C语言中,我们通常会使用 scanf 和 printf 来对数据进行输入输出操作。在C++语言中,C语言的这一套输入输出库我们仍然能使用,但是 C++ 又增加了一套新的、更容易使用的输入输出库。
C++ 中的输入与输出可以看做是一连串的数据流,输入即可视为从文件或键盘中输入程序中的一串数据流,而输出则可以视为从程序中输出一连串的数据流到显示屏或文件中。

在编写 C++ 程序时,如果需要使用输入输出时,则需要包含头文件iostream,它包含了用于输入输出的对象,例如常见的cin表示标准输入、cout表示标准输出、cerr表示标准错误。
使用 cout 进行输出时需要紧跟<<运算符,使用 cin 进行输入时需要紧跟>>运算符,这两个运算符可以自行分析所处理的数据类型,因此无需像使用 scanf 和 printf 那样给出格式控制字符串。
“<<” 和 “>>” 提供了 C++ 语言的字符串输入和字符串输出功能。"<<" 可以将字符读入一个流中(例如 ostream);">>" 可以实现将以空格或回车为 “结束符” 的字符序列读入到对应的字符串中,并且开头和结尾的空白字符不包括进字符串中。

C++:getline(),每次读取一行字符串输入

char name[20];
cin.getline(name,20);//读取20个字符到name
#include <iostream>
#include <string>
using namespace std;
void main ()
{
string s1, s2;
getline(cin, s1);
getline(cin, s2, ' ');
cout << "You inputed chars are: " << s1 << endl;
cout << "You inputed chars are: " << s2 << endl;
}

C++:string类简介

string类位于命名空间std中,所以需要使用using来应用,或者通过std::string来引用。,它隐藏了字符串的数组性质,可以像处理普通变量一样处理字符串。

#include <iostream>
#include<string>

using std::cout;
using std::cin;
using std::endl;
using std::string;

int main(void) {
	
	string str1;
	string str2 = "Hello";
	cout << "Enter your name;" << endl;
	cin>>str1;
	//string类操作
	str2 += " "+str1;
	cout << str2 << endl;
	//求字符串长度
	cout << "The size of str2 is :"<<str2.size() << endl;
	cout << str2[2] << endl;
	//使用getline输入字符串
	string str3;
	getline(cin, str3);
	cout << str3 << endl;
	return 0;
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SOC罗三炮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值