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

系列文章目录

第一章 C语言基础知识

第二章 C语言控制语句

第三章 C语言函数详解

第四章 C语言数组详解

第五章 C语言操作符详解

第六章 C语言指针详解

第七章 C语言结构体详解

第八章 详解数据在内存中的存储

第九章 C语言指针进阶

第十章 C语言结构体,枚举,联合

文章目录

1. 概念

2. 函数

2.1 strlen

功能描述

为什么需要以 null 字符结束?

代码示例

2.2 strcpy

2.3 strncpy 

 2.4 strcmp

2.5 strcat

2.6 strncat

2.7 strncmp

 2.8 strstr

2.9 strtok

2.10 strerror

2.11 memcpy

2.12 memmove

2.13 memcmp

3. 函数总结

 4. 模拟实现库函数


1. 概念

在C语言中,字符函数和字符串函数是用来处理单个字符和字符数组(通常作为字符串处理)的标准库函数。这些函数有各种功能,如字符检查(例如是否为字母、数字等)、转换(大写、小写转换)以及字符串的操作(比较、复制、连接等)。这些函数大多定义在 <ctype.h> 和 <string.h> 头文件中。

2. 函数

2.1 strlen

strlen 是一个标准库函数,定义在 <string.h> 头文件中。该函数用于计算给定的以 null 结尾的字符串的长度,不包括结尾的 null 字符('\0')。这意味着 strlen 返回的是字符串中字符的数量,直到第一个 null 字符为止。

size_t strlen(const char *s);
  • 参数s 是指向字符数组(字符串)的指针,该数组应以 null 字符终止。
  • 返回值:返回类型为 size_t,表示字符串的长度。size_t 是一个无符号整数类型,足以表示任何数组的大小。
功能描述

strlen 函数通过遍历字符串,从首地址开始计数,直到遇到第一个 null 字符,然后返回计数值。该函数不计入结尾的 null 字符。

为什么需要以 null 字符结束?

在 C 语言中,字符串是以 null 字符结束的,这句话描述了 C 语言中字符串的一个基本约定:字符串总是以一个特殊的字符 \0 (null 字符,ASCII 码为 0)结尾。这个约定允许程序确定字符串的结束位置,即使不知道字符串的实际长度。

char str[] = "Hello";

这个数组在内存中的存储实际上是这样的:

'H' 'e' 'l' 'l' 'o' '\0'

当你手动创建一个字符数组用作字符串时,你必须确保自己在字符串的末尾添加了 null 字符。例如:

char str[6];
str[0] = 'H';
str[1] = 'e';
str[2] = 'l';
str[3] = 'l';
str[4] = 'o';
str[5] = '\0';  // 明确地添加 null 字符
代码示例
#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "Hello, world!";
    char str2[] = "";

    // 获取并打印字符串str1的长度
    size_t len1 = strlen(str1);
    printf("The length of '%s' is %zu.\n", str1, len1);

    // 获取并打印字符串str2的长度
    size_t len2 = strlen(str2);
    printf("The length of an empty string is %zu.\n", len2);

    return 0;
}

输出结果:

The length of 'Hello, world!' is 13.
The length of an empty string is 0.

 

2.2 strcpy

char *strcpy(char *dest, const char *src);
  • dest:目标字符串数组的指针,用于接收复制的内容。
  • src:源字符串的常量指针,即要复制的字符串。
  • 返回指向目标字符串 dest 的指针。

功能描述

strcpy 函数将 src 字符串(包括终止的 null 字符 \0)复制到 dest 指向的位置。复制会一直进行,直到包括 src 中的终止 null 字符为止,因此 dest 必须有足够的空间来存储整个 src 字符串。

使用注意

使用 strcpy 时需要格外注意,因为它不会检查目标缓冲区的大小。如果 dest 缓冲区不够大,无法容纳 src 的全部内容,就会发生缓冲区溢出,可能导致数据损坏和程序崩溃。为了避免这种风险,建议使用更安全的字符串操作函数,如 strncpy,或在较新的代码中使用边界检查的函数版本,如 strcpy_s(在支持它的编译器中)。

