C语言学习笔记

输入输出函数

printf 格式输出到屏幕
fprintf 格式输出到磁盘

scanf 从屏幕格式输入
fscanf 从磁盘格式输入

putchar 字符输出到屏幕
puts 字符串输出到屏幕
fputc 字符输出到磁盘
fputs 字符串输出到磁盘

getchar 从屏幕得到一个字符
gets 从屏幕得到一个字符串
fgetc 从磁盘得到一个字符
fgets 从磁盘得到一个字符串

双链表中删除节点

1,首先查找需要删除的节点(Node)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h> 
#include <time.h>

struct mytime
{   
	//char name[256];
	int hour;//时
	int min; //分
	int sec; //秒
};

struct  stu_data
{
	char name[256];//学生名字
	int sex;//0女生,非0表男生
	struct mytime stuTime;//签到时间
	struct  stu_data* front; //指向前一个结点
	struct  stu_data* back;  //指向后一个结点

}  ;

int main(int argn,char* argv[])// int a[1]//a[0]
{   
    struct mytime t2;
    struct stu_data *stu,*p,*Head,*tail,*Node;
    time_t t;// long int
    struct tm * timfo;
    int i;
 
    //建立Head头结点
    Head=p=tail=malloc(sizeof( struct stu_data)); //256+12=268
    Head->back=Head->front=Head;//循环链表初始化头结点
    memset(p,0,sizeof( struct stu_data));
    strcpy(Head->name,"头结点");

	do
	{
        //插入新的结点
        stu= malloc(sizeof( struct stu_data)); //
        memset(stu,0,sizeof( struct stu_data)); //初始化内存区域

        //stu->back=NULL; //新结点尾指针置空
        //p->back=stu; //前驱结点back指针指向新结点
        //p=stu; //重要移动标志指针

        stu->front=p; //新结点指向前驱  2
        stu->back=NULL; //新结点尾指针置空
        p->back=stu; //前驱结点back指针指向新结点
        p=stu; //重要移动标志指针
        tail=stu;//可有可无的  2

        scanf("%s",&stu->name);
        time(&t);
        timfo= localtime(&t); //取当前系统时间 
        stu->stuTime.hour=timfo->tm_hour;//时
        stu->stuTime.min=timfo->tm_min;//分
        stu->stuTime.sec=timfo->tm_sec;//秒
		//构建循环链表
        Head->front=stu;
        tail->back=Head;
	 } while(strcmpi(stu->name,"exit")!=0);
 
   Node= FindNode(Head,"s1");
   //删除结点
   DeleteNode(Node);

   //初始指针p 使他头结点Head
   stu=Head->back;
   do 
   {
     printf("%s,到校时间:%d时%d分%d秒\n",
            stu->name, 
            stu->stuTime.hour, 
            stu->stuTime.min, 
            stu->stuTime.sec); 
    stu=stu->back;
   } while (strcmpi(stu->name,"exit"));  
	return 0;
}
struct  stu_data * FindNode(struct  stu_data* Head,char* Name)
{
     struct  stu_data * stu;
     stu=Head->back;
     do 
     {
         if (strcmpi(stu->name,Name)==0)
         {
             printf("%s,到校时间:%d时%d分%d秒\n",
                    stu->name, 
                    stu->stuTime.hour, 
                    stu->stuTime.min, 
                    stu->stuTime.sec);
             if (stu->sex)
               printf(" 男\n\n");
             else            
               printf(" 女\n\n");
             return stu;
         }
         stu=stu->back;
     } while (stu!=Head->back);
 
     return NULL;
 }

2,删除节点

struct stu_data* DeleteNode(struct stu_data* Node)
{
    if (Node==NULL)  return;

	 Node->front->back=Node->back;
	 Node->back->front=Node->front;
	 free(Node);//释放结点空间
 }
 

验证节点是否删除

//初始指针p 使他头结点Head
stu=Head->back;
do 
{
    printf("%s,到校时间:%d时%d分%d秒\n",
            stu->name, 
            stu->stuTime.hour, 
            stu->stuTime.min, 
            stu->stuTime.sec);
    stu=stu->back;
   } while (strcmpi(stu->name,"exit"));

 

