C语言03 - 函数指针、内存分配、字符串使用

1. 函数指针

int plus(int a, int b){
    return a + b;
}

// 函数名是一个函数的首地址,我已我们可以将函数赋值给对应类型的函数指针
int minus(int a, int b){
    return a - b;
}

int plus2(int *a, int *b){
    return *a + *b;
}

int minus2(char *a, char *b){
    return 0;
}

int main(){

    int result;
    int(*calc)(int a, int b); // 定义了函数指针
    //calc = plus;
    calc = minus;
    result = calc(3,5);
    printf("minus : %#x \n", minus);
    printf("result : %d \n",result); // plus result:8 。 minusresult:-2

    // ==========================
    int c = 3;
    int d = 5;
    int(*calc2)(void *a, void *);
    calc2 = (int(*)(void *, void *))plus2;// 强制类型转换
    result = calc2(&c,&d);
    printf("result : %d \n", result); // result : 8

    // void类型的指针:类似java中的object
    // 指针变量都是4个字节。都是用十六进制表示。
    // void * -> int * / char * / float *

    // ==============================================================================
    calc2 = (int(*)(void *, void *))minus2;
    result = calc2(&c, &d);
    printf("result : %d \n", result); // result : 0

    // ==============================================================================

    int *p(int a, int b);// 一个返回值是int *的函数,请和函数指针区别开来

    system("pause");
    return  0;
}

2. 内存分配

int const num = 100;  // 静态变量 静态存储区,不可改变值

void mem() {
    int *a = (int *)malloc(sizeof(int)* 1024 * 1024);  //4M  
}

int main(){

    // 40M 的数组
    // 报错 ,栈溢出:0x00EE1467 处有未经处理的异常(在 JNI_03_VS.exe 中):  0xC00000FD: Stack overflow (参数:  0x00000000, 0x00B82000)。
    // int a[1024 * 1024 * 10];

    // ==============================================================================

    // 在任务管理器可以看到 40.4M ,其中40M是我们开辟的
    // 剩下的0.4M 呢?
    // 内存:
    //  分为3区:
    //  程序区
    //  程序的二进制文件 (0.4M的由来)

    //  静态存储区
    //  全局变量和静态变量

    //  动态存储区
    //  堆区:用于程序动态分配  (比如 malloc)
    //  栈区:编译器自动分配,编译器自动申请和释放 2M , 局部变量,
    //        自动分配,程序退出自动释放free (比如:int a[1024 * 1024 * 10];
    //        预编译阶段,必须确定大小)
    // int *a = (int *)malloc(sizeof(int) *1024*1024*10);

    // ==============================================================================

    // int aa[num];
    // int b;
    // aa = &b;  // 报错,aa的地址是个常量,你能该他的内容,但是不能改他的地址(系统分配的是个常量)

    // ==============================================================================


    int t = 1000;
    int aa[10];   // aa的地址是个常量,你能该他的内容,但是不能改他的地址(系统分配的是个常量)
    int ab[100];
    /*while (1) {
        mem();
        Sleep(2000);
    }*/ // 每次都会申请4M。会越来越多

    //  void* malloc(size_t size)
    //  分配内存的单元是 字节, 大小 size,连续的内存
    //  如果申请失败,返回值是NULL
    //  为什么是void* 呢?
    //  int *a = (int *)malloc(sizeof(int) *1024*1024*10);
    //  如果 a  + 1  就是移动了 int 大小的 内存空间
    //  char *ch = (int *)malloc(sizeof(char) *1024*1024*10);
    //  ch +1  移动了 char大小的内存空间

    int *a = (int *)malloc(sizeof(int)* 1024 * 1024 *500);
    if (a == NULL)
    {
        // 如果我分配2G(sizeof(int)* 1024 * 1024 *500) ,
        // 能进来,但是如果申请更大,为什么不走这里面?
        // 因为他已经溢出了,int型数据有一个范围 2的正负32次方
        // 比如 1024 * 1024 * 1024 * 100  就已经溢出了
        // 溢出了就不去申请了
        printf("内存不够,请温柔\n");
    }
    //a[0] = 5;  // 报错,因为是空指针

    printf("%#x", a);
    free(a);     // 释放内存,不能重复释放
    printf("a address: %#x \n",&a);  // a address: 0x59fb68 ,所以要 =NULL
    a = NULL;
    // 动态申请的内存一定要收到释放
    //  free(*p)
    //  原则:不能重复释放
    //  必须赋值NULL (a 内存释放了,但是指针还是存在的,如果不进行a=NULL,a就是一个野指针)
    // if(a!=NULL){ ... } java GC 虽然标记为释放,但是并没有 及时的释放,所有很多OOM
    //  申请和释放一一对应,(使用一次,释放一次)
    // ===================================================================

    //int *b = (int*)calloc(4, 100 * sizeof(int));
    //if (b == NULL){
    //  printf("内存不够,请温柔\n");
    //}
    //printf("%#x", b);
    // void* calloc(size_t _Count,size_t _Size) 
    // 申请 _Count 个 大小为_Size 的连续空间,这个连续空间的大小是_Size,
    // 而不是 _Count * size, 同时,它会初始化为0
    // 如果申请失败,返回值是NULL


    system("pause");
    return 0;
}