示例代码:

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, world!";
    char dest[50];  // 确保有足够的空间

    strcpy(dest, src);

    printf("Copied string: %s\n", dest);
    return 0;
}

这段代码首先定义了一个源字符串 src,然后定义了一个足够大的目标字符串数组 dest。使用 strcpy 将 src 复制到 dest 中,然后打印出 dest。 

2.3 strncpy 

char *strncpy(char *dest, const char *src, size_t n);
  • dest:目标字符串数组的指针。这个数组应有足够的空间至少包含 n 个字符。
  • src:源字符串的常量指针。
  • n:要从源字符串复制的最大字符数。
  • 返回指向目标字符串 dest 的指针。

功能描述

strncpy 函数从 src 字符串复制最多 n 个字符到 dest 字符串。如果 src 的长度小于 n,函数将复制 src 中的字符,然后添加足够的 null 字符(\0)到 dest 中,直到总共复制了 n 个字符。如果 src 的长度大于或等于 n,则复制前 n 个字符而不自动添加 null 字符到 dest 的末尾。

代码示例:

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, world!";
    char dest[20];

    // 使用 strncpy 复制 5 个字符
    strncpy(dest, src, 5);
    dest[5] = '\0';  // 显式添加 null 字符

    printf("Copied string: %s\n", dest);  // 输出 "Hello"
    return 0;
}

 

 2.4 strcmp

int strcmp(const char *s1, const char *s2);
  • s1:指向第一个要比较的 null 终止 C 字符串的指针。
  • s2:指向第二个要比较的 null 终止 C 字符串的指针。
  • 如果返回值 < 0,则表示 s1 小于 s2
  • 如果返回值 > 0,则表示 s1 大于 s2
  • 如果返回值 = 0,则表示 s1s2 相等。

功能描述

strcmp 函数比较两个字符串 s1s2。比较是基于每个字符的无符号字符值(通常是 ASCII 值)逐个进行的。一旦发现两个字符串中的字符不同,或者检测到字符串的结束符(null 字符 '\0'),比较就会停止。

这种比较方式意味着比较结果是字典顺序的,即基于字符的数值。例如,字母 'a' 的 ASCII 值是 97,而 'b' 是 98,因此 "a" 小于 "b"。

示例代码

#include <stdio.h>
#include <string.h>

int main() {
    char *str1 = "Hello, World!";
    char *str2 = "Hello, world!";

    int result = strcmp(str1, str2);

    if (result < 0) {
        printf("'%s' is less than '%s'\n", str1, str2);
    } else if (result > 0) {
        printf("'%s' is greater than '%s'\n", str1, str2);
    } else {
        printf("'%s' is equal to '%s'\n", str1, str2);
    }

    return 0;
}

在这个例子中,因为字符串 str1 和 str2 在第 7 个字符处不同(大写的 'W' 与小写的 'w'),并且 'W' 的 ASCII 值小于 'w' 的 ASCII 值,所以 strcmp 将返回一个小于 0 的值,表示 str1 小于 str2。

2.5 strcat

char *strcat(char *dest, const char *src);
  • dest:目标字符串的指针,用于接收追加的字符串。必须有足够的空间来容纳追加后的结果,包括追加的字符串 src 和终止的 null 字符。
  • src:源字符串的指针,这个字符串会被追加到 dest 的末尾。
  • 返回指向目标字符串 dest 的指针。

功能描述

strcat 函数将 src 字符串追加到 dest 字符串的末尾。操作的方式是,首先在 dest 中找到终止的 null 字符(\0),然后从这个位置开始,将 src 中的字符逐个复制到 dest 中,包括 src 的终止 null 字符。这样操作后,dest 和 src 原来的内容将被合并,dest 成为新的、更长的字符串。

使用注意

使用 strcat 时需要确保 dest 数组有足够的空间来存储追加后的结果。如果 dest 的空间不足以容纳原来的 dest 加上 src 的内容,这将导致缓冲区溢出,可能引起程序崩溃或数据损坏。