二叉树

 二叉树是一种递归定义。每一个二叉树的结点最多可以指向2个结点(左结点一个,右结点一个)。

满二叉树:除最后一层节点外,其他节点都是两个节点

完全二叉树:非满二叉树,只有左节点

非完全二叉树:非满二叉树,只有右节点

有序二叉树:满足:左节点<根节点<右节点  或者 根节点<左节点<右节点  总之:右节点始终大于左节点的值

创建结点:

struct node
{
 long  data; //存放数据的一个或者多个项 
 struct node *pLeft;  //左孩子 指向一个二叉树
 struct node *pRight; //右孩子  指向一个二叉树
}

//创建节点
struct node *p=malloc(sizeof(struct node));
p->pLeft=p->pRight=NULL;
p->data=0

构建二叉树:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h> 
#include <time.h>
struct node
{
	long  data; //存放数据的一个或者多个项 
	long count;
	struct node *pLeft;  //左孩子 指向一个二叉树
	struct node *pRight; //右孩子  指向一个二叉树
};

struct node * CreateNode(long value)
{
	struct node *p=malloc(sizeof(struct node));
	p->pLeft=p->pRight=NULL;
	p->data=value;
	p->count=1;
}
struct node * AddNode(struct node * pNode,long v)
{
	//情况一 pNode==NULL
	if (pNode==NULL)
	{
		return CreateNode(v);
	}
	// pNode->data=v
	if (pNode->data==v)
	{
		pNode->count++;
		return pNode;
	}
	//v大于结点数据
	if (v>pNode->data)
	{
		if (pNode->pRight==NULL)
		{
			pNode->pRight=CreateNode(v);
			return pNode->pRight;
		}else return AddNode(pNode->pRight,v); //递归调用
	}
	//v小于 结点数据
	if (v<pNode->data)
	{
		if (pNode->pLeft==NULL)
		{
			pNode->pLeft=CreateNode(v);
			return pNode->pLeft;
		}else return AddNode(pNode->pLeft,v); //递归调用
	}

	return NULL;
}
int main(void)
{	
	struct node*root;
	long v,i;
	printf("请输入二叉树根结点数值:");
	scanf("%d",&v);
	root=CreateNode(v);
	for (i=0;i<=10;i++)
	{
		AddNode(root,i);
	}
 
	return 0;
}

二叉树遍历:

//二叉树遍历
void traversal(struct node* pNode)
{ 
    int i;
	if (pNode->pLeft!=NULL)
	{
		traversal(pNode->pLeft);
	}
	for (i=1;i<=pNode->count;i++)
	{
		printf("%d,",pNode->data);
	}
	if (pNode->pRight!=NULL)
	{
			traversal(pNode->pRight);
	}
}

 

共享内存--联合(union)

union : 指向同一块内存区域地址

struct:结构的数据是指向不同内存区域地址

Union联合:理解

  1. 将几个变量放在相同的内存区,但其中只有一个变量在给定时刻有有效值。
  2. 程序处理许多不同类型的数据,但是一次只处理一种。要处理的类型在执行期间才能确定。
  3. 在不同的时间访问相同的数据,但在不同的情况下该数据的类型是不同的。

 

typedef 自定义数据

typedef  类型   别名; typedef struct  _stu_data  stu_data;

 

文件操作

1,文件打开:

FILE*fopen(constchar*filename,constchar*mode);

filename是要操作的文件名。

mode

说明

"w"

打开一个文本文件,进行写入操作。如果文件不存在,则会建立一个新文件. 存在则清空内容。

"a"

打开一个文本文件,进行追加操作。如果文件不存在,则会建立一个新文件. 存在则追加内容。

"r"

打开一个文本文件,进行读取操作。

"w"

 FILEf;

 f=fopen("test.txt","w");

 f=fopen("test.txt","a");

 f=fopen("test.txt","r");

2,关闭文件 fclose

   int fclose(FILE*stream); //如果成功关闭返回0,不成功则返回EOF,EOF一般定义为-1;