3. 字符串

// C 语言没有String
// C 语言 用 char* 或char ch[10]表示String
// C 里面,把所有 用 双引号 引起来的 都是放在常量区的,约定俗成的
int main(){

    char ch1[10] = { 'c', 'h','i','n','a'};
    printf("%s\n", ch1);
    // 在printf里面如果占位符是%s的话,它回去接收一个字符串的首地址
    // 从这个地址里面获取所有的字符串,获取到\0 为止,所以在这个字符串
    // 的最后面会有一个 \0 这个是系统自动加上的空格,以这个空格为结束
    // 如下面的代码 ch2
    char ch2[10] = { 'c', 'h', 'i', 'n', 'a','\0' };
    printf("%s\n", ch2);

    //char ch1[10] = { 'c', 'h','i','n','a','\0','a'}; // 这边打印的 是 china
    //char ch1[] = { 'c', 'h','i','n','a'};  // 这边打印的 是  china加上一些乱码
    //char ch1[] = { 'c', 'h','i','n','a','\0' };  // 这种事正常的 打印china

    // =================================================================================

    // 为什么这样子可以?
    // ch3 是常量 ,在这个常量里面他可以存储20个字节的char类型数据
    // c语言会把 “china” 这个内存中的内容copy给 ch1 常量所指的空间, 所以我们可以修改ch3[0]的内容
    // ch3 是不能被赋值的,因为他是常量,存的是一个地址
    char ch3[20] = "china";
    // char a;
    // ch3 = a;// 报错
    ch3[0] = 's';
    printf("%s\n", ch3);

    // =================================================================================

    char * ch = "zeking";
    // ch[2] = 'f'; // 不能修改 ch[2],报错。为什么?
    // 因为 ch是一个指针名, zeking是一个常量,当我们赋值给 指针变量的时候
    // 这个指针并没有定义空间来存储字符串,所以 编译器就将zeking放到了常量区
    // 然后将常量区的首地址赋给了ch,所以ch指向的是一个常量区的地址
    // 常量区是不能修改的!所以报错
    printf("%#x\n", ch);
    printf("%s\n", ch);

    // ===================================================================================

    char * che = (char *)malloc(100 * sizeof(char)); //让che指向一个非常量区
    che = "zeking";
    //che[2] = 'f'; // 这边还是报错,为什么,因为 把常量区的地址赋给了 che,还存在内存泄漏
    // 怎么不内存泄漏呢。在 che = "zeking" 之前 写 free(che); 和 che=NULL;
    // ===================================================================================

    // 正确的做法
    char * che1 = (char *)malloc(100 * sizeof(char));
    strcpy(che1, "china"); // 将china常量的内容一一赋值给che1,所以che1还是指向他申请的那片空间
    che1[2] = 'f';
    printf("%#x\n", che1);
    printf("%s\n", che1);

    // ===================================================================================



    system("pause");
    return 0;
}