示例代码

#include <stdio.h>
#include <string.h>

int main() {
    char dest[50] = "Hello";
    char src[] = ", world!";

    // 使用 strcat 追加字符串
    strcat(dest, src);

    printf("Concatenated string: %s\n", dest);  // 输出 "Hello, world!"
    return 0;
}

 

2.6 strncat

char *strncat(char *dest, const char *src, size_t n);
  • dest:目标字符串的指针,用于接收追加的字符串。它必须指向一个足够大的缓冲区,这个缓冲区能够存储追加后的字符串和终止的 null 字符。
  • src:源字符串的指针,将被追加到 dest 的末尾。
  • n:最大复制字符数,指从 src 复制到 dest 的最大字符数,不包括自动追加的 null 字符。
  • 返回指向目标字符串 dest 的指针。

功能描述

strncat 函数从 src 开始复制字符到 dest 字符串的结尾(从 dest 的首个 null 字符开始)。它会复制字符直到复制了 n 个字符或者遇到 src 的结束 null 字符。不论是哪种情况发生,strncat 总是在最后添加一个 null 字符来终止 dest 字符串。

这意味着如果 src 的长度小于或等于 n,则 src 的全部内容都将被追加到 dest;如果 src 的长度大于 n,则只有其前 n 个字符被追加。

使用注意

  • dest 必须有足够的空间来存储追加的字符和终止的 null 字符。
  • 不要忽视 n 的设置,适当的 n 值能防止缓冲区溢出。

示例代码

//strncat 追加了最多 7 个字符从 src 到 dest。
//即使 src 的实际长度超过了 7,函数仍然确保了不会超出指定的字符数,保护了 dest 的缓冲区不被溢出。
#include <stdio.h>
#include <string.h>

int main() {
    char dest[20] = "Hello";
    char src[] = ", world!";

    // 使用 strncat 追加部分字符串,防止溢出
    strncat(dest, src, 7);  // 只追加 ", world",注意包括空格和逗号

    printf("Concatenated string: %s\n", dest);  // 输出 "Hello, world"
    return 0;
}

2.7 strncmp

int strncmp(const char *s1, const char *s2, size_t n);
  • s1:指向第一个要比较的字符串的指针。
  • s2:指向第二个要比较的字符串的指针。
  • n:要比较的最大字符数。
  • 如果两个字符串的前 n 个字符完全相同,则返回 0。
  • 如果根据字典顺序 s1 小于 s2,返回一个小于 0 的值。
  • 如果根据字典顺序 s1 大于 s2,返回一个大于 0 的值。

功能描述

strncmp 函数比较来自 s1 和 s2 的最多 n 个字符。比较是基于每个字符的无符号数值(通常是 ASCII 值)进行的。如果在比较达到 n 个字符之前,任一字符串的结束 null 字符被遇到,比较停止。这意味着,如果字符串中包含 null 字符或其长度小于 n,则比较可能提前结束。

使用注意

  1. 确保安全:虽然 strncmp 通过限制比较的字符数增加了安全性,使用它时仍应确保字符串至少有 n 个字符长,或者你接受比较可能因为提前遇到 null 字符而结束。
  2. 处理结果:和 strcmp 一样,strncmp 的返回结果需要正确理解和使用,特别是在条件判断中。

示例代码

#include <stdio.h>
#include <string.h>

int main() {
    const char *str1 = "Hello, world!";
    const char *str2 = "Hello, there!";

    // 比较前 7 个字符
    int result = strncmp(str1, str2, 7);

    if (result == 0) {
        printf("The first 7 characters of both strings are the same.\n");
    } else if (result < 0) {
        printf("The first string is less than the second in the first 7 characters.\n");
    } else {
        printf("The first string is greater than the second in the first 7 characters.\n");
    }

    return 0;
}

输出结果:

The first 7 characters of both strings are the same.
尽管两个字符串在整体上不同,strncmp 只比较前 7 个字符,在这个范围内,两个字符串相同。


 2.8 strstr