3,写入文本文件fputc

intfputc(intc,FILE*stream);

  功能:向文件写入一个字符,且指针下移。

4,读取文本文件fgetc

intfgetc(FILE*stream);

  功能:从文件中获取一个字符,且指针下移。

#include <stdio.h>
int main(void)
{   
	 FILE* f;
	 char i;
	 f=fopen("test.txt","w");//"w","a"
     for (i='A';i<='Z';i++)
     {
		 fputc(i,f);
     }
	 fclose(f);//重要
	 f= fopen("test.txt","r");
	 for (i=1;i<=26;i++)
	 {
		 printf("%c",fgetc(f));

	 }
     fclose(f); 
	return 0;
}

5,字符串读写:

写:

int fputs( const char *string, FILE *stream );  //int fputs(char *pstr,FILE *pfile);

string待写入的字符串地址;

stream表示文件指针

读:

char *fgets( char *string, int n, FILE *stream );//char* fgets(char *pstr,int ncahrs,FILE *pfile);

string是用于存放字符串的缓冲区。

n表示要读出字符的个数。

stream表示文件指针

 

puts(char* s);//把字串输出到屏幕

gets(char* s);//读入字符串

int main(void)
{
    FILE* f;
    char I;
    char s[256];
    写字符串
    f=fopen("test.txt","w");//以写入模式打开文件
    gets(s);//scanf("%s",s);//从控制台读取字符串
    fputs(s,f);//向文件test.txt写入字符串s
    fclose(f);//关掉指针与文件的关联

    //读字符串
    f=fopen("test.txt","r");//以读取模式打开文件test.txt
    fgets(s,256,f);//从文件读取字串到s地址开始的缓存区
    puts(s);//printf("%s",s); 把字串输出到控制台显示出来 或者理解为向控制台屏幕写入字符串
    fclose(f);//关掉指针与文件的关联

    return 0;
}

6,格式化文件输出fprintf 

 int fprintf( FILE *stream, const char *format [, argument ]...);//printf 输出到控制台

eg: fprintf(f,"%d%d%f %s",111,222,444.88,"xxxbbb");

7,格式化文件输出fprintf 

 int fscanf( FILE *stream, const char *format [, argument ]... );//scanf从控制台获取输入

eg: fscanf(f,"%d%d%f%s",&n1,&n2,&f1,s);

8,文件重命名rename

int rename( const char *oldname, const char *newname );

oldname  //需要重新命名的文件名

newname  //新的文件名 

9,文件删除remove

int remove( const char *path );

path  //是全路径名称

10,流的重定向freopen:

区别:stdin和stdout都可以被重定向,stderr不能

FILE *f =freopen("test.txt","r",stdin); printf("%s",fgets(f)); //成功则返回stdin指针

ffreopen("test.txt","r",stdin);//stdin重定向至test输入

11,清空流缓冲区 fflush:

 int fflush( FILE *stream );// 返回0表示成功,非零表示出错

12,错误信息和错误处理 stderr:

//错误信息和错误处理
int main(void)
{   
	//未重定向的代码
	char num[256];
	FILE *f;
	f=fopen("test.txt","r"); 
	 if (f==NULL) //if (!f)
	 {
		 fprintf(stderr,"文件打开出错或者是文件不存在 \n");//stdout
		 perror("test.txt");
	 }
	return 0;
}

 

13,打开二进制文件

   FILE*fopen(constchar*filename,constchar*mode);

    filename是要操作的文件名。

mode

说明

"wb"

打开一个二进制文件,进行写入操作。如果文件不存在,则会建立一个新文件. 存在则清空内容。

"ab"

打开一个二进制文件,进行追加操作。如果文件不存在,则会建立一个新文件. 存在则追加内容。

"rb"

打开一个二进制文件,进行读取操作。

 

14,写二进制文件

   size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

//count*size 是要写入文件的字节数

 buffer是缓冲区指针

 stream是文件指针(或者流指针)

15,读二进制文件

   size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

//count*size 是要读取的字节数