4. 字符串 案例

char* item32(char * str, char *charSet) {

    int hash[256];
    if (NULL == charSet)
        return str;
    for (int i = 0; i < 256; i++)
        hash[i] = 0;
    for (int i = 0; i < strlen(charSet); i++)
        hash[charSet[i]] = 1;
    int currentIndex = 0;
    for (int i = 0; i < strlen(str); i++)
    {
        if (!hash[str[i]])
            str[currentIndex++] = str[i]; // 这边相当于对 c1 进行了修改,他是常量
    }
    str[currentIndex] = '\0';
    return str;

}


void main() {
    printf("hello \n");

    //char *c1 = "abcbd";  // 这样是会报错的,形参地址指向的是常量区

    // 解决方法1
    //char c1[] = "abcbd";  // c1 地址是 stack栈区,保存的是abcbd 字符,自动分配空间,在栈,自动释放
    // 解决方法2
    char * c1 = (char *)malloc(sizeof(char)* 20);
    strcpy(c1, "abcbd");


    // char *c1 = "fefe";
    char *c2 = "b";
    char * s = item32(c1, c2);
    printf("%s", s);
    system("pause");
}

5. 字符串api

1. stpcpy :拷贝一个字符串到另一个

函数名: stpcpy
功 能: 拷贝一个字符串到另一个
用 法: char *stpcpy(char *destin, char *source);
程序例:


#include <stdio.h> 
#include <string.h> 
int main(void) 
{ 
   char string[10]; 
   char *str1 = "abcdefghi"; 
   stpcpy(string, str1); 
   printf("%sn", string); 
   return 0; 
} 

2. strcat :字符串拼接函数

函数名: strcat
功 能: 字符串拼接函数
用 法: char *strcat(char *destin, char *source);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char destination[25]; 
   char *blank = " ", *c = "C++", *Borland = "Borland"; 
   strcpy(destination, Borland); 
   strcat(destination, blank); 
   strcat(destination, c); 
   printf("%sn", destination); 
   return 0; 
} 

3. strchr :在一个串中查找给定字符的第一个匹配之处

函数名: strchr
功 能: 在一个串中查找给定字符的第一个匹配之处
用 法: char *strchr(char *str, char c);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
 { 
    char string[15]; 
    char *ptr, c = 'r'; 
    strcpy(string, "This is a string"); 
    ptr = strchr(string, c); 
    if (ptr) 
       printf("The character %c is at position: %dn", c, ptr-string); 
    else 
       printf("The character was not foundn"); 
    return 0; 
 } 

4. strcmp : 串比较

函数名: strcmp
功 能: 串比较
用 法: int strcmp(char *str1, char *str2);
看Asic码,str1>str2,返回值 > 0;两串相等,返回0
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
 { 
    char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc"; 
    int ptr; 
    ptr = strcmp(buf2, buf1); 
    if (ptr > 0) 
       printf("buffer 2 is greater than buffer 1n"); 
    else 
       printf("buffer 2 is less than buffer 1n"); 
    ptr = strcmp(buf2, buf3); 
    if (ptr > 0) 
       printf("buffer 2 is greater than buffer 3n"); 
    else 
       printf("buffer 2 is less than buffer 3n"); 
    return 0; 
 } 

5. strncmpi :将一个串中的一部分与另一个串比较, 不管大小写

函数名: strncmpi
功 能: 将一个串中的一部分与另一个串比较, 不管大小写
用 法: int strncmpi(char *str1, char *str2, unsigned maxlen);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char *buf1 = "BBB", *buf2 = "bbb"; 
   int ptr; 
   ptr = strcmpi(buf2, buf1); 
   if (ptr > 0) 
      printf("buffer 2 is greater than buffer 1n"); 
   if (ptr < 0) 
      printf("buffer 2 is less than buffer 1n"); 
   if (ptr == 0) 
      printf("buffer 2 equals buffer 1n"); 
   return 0; 
} 