char *strstr(const char *haystack, const char *needle);
  • haystack:要搜索的主字符串。
  • needle:要查找的子字符串。
  • 如果找到 needle,则返回一个指向 haystack 中第一次出现 needle 的位置的指针。
  • 如果没有找到 needle,则返回 NULL。

功能描述

strstr 函数搜索 needle 子串的第一次出现在 haystack 字符串中的位置。搜索不区分大小写,是从左向右进行。如果 needle 是一个空字符串,strstr 会返回 haystack 的地址,因为空字符串被视为存在于任何字符串的开头。

使用注意

  1. 空字符串的处理:如果 needle 是空字符串,函数返回 haystack 的起始地址。这是逻辑上的处理,因为空字符串在任何位置都能匹配。
  2. 返回值:如果找到 needle,可以通过返回的指针对 haystack 进行操作,例如提取子串后面的部分。如果 needle 不存在于 haystack 中,返回 NULL,任何尝试访问此返回值的操作都应进行空指针检查。

示例代码

#include <stdio.h>
#include <string.h>

int main() {
    const char *text = "Here is a simple example.";
    const char *substr = "simple";

    // 查找子串
    char *result = strstr(text, substr);
    if (result != NULL) {
        printf("Found: '%s'\n", substr);
        printf("Rest of the string after '%s': '%s'\n", substr, result + strlen(substr));
    } else {
        printf("Substring not found.\n");
    }

    return 0;
}

输出结果:

Found: 'simple'
Rest of the string after 'simple': ' example.'

 

2.9 strtok

char *strtok(char *str, const char *delim);
  • str:要被解析的字符串,第一次调用时传入字符串的指针,后续调用传入 NULL。
  • delim:作为分隔符的字符集,任何包含在此字符串中的字符都被视为一个分隔符。
  • 返回下一个标记的指针。
  • 如果没有更多的标记,则返回 NULL。

功能描述

strtok 在 str 指定的字符串中查找由 delim 指定的分隔符。当它找到一个分隔符时,它会将其替换为 \0(null 字符)并返回前一个标记的开始位置。在连续的调用中,应将 str 参数设置为 NULL,以指示函数继续处理上次调用时剩余的字符串。

由于 strtok 会修改输入字符串(通过替换分隔符为 \0),它并不是线程安全的。在多线程程序中,应考虑使用 strtok_r(在 POSIX 系统中可用),它是 strtok 的线程安全版本。

使用注意

  • 非线程安全strtok 修改原始字符串,并使用一个静态缓冲区来存储函数的状态,因此它不是线程安全的。
  • 修改输入字符串strtok 通过在分隔符位置插入 null 字符来“破坏”原始字符串。
  • 多次调用:对于同一字符串的多次调用,除了第一次外,str 应为 NULL

示例代码

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, world! Welcome to C programming.";
    const char *delim = " ,.!";  // 包含了空格和几个标点符号作为分隔符

    // 获取第一个标记
    char *token = strtok(str, delim);
    
    // 继续获取其他的标记
    while (token != NULL) {
        printf("%s\n", token);
        token = strtok(NULL, delim);
    }

    return 0;
}

输出结果:

Hello
world
Welcome
to
C
programming

 

2.10 strerror

char *strerror(int errnum);
  • errnum:错误编号,通常是 errno 变量的值。
  • 返回一个指向错误消息字符串的指针,该字符串描述了参数 errnum 指定的错误。

功能描述

strerror 函数根据给定的错误编号返回一个指向描述该错误的字符串的指针。这些错误消息是静态分配的,不应由程序修改或释放。每个错误编号对应一个特定的错误情况,例如文件访问问题、内存分配失败等。

使用注意

  1. 线程安全:标准的 strerror 函数不是线程安全的,因为它返回一个指向静态数据的指针,可能在多线程环境下由另一个线程覆盖。为了解决这个问题,POSIX 提供了 strerror_r 函数,这是一个线程安全版本的 strerror。

  2. 局限性:由于 strerror 返回的是静态数据的指针,其内容可能在下一次调用 strerror 或 strerror_r 时被覆盖。