buffer是缓冲区指针

stream是文件指针(或者流指针)

int main(void)
{   
	//未重定向的代码
	char num[256];
	FILE *f;
	stu_data stu10[10]={0};
	int i;
	time_t t1;
	struct tm * tm1;
	f=fopen("test.txt","rb");
	 //fprintf(f,"ddddd");
	 if (f==NULL) //if (!f)
	 {
		 //fprintf(stderr,"文件打开出错或者是文件不存在 \n");//stdout
		 perror("test.txt");
	 }
	 获取数据并写入文件
	 //for (i=0;i<10;i++)
	 //{
		// scanf("%s",&stu10[i].name );
		// time(&t1);
		// tm1=localtime(&t1);
		// //记录签到时间//记录学生 姓名和签到时间
		// stu10[i].stuTime.hour=tm1->tm_hour;
		//  stu10[i].stuTime.min=tm1->tm_min;
		//   stu10[i].stuTime.sec=tm1->tm_sec;
	 //}
	 写入到二进制文件里
	 //fwrite(stu10,sizeof(stu_data),10,f);
	 //读取二进制文件数据至stu10缓冲区
	 fread(stu10,sizeof(stu_data),10,f);
	 //显示数据
	 for (i=0;i<10;i++)
	 {
		 printf("name=%s  ",stu10[i].name);
		 printf("时间:%d-%d-%d \n",stu10[i].stuTime.hour,stu10[i].stuTime.min,stu10[i].stuTime.sec);
	 }
	 fclose(f); 
	return 0;
}

16,文件位置相关操作fgetpos和fsetpos

  • 找出我们在文件中的位置

  int fgetpos(FILE*pfile,fpos_t*position);

  fpost_t here=0;//fpos_t  一般是long类型,不同的系统可能有不同的区别所以最好用fpost   typedef

  fgetpos(pfile,&here);

 

  • 在文件中设定位置

与fgetpos配对的函数是fsetpos

   int fsetpos(FILE*pfile,fpos_t*position);

   fpost_t here=10;//fpos_t  一般是long类型,不同的系统可能有不同的区别所以最好用fpost   typedef

  fsetpos(pfile,&here);

  • 文件结束判断函数feof

   函数名: feof 

  功  能: 检测流上的文件结束符

   用  法: int feof(FILE *stream); feof(fp)有两个返回值: 如果遇到文件结束,函数feof(fp)的值为1,否则为0。

int main(void)
{   
	int i;
	FILE *f;
	fpos_t pos; //long pos;
	int temp;
	
    // 写入文件二进制数据
	//f=fopen("test.txt","wb");
	//fgetpos(f,&pos);
	//   //打印文件位置
	//printf("文件位置:%d,\n",pos);
	//for(i=1;i<=256;i++)
	//{
	//	fwrite(&i,sizeof(int),1,f);//4*256=1024

	//}
	//fgetpos(f,&pos);
	//printf("文件位置:%d,\n",pos);
    
    //读取文件二进制数据
	 f=fopen("test.txt","rb");
	 pos=(256-20)*sizeof(int);//4*20
	// fsetpos(f,&pos);
	  
	 while(!feof(f))
	 {
		 fread(&temp,sizeof(int),1,f);
		 printf("%d,",temp);
	 } 
	return 0;
}

17,文件位置相关操作ftell和fseek

  • 找出我们在文件中的位置

    long ftell (FILE *pfile);

    longfpos=ftell(pfile); //fgetpos 通过指针返回fpost_t 位置

  • 在文件中设定位置

   与ftell配对的函数是fseek

   int fseek(FILE*pfile,long offset,int origin);

SEEK_CUR  //可正可负

指向当前位置

SEEK_END  // - 

文件结束位置

SEEK_SET  // + 

文件开始

成功,返回0,否则返回其他值。

 fseek(f,  20,SEEK_CUR)   ;//指针后移20字节的位置

 fseek(f,-20,SEEK_END)   ;//从文件结束位置前移20字节的位置

 fseek(f,-20,SEEK_SET)   ;//这样写执行会不成功,对于SEEK_SET应该指定正数向后移指针才行fseek(f,20,SEEK_SET)