6. strcpy :串拷贝

函数名: strcpy
功 能: 串拷贝
用 法: char *strcpy(char *str1, char *str2);
程序例:

#include <stdio.h> 
#include <string.h> 
int main(void) 
 { 
    char string[10]; 
    char *str1 = "abcdefghi"; 
    strcpy(string, str1); 
    printf("%sn", string); 
    return 0; 
 } 

7. strcspn :在串中查找第一个给定字符集内容的段

函数名: strcspn
功 能: 在串中查找第一个给定字符集内容的段
用 法: int strcspn(char *str1, char *str2);
程序例:

#include <stdio.h> 
#include <string.h> 
#include <alloc.h> 
int main(void) 
 { 
    char *string1 = "1234567890"; 
    char *string2 = "747DC8"; 
    int length; 
    length = strcspn(string1, string2); 
    printf("Character where strings intersect is at position %dn", length); 
    return 0; 
 } 

8. strdup :将串拷贝到新建的位置处

函数名: strdup
功 能: 将串拷贝到新建的位置处
用 法: char *strdup(char *str);
程序例:

#include <stdio.h> 
#include <string.h> 
#include <alloc.h> 
int main(void) 
 { 
    char *dup_str, *string = "abcde"; 
    dup_str = strdup(string); 
    printf("%sn", dup_str); 
    free(dup_str); 
    return 0; 
 } 

9. stricmp : 以大小写不敏感方式比较两个串

函数名: stricmp
功 能: 以大小写不敏感方式比较两个串
用 法: int stricmp(char *str1, char *str2);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char *buf1 = "BBB", *buf2 = "bbb"; 
   int ptr; 
   ptr = stricmp(buf2, buf1); 
   if (ptr > 0) 
      printf("buffer 2 is greater than buffer 1n"); 
   if (ptr < 0) 
      printf("buffer 2 is less than buffer 1n"); 
   if (ptr == 0) 
      printf("buffer 2 equals buffer 1n"); 
   return 0; 
} 

10. strerror :返回指向错误信息字符串的指针

函数名: strerror
功 能: 返回指向错误信息字符串的指针
用 法: char *strerror(int errnum);
程序例:

#include <stdio.h> 
#include <errno.h> 
int main(void) 
{ 
   char *buffer; 
   buffer = strerror(errno); 
   printf("Error: %sn", buffer); 
   return 0; 
} 

11. strcmpi :将一个串与另一个比较, 不管大小写

函数名: strcmpi
功 能: 将一个串与另一个比较, 不管大小写
用 法: int strcmpi(char *str1, char *str2);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char *buf1 = "BBB", *buf2 = "bbb"; 
   int ptr; 
   ptr = strcmpi(buf2, buf1); 
   if (ptr > 0) 
      printf("buffer 2 is greater than buffer 1n"); 
   if (ptr < 0) 
      printf("buffer 2 is less than buffer 1n"); 
   if (ptr == 0) 
      printf("buffer 2 equals buffer 1n"); 
   return 0; 
} 

12. strncmp :串比较

函数名: strncmp
功 能: 串比较
用 法: int strncmp(char *str1, char *str2, int maxlen);
程序例:

#include <string.h> 
#include <stdio.h> 
int  main(void) 
{ 
   char *buf1 = "aaabbb", *buf2 = "bbbccc", *buf3 = "ccc"; 
   int ptr; 
   ptr = strncmp(buf2,buf1,3); 
   if (ptr > 0) 
      printf("buffer 2 is greater than buffer 1n"); 
   else 
      printf("buffer 2 is less than buffer 1n"); 
   ptr = strncmp(buf2,buf3,3); 
   if (ptr > 0) 
      printf("buffer 2 is greater than buffer 3n"); 
   else 
      printf("buffer 2 is less than buffer 3n"); 
   return(0); 
} 

13. strncmpi :把串中的一部分与另一串中的一部分比较, 不管大小写