字符分类函数:
函数
如果他的参数符合下列条件就返回真
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
任何可打印字符,包括图形字符和空白字符

示例代码

#include <stdio.h>
#include <string.h>
#include <errno.h>

int main() {
    // 故意造成一个错误,比如尝试打开一个不存在的文件
    FILE *fp = fopen("nonexistentfile.txt", "r");
    if (fp == NULL) {
        int err = errno;  // 获取错误编号
        printf("Error opening file: %s\n", strerror(err));
    } else {
        fclose(fp);
    }

    return 0;
}

在这个例子中,尝试打开一个不存在的文件将导致 fopen 返回 NULL 并设置 errno。然后使用 strerror 函数来获取并打印错误消息。

输出:

Error opening file: No such file or directory

2.11 memcpy

void *memcpy(void *dest, const void *src, size_t n);
  • dest:目标内存地址的指针,到哪里去复制数据。
  • src:源内存地址的指针,从哪里来复制数据。
  • n:要复制的字节数。
  • 返回指向目标内存地址 dest 的指针。

功能描述

memcpy 函数将 src 指向的内存区域的前 n 个字节复制到 dest 指向的内存区域。这个函数不检查任何终止 null 字符,它只是简单地复制一定数量的字节,因此它非常适合用于任何类型的数据,包括字符数组、整数、结构体、类对象等。

使用注意

重叠问题:如果 src 和 dest 所指向的内存区域重叠,memcpy 的行为是未定义的。在内存区域可能重叠的情况下,应该使用 memmove 函数,memmove 是为处理重叠区域设计的,可以正确地处理源和目标内存区域重叠的情况。

示例代码

//如何使用 memcpy 函数来复制一个结构体数组。
#include <stdio.h>
#include <string.h>

typedef struct {
    char name[40];
    int age;
} Person;

int main() {
    Person people[] = {{"Alice", 30}, {"Bob", 25}};
    Person copy[2];

    // 复制 people 数组到 copy 数组
    memcpy(copy, people, sizeof(people));

    for (int i = 0; i < 2; i++) {
        printf("Name: %s, Age: %d\n", copy[i].name, copy[i].age);
    }

    return 0;
}

输出:

Name: Alice, Age: 30
Name: Bob, Age: 25

 

2.12 memmove

void *memmove(void *dest, const void *src, size_t n);
  • dest:目标内存地址的指针,到哪里去复制数据。
  • src:源内存地址的指针,从哪里来复制数据。
  • n:要复制的字节数。
  • 返回指向目标内存地址 dest 的指针。

功能描述

memmove 函数复制 src 指向的内存区域的前 n 个字节到 dest 指向的内存区域。与 memcpy 不同,memmove 考虑到内存区域可能重叠的情况,它首先判断 src 和 dest 的相对位置,如果有重叠并且 src 在 dest 的前面,则从后往前复制,否则从前往后复制。这样的处理确保了复制过程中源数据不会被覆盖,从而保证数据的正确性。

使用注意

内存重叠:memmove 是专为处理内存重叠设计的。当不确定内存是否重叠或明确知道内存重叠时,应选择 memmove 而不是 memcpy。

示例代码

//如何使用 memmove 在内存重叠时安全地复制数据。
#include <stdio.h>
#include <string.h>

int main() {
    char data[100] = "Hello, world!";
    printf("Original data: %s\n", data);

    // 将数据向右移动5个字节
    memmove(data + 5, data, strlen(data) + 1);

    printf("After memmove: %s\n", data);
    return 0;
}

输出:

Original data: Hello, world!
After memmove: HelloHello, world!
data 数组的内容被安全地向右移动了5个字节。
使用 strlen(data) + 1 来确保包括字符串终止符 \0 在内的所有字符都被复制。

 

2.13 memcmp