int main(void)
{   
	int i;
	FILE *f;
	fpos_t pos; //long pos;
	int temp;
    //写入二进制数据
	//f=fopen("t.txt","wb");
	//printf("%d,",ftell(f)); //fgetpos 代替
	//for (i=101;i<=356;i++)
	//{
	//	fwrite(&i,sizeof(int),1,f);//1024字节
	//	printf("%d,",ftell(f));
	//}
 
	//fseek读取数据
	f=fopen("t.txt","rb");
	//fseek
	//读取末尾的20个int数据
	fseek(f,0,SEEK_END);//指向文件尾
	pos=ftell(f);//1024
	if(fseek(f,pos/2,SEEK_SET)!=0)
	{//文件中间 512
		printf("fseek 失败 \n");
	}
	fseek(f,100,SEEK_CUR);  //612/4=153+101
	while(!feof(f))
	{
		fread(&temp,sizeof(int),1,f);
		printf("%d,",temp);
	} 
	return 0;
}

共享的方式打开文件或者流  安全性比fopen 高

 FILE *_fsopen( const char *filename,  const char *mode,  int shflag );  

filename  Name of the file to open.  //需要打开的文件名

mode   Type of access permitted.  //可以访问的类型

shflag   Type of sharing allowed.  //共享访问类型

 _SH_COMPAT   Sets Compatibility mode for 16-bit applications. //以兼容模式打开16位程序

 _SH_DENYNO   Permits read and write access.  //充许读和写  以此模式打开类似fopen

 _SH_DENYRD   Denies read access to the file.  //拒绝读

 _SH_DENYRW  Denies read and write access to the file.  //拒绝读和写

 _SH_DENYWR   Denies write access to the file  //拒绝写

#include <share.h>
 
int main(void)
{   
	 FILE *f1,*f2;
	 char s1[256],s2[256];
	 //同时打开文件读取
	 /*f1=fopen("share.txt","r");
	 f2=fopen("share.txt","r");*/
	 f1=f2=NULL;
	 f1=_fsopen("share.txt","r",_SH_DENYRW);//独占文件访问wb
	
	// f2=_fsopen("share.txt","r",_SH_DENYRW);
	 

	 if (!f1)
	 {
		 perror("打开出错");
	 }else
	 {
		 fgets(s1,256,f1);
		 printf("%s \n",s1);
	 }
      fclose(f1);
	 f2=fopen("share.txt","r");
	 if (!f2)
	 {
		 perror("打开出错");
	 }else
	 {
		 fgets(s2,256,f2);
		 printf("%s \n",s2);
	 }
	 //关掉指针
	fclose(f2); 
	return 0;
}

预处理

  • #include

  #include<file.h>  //表示在默认路径中搜索file.h 并用file.h里的内容替换#include<file.h>

   #include"file.h"  //表示在当前目录里搜索file.h 并用file.h里的内容替换#include"file.h"

  • #define

   #define filenaeme "test.txt" //在预处理时用"test.txt" 替换所有filename 并且删掉此行

   #deinfe pi 3.1415926       //在预处时  用3.1415926 替换所有pi        并且删掉此行

  • extern

  extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。(另外,在C++extern也可用来进行链接指定。)

如在a.c中定义过全局变量int a要在hello.c中引用全局变量a则要作如下定义:

extern int a;   

  仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。

如在a.c中定义过全局函数int add(int a,int b)要在hello.c中引用函数add则要作如下定义:

extern int add(int,int);   

   仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。

define 的高级应用
预处理换多行  

#define add(a,b) \ 

a+b

拼接字符

int my2=222;
#define cat(a,b) a##b   

printf(%d,cat(my,2))  == printf(%d,my2)  

 

条件编译

一、条件编译#if 条件

    #if  表达式

     代码段

    #endif

 //如果表达式成立则,编译代码段

 注意:表达式里测试的是预处理指令赋给标识符的指定值

二、条件编译#if defined

    #if  defined flag 

   代码段

    #endif