函数名: strncmpi
功 能: 把串中的一部分与另一串中的一部分比较, 不管大小写
用 法: int strncmpi(char *str1, char *str2);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char *buf1 = "BBBccc", *buf2 = "bbbccc"; 
   int ptr; 
   ptr = strncmpi(buf2,buf1,3); 
   if (ptr > 0) 
      printf("buffer 2 is greater than buffer 1n"); 
   if (ptr < 0) 
      printf("buffer 2 is less than buffer 1n"); 
   if (ptr == 0) 
      printf("buffer 2 equals buffer 1n"); 
   return 0; 
} 

14. strncpy : 串拷贝

函数名: strncpy
功 能: 串拷贝
用 法: char *strncpy(char *destin, char *source, int maxlen);
程序例:

#include <stdio.h> 
#include <string.h> 
int main(void) 
{ 
   char string[10]; 
   char *str1 = "abcdefghi"; 
   strncpy(string, str1, 3); 
   string[3] = ''; 
   printf("%sn", string); 
   return 0; 
} 

15. strnicmp :不注重大小写地比较两个串

函数名: strnicmp
功 能: 不注重大小写地比较两个串
用 法: int strnicmp(char *str1, char *str2, unsigned maxlen);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char *buf1 = "BBBccc", *buf2 = "bbbccc"; 
   int ptr; 
   ptr = strnicmp(buf2, buf1, 3); 
   if (ptr > 0) 
      printf("buffer 2 is greater than buffer 1n"); 
   if (ptr < 0) 
      printf("buffer 2 is less than buffer 1n"); 
   if (ptr == 0) 
      printf("buffer 2 equals buffer 1n"); 
   return 0; 
} 

16. strnset :将一个串中的所有字符都设为指定字符

函数名: strnset
功 能: 将一个串中的所有字符都设为指定字符
用 法: char *strnset(char *str, char ch, unsigned n);
程序例:

#include <stdio.h> 
#include <string.h> 
int main(void) 
{ 
   char *string = "abcdefghijklmnopqrstuvwxyz"; 
   char letter = 'x'; 
   printf("string before strnset: %sn", string); 
   strnset(string, letter, 13); 
   printf("string after  strnset: %sn", string); 
   return 0; 
} 

17. strpbrk :在串中查找给定字符集中的字符

函数名: strpbrk
功 能: 在串中查找给定字符集中的字符
用 法: char *strpbrk(char *str1, char *str2);
程序例:

#include <stdio.h> 
#include <string.h> 
int main(void) 
{ 
   char *string1 = "abcdefghijklmnopqrstuvwxyz"; 
   char *string2 = "onm"; 
   char *ptr; 
   ptr = strpbrk(string1, string2); 
   if (ptr) 
      printf("strpbrk found first character: %cn", *ptr); 
   else 
      printf("strpbrk didn't find character in setn"); 
   return 0; 
} 

18. strrchr :在串中查找指定字符的最后一个出现

函数名: strrchr
功 能: 在串中查找指定字符的最后一个出现
用 法: char *strrchr(char *str, char c);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char string[15]; 
   char *ptr, c = 'r'; 
   strcpy(string, "This is a string"); 
   ptr = strrchr(string, c); 
   if (ptr) 
      printf("The character %c is at position: %dn", c, ptr-string); 
   else 
      printf("The character was not foundn"); 
   return 0; 
} 

19. strrev :串倒转

函数名: strrev
功 能: 串倒转
用 法: char *strrev(char *str);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char *forward = "string"; 
   printf("Before strrev(): %sn", forward); 
   strrev(forward); 
   printf("After strrev():  %sn", forward); 
   return 0; 
} 

20. strset :将一个串中的所有字符都设为指定字符

函数名: strset
功 能: 将一个串中的所有字符都设为指定字符
用 法: char *strset(char *str, char c);
程序例:

#include <stdio.h> 
#include <string.h> 
int main(void) 
{ 
   char string[10] = "123456789"; 
   char symbol = 'c'; 
   printf("Before strset(): %sn", string); 
   strset(string, symbol); 
   printf("After strset():  %sn", string); 
   return 0; 
} 