int memcmp(const void *s1, const void *s2, size_t n);
  • s1:指向第一个内存块的指针。
  • s2:指向第二个内存块的指针。
  • n:要比较的字节数。
  • 如果两个内存块在前 n 字节内相等,返回 0。
  • 如果不相等,返回值将是两个不相匹配的字节的差值(取决于不相匹配的第一个字节对),具体表现为:
  • 如果 s1 所指内存块的字节值大于 s2 所指的,返回一个大于零的值。
  • 如果 s1 所指的字节值小于 s2 所指的,返回一个小于零的值。

功能描述

memcmp 函数按字节比较两个内存块。它从两块内存的起始位置开始,逐字节进行比较,直到第一个不匹配的字节被发现或比较了 n 字节。这使得 memcmp 非常适合比较任意类型的数据块,不论它们是否包含文本数据。

使用注意

  • 二进制安全memcmp 是二进制安全的,可以用于任何类型的数据,包括包含空字节('\0')的数据。
  • 用途限制:尽管 memcmp 在比较数据方面非常有效,但不用于需要考虑特定编码或文化区别的字符串比较,例如文本字符串的本地化比较。

示例代码

//如何使用 memcmp 来比较两个简单的结构体数组是否相同
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    double balance;
} Account;

int main() {
    Account accounts1[2] = {{1, 100.50}, {2, 150.75}};
    Account accounts2[2] = {{1, 100.50}, {2, 150.75}};
    Account accounts3[2] = {{1, 100.50}, {3, 150.75}};

    // 比较 accounts1 和 accounts2
    if (memcmp(accounts1, accounts2, sizeof(accounts1)) == 0) {
        printf("accounts1 and accounts2 are the same.\n");
    } else {
        printf("accounts1 and accounts2 are different.\n");
    }

    // 比较 accounts1 和 accounts3
    if (memcmp(accounts1, accounts3, sizeof(accounts1)) == 0) {
        printf("accounts1 and accounts3 are the same.\n");
    } else {
        printf("accounts1 and accounts3 are different.\n");
    }

    return 0;
}

输出:

accounts1 and accounts2 are the same.
accounts1 and accounts3 are different.

3. 函数总结

求字符串长度
  • strlen
长度不受限制的字符串函数
  • strcpy
  • strcat
  • strcmp
长度受限制的字符串函数介绍
  • strncpy
  • strncat
  • strncmp
字符串查找
  • strstr
  • strtok
错误信息报告
  • strerror
字符操作
内存操作函数
  • memcpy
  • memmove
  • memset
  • memcmp

 4. 模拟实现库函数

模拟实现strlen,可以更好的理解函数的结构和逻辑

方法一:计数器方式

//使用一个循环遍历字符串,每遍历一个非 null 字符就将计数器增加1。
int my_strlen(const char *str) {
    int count = 0;  // 初始化计数器
    while (*str) {  // 继续循环,直到遇到 null 字符
        count++;    // 对每个非 null 字符增加计数
        str++;      // 移动指针到下一个字符
    }
    return count;  // 返回计数,即字符串的长度
}

方法二:递归方式(不使用临时变量计数器)

int my_strlen(const char *str) {
    if (*str == '\0')  // 基本情况:如果当前字符是 null 字符
        return 0;       // 返回 0,递归结束
    else
        return 1 + my_strlen(str + 1);  // 递归调用,移动到下一个字符,并加一计算长度
}
//递归方法通过每次调用自身来处理字符串的下一个字符,直到遇到字符串的结束符。
//这种方法不使用循环或外部变量,而是利用调用栈来计数。

方法三:指针- 指针的方式

int my_strlen(char *s) {
    char *p = s;  // p 指针用来遍历字符串
    while (*p != '\0') {  // 循环直到 p 指向的字符是 null 字符
        p++;  // 移动 p 到下一个字符
    }
    return p - s;  // 返回两个指针之间的差值,即字符串的长度
}
//利用两个指针来确定字符串的长度。一个指针指向字符串的开始,另一个遍历到字符串的末尾。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

TENET-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值