//用于测试flag 标识符是否被#define 指令定义过,如果定义过,则编译代码段

  #if !defined flag 

   代码段

  #endif

//用于测试flag 标识符是否被#define 指令定义过,如果未被定义过,则编译代码段

三、条件编译#if #else

  #if  表达式

   代码段1

  #else

   代码段2

  #endif

//如果表达式成立则编译代码段1,不成立则编译代码段2

 

多线程临界区

创建线程

//创建新线程

 HANDLE CreateThread(

  LPSECURITY_ATTRIBUTESlpThreadAttributes,    // pointer to security attributes
 //安全描述符指针

  DWORDdwStackSize,                            // initial thread stack size
     //初始化线程堆栈大小

  LPTHREAD_START_ROUTINElpStartAddress,     // pointer to thread function
   //重要 线程回调函数指针

  LPVOIDlpParameter,                            // argument for new thread
    //新线程参数

  DWORDdwCreationFlags,                        // creation flags
             //创建标志

  LPDWORDlpThreadId                           // pointer to receive thread ID
  //返回线程ID

);

DWORD WINAPI ThreadProc(

  LPVOID lpParameter   //接收CreateThread的第4个参数

)

{

 //添加线程代码

  return 1;

}

hand=CreateThread(NULL,0,ThreadProc,NULL,0,NULL);      //创建线程

三、临界区

   临界区在使用时以CRITICAL_SECTION结构对象保护共享资源,并分别用EnterCriticalSection()和LeaveCriticalSection()函数去标识和释放一个临界区

 CRITICAL_SECTION

InitializeCriticalSection

EnterCriticalSection

LeaveCriticalSection

 EnterCriticalSection

 LeaveCriticalSection成对出现可以保护全局共享资源有序访问

//恢复线程  

    ResumeThread(hThread);  

  //挂起线程 

    SuspendThread(hThread);  

CRITICAL_SECTION cs;

DWORD WINAPI ThreadProc1(
						LPVOID lpParameter   // 接收 CreateThread的第4个参数
						)
{  int i=0;
   while(1)
	//添加线程代码
   { i++;
   EnterCriticalSection(&cs);
    gotoxy(0,1);
	printf("i=%d  \n",i);
	Sleep(100);
 LeaveCriticalSection(&cs);
   }
	return 1;
}

DWORD WINAPI ThreadProc2(
						 LPVOID lpParameter   // 接收 CreateThread的第4个参数
						 )
{  int i=0;
while(1)
//添加线程代码
{ i++;
EnterCriticalSection(&cs);
gotoxy(0,3);
printf("i=%d  \n",i);
Sleep(100);
LeaveCriticalSection(&cs);
}
return 1;
}


//主函数
int main(void)
{  
	  
	InitializeCriticalSection(&cs);
	CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);	//创建线程
	CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);	//创建线程
	getch();
	printf("22222222222");
	getch();
	return 0;
}

随机数

 随机种子初始化函数srand     

  srand( (unsigned)time( NULL ) );

   rx=rand()%2;

 

播放声音

//增加库文件  播放自定义音频文件
#pragma  comment(lib,"winmm.lib")

//认识几个声音相关的函数   
BOOL MessageBeep(
  UINTuType   // sound type
);


BOOL sndPlaySound(
 LPCSTRlpszSound,  //*.wav 
 UINTfuSound      
);


BOOL PlaySound
(
LPCSTRpszSound, 
HMODULEhmod,   //只有播放资源文件里的声音才使用此参数,否则置NULL
DWORDfdwSound 
);



//添加声音效果 
void playwav()
{
	//MessageBeep(MB_ICONQUESTION  );
	//sndPlaySoundA("turn.wav",SND_ASYNC);
	//sndPlaySoundW(L"turn.wav",SND_ASYNC|SND_NODEFAULT);
	//sndPlaySound(L"turn.wav",SND_ASYNC|SND_NODEFAULT);
	//PlaySoundA("turn.wav",NULL,SND_ASYNC);
	PlaySound (L"turn.wav",NULL,SND_ASYNC);
}

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值