21. strspn :在串中查找指定字符集的子集的第一次出现

函数名: strspn
功 能: 在串中查找指定字符集的子集的第一次出现
用 法: int strspn(char *str1, char *str2);
程序例:

#include <stdio.h> 
#include <string.h> 
#include <alloc.h> 
int main(void) 
{ 
   char *string1 = "1234567890"; 
   char *string2 = "123DC8"; 
   int length; 
   length = strspn(string1, string2); 
   printf("Character where strings differ is at position %dn", length); 
   return 0; 
} 

22. strstr :在串中查找指定字符串的第一次出现

函数名: strstr
功 能: 在串中查找指定字符串的第一次出现
用 法: char *strstr(char *str1, char *str2);
程序例:

#include <stdio.h> 
#include <string.h> 
int main(void) 
{ 
   char *str1 = "Borland International", *str2 = "nation", *ptr; 
   ptr = strstr(str1, str2); 
   printf("The substring is: %sn", ptr); 
   return 0; 
} 

23. strtod :将字符串转换为double型值

函数名: strtod
功 能: 将字符串转换为double型值
用 法: double strtod(char *str, char **endptr);
程序例:

#include <stdio.h> 
#include <stdlib.h> 
int main(void) 
{ 
   char input[80], *endptr; 
   double value; 
   printf("Enter a floating point number:"); 
   gets(input); 
   value = strtod(input, &endptr); 
   printf("The string is %s the number is %lfn", input, value); 
   return 0; 
} 

24. strtok :查找由在第二个串中指定的分界符分隔开的单词

函数名: strtok
功 能: 查找由在第二个串中指定的分界符分隔开的单词
用 法: char *strtok(char *str1, char *str2);
程序例:

#include <string.h> 
#include <stdio.h> 
int main(void) 
{ 
   char input[16] = "abc,d"; 
   char *p; 
   /* strtok places a NULL terminator 
   in front of the token, if found */ 
   p = strtok(input, ","); 
   if (p)   printf("%sn", p); 
   /* A second call to strtok using a NULL 
   as the first parameter returns a pointer 
   to the character following the token  */ 
   p = strtok(NULL, ","); 
   if (p)   printf("%sn", p); 
   return 0; 
} 

25. strtol :将串转换为长整数

函数名: strtol
功 能: 将串转换为长整数
用 法: long strtol(char *str, char **endptr, int base);
程序例:

#include <stdlib.h> 
#include <stdio.h> 
int main(void) 
{ 
   char *string = "87654321", *endptr; 
   long lnumber; 
   /* strtol converts string to long integer  */ 
   lnumber = strtol(string, &endptr, 10); 
   printf("string = %s  long = %ldn", string, lnumber); 
   return 0; 
} 

26. strupr :将串中的小写字母转换为大写字母

函数名: strupr
功 能: 将串中的小写字母转换为大写字母
用 法: char *strupr(char *str);
程序例:

#include <stdio.h> 
#include <string.h> 
int main(void) 
{ 
   char *string = "abcdefghijklmnopqrstuvwxyz", *ptr; 
   /* converts string to upper case characters */ 
   ptr = strupr(string); 
   printf("%sn", ptr); 
   return 0; 
} 

27. swab :交换字节

函数名: swab
功 能: 交换字节
用 法: void swab (char *from, char *to, int nbytes);
程序例:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
char source[15] = "rFna koBlrna d"; 
char target[15]; 
int main(void) 
{ 
   swab(source, target, strlen(source)); 
   printf("This is target: %sn", target); 
   return 0; 
}

PS:isalpha()是字符函数,不是字符串函数,

isalpha

原型:extern int isalpha(int c);

用法:#include

  // isalpha.c
  #include <syslib.h>
  #include <ctype.h>
  #include <stdio.h>

  main()
  {
    int c;

    clrscr();        // clear screen
    printf("Press a key");
    for(;;)
    {
      c=getchar();
      clrscr();
      printf("%c: %s letter",c,isalpha(c)?"is":"not");
    }
    return 0; // just to avoid warnings by compiler
  }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值