Basic String Handling Functions

本文详细介绍了C语言中标准字符串处理函数的使用方法,包括复制、比较、连接等基本操作及字符串搜索功能。此外还概述了内存操作函数,如内存复制、移动、设置等。

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

All the string handling functions are prototyped in:

#include <string.h>

The common functions are described below:

char *stpcpy (const char *dest,const char *src) -- Copy one string into another.
int strcmp(const char *string1,const char *string2) - Compare string1 and string2 to determine alphabetic order.
char *strcpy(const char *string1,const char *string2) -- Copy string2 to stringl.
char *strerror(int errnum) -- Get error message corresponding to specified error number.
int strlen(const char *string) -- Determine the length of a string.
char *strncat(const char *string1, char *string2, size_t n) -- Append n characters from string2 to stringl.
int strncmp(const char *string1, char *string2, size_t n) -- Compare first n characters of two strings.
char *strncpy(const char *string1,const char *string2, size_t n) -- Copy first n characters of string2 to stringl .
int strcasecmp(const char *s1, const char *s2) -- case insensitive version of strcmp().
int strncasecmp(const char *s1, const char *s2, int n) -- case insensitive version of strncmp().

The use of most of the functions is straightforward, for example:

 

char *str1 = "HELLO";
char *str2;
int length;

length = strlen("HELLO"); /* length = 5 */
(void) strcpy(str2,str1);

Note that both strcat() and strcopy() both return a copy of their first argument which is the destination array. Note the order of the arguments is destination array followed by source array which is sometimes easy to get the wrong around when programming.

The strcmp() function lexically compares the two input strings and returns:

 

Less than zero
-- if string1 is lexically less than string2
Zero
-- if string1 and string2 are lexically equal
Greater than zero
-- if string1 is lexically greater than string2

This can also confuse beginners and experience programmers forget this too.

The strncat(), strncmp,() and strncpy() copy functions are string restricted version of their more general counterparts. They perform a similar task but only up to the first n characters. Note the the NULL terminated requirement may get violated when using these functions, for example:

 

char *str1 = "HELLO";
char *str2;
int length = 2;


(void) strcpy(str2,str1, length); /* str2 = "HE" */

str2 is NOT NULL TERMINATED!! -- BEWARE

 

String Searching

The library also provides several string searching functions:

char *strchr(const char *string, int c) -- Find first occurrence of character c in string.
char *strrchr(const char *string, int c) -- Find last occurrence of character c in string.
char *strstr(const char *s1, const char *s2) -- locates the first occurrence of the string s2 in string s1.
char *strpbrk(const char *s1, const char *s2) -- returns a pointer to the first occurrence in string s1 of any character from string s2, or a null pointer if no character from s2 exists in s1
size_t strspn(const char *s1, const char *s2) -- returns the number of characters at the begining of s1 that match s2.
size_t strcspn(const char *s1, const char *s2) -- returns the number of characters at the begining of s1 that do not match s2.
char *strtok(char *s1, const char *s2) -- break the string pointed to by s1 into a sequence of tokens, each of which is delimited by one or more characters from the string pointed to by s2.
char *strtok_r(char *s1, const char *s2, char **lasts) -- has the same functionality as strtok() except that a pointer to a string placeholder lasts must be supplied by the caller.

strchr() and strrchr() are the simplest to use, for example:

 

char *str1 = "Hello";
char *ans;

ans = strchr(str1,'l');

After this execution, ans points to the location str1 + 2

strpbrk() is a more general function that searches for the first occurrence of any of a group of characters, for example:

 

char *str1 = "Hello";
char *ans;

ans = strpbrk(str1,'aeiou');

Here, ans points to the location str1 + 1, the location of the first e.

strstr() returns a pointer to the specified search string or a null pointer if the string is not found. If s2 points to a string with zero length (that is, the string ""), the function returns s1. For example,

 

char *str1 = "Hello";
char *ans;

ans = strstr(str1,'lo');

will yield ans = str + 3.

strtok() is a little more complicated in operation. If the first argument is not NULL then the function finds the position of any of the second argument characters. However, the position is remembered and any subsequent calls to strtok() will start from this position if on these subsequent calls the first argument is NULL. For example, If we wish to break up the string str1 at each space and print each token on a new line we could do:

 

char *str1 = "Hello Big Boy";
char *t1;


for ( t1 = strtok(str1," ");
      t1 != NULL;
      t1 = strtok(NULL, " ") )

printf("%s/n",t1);

Here we use the for loop in a non-standard counting fashion:

 

  • The initialisation calls strtok() loads the function with the string str1
  • We terminate when t1 is NULL
  • We keep assigning tokens of str1 to t1 until termination by calling strtok() with a NULL first argument.

    Memory Operations: <memory.h>

    Finally we briefly overview some basic memory operations. Although not strictly string functions the functions are prototyped in #include <string.h>:

    void *memchr (void *s, int c, size_t n) -- Search for a character in a buffer .
    int memcmp (void *s1, void *s2, size_t n) -- Compare two buffers.
    void *memcpy (void *dest, void *src, size_t n) -- Copy one buffer into another .
    void *memmove (void *dest, void *src, size_t n) -- Move a number of bytes from one buffer lo another.
    void *memset (void *s, int c, size_t n) -- Set all bytes of a buffer to a given character.

    Their use is fairly straightforward and not dissimilar to comparable string operations (except the exact length (n) of the operations must be specified as there is no natural termination here).

    Note that in all case to bytes of memory are copied. The sizeof() function comes in handy again here, for example:

     

    char src[SIZE],dest[SIZE];
    int  isrc[SIZE],idest[SIZE];
    
    memcpy(dest,src, SIZE); /* Copy chars (bytes) ok */
    
    memcpy(idest,isrc, SIZE*sizeof(int)); /* Copy arrays of ints */
    

    memmove() behaves in exactly the same way as memcpy() except that the source and destination locations may overlap.

    memcmp() is similar to strcmp() except here unsigned bytes are compared and returns less than zero if s1 is less than s2 etc.

 

 

 

 

一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
//============================================================================== // WARNING!! This file is overwritten by the Block UI Styler while generating // the automation code. Any modifications to this file will be lost after // generating the code again. // // Filename: D:\NXopen\BaiduSyncdisk\studio\hkjm\ui\hkjm.cpp // // This file was generated by the NX Block UI Styler // Created by: MiCH-CEO // Version: NX 12 // Date: 08-06-2025 (Format: mm-dd-yyyy) // Time: 19:18 (Format: hh-mm) // //============================================================================== //============================================================================== // Purpose: This TEMPLATE file contains C++ source to guide you in the // construction of your Block application dialog. The generation of your // dialog file (.dlx extension) is the first step towards dialog construction // within NX. You must now create a NX Open application that // utilizes this file (.dlx). // // The information in this file provides you with the following: // // 1. Help on how to load and display your Block UI Styler dialog in NX // using APIs provided in NXOpen.BlockStyler namespace // 2. The empty callback methods (stubs) associated with your dialog items // have also been placed in this file. These empty methods have been // created simply to start you along with your coding requirements. // The method name, argument list and possible return values have already // been provided for you. //============================================================================== //------------------------------------------------------------------------------ //These includes are needed for the following template code //------------------------------------------------------------------------------ #include "hkjm.hpp" using namespace NXOpen; using namespace NXOpen::BlockStyler; //------------------------------------------------------------------------------ // Initialize static variables //------------------------------------------------------------------------------ Session *(hkjm::theSession) = NULL; UI *(hkjm::theUI) = NULL; //------------------------------------------------------------------------------ // Constructor for NX Styler class //------------------------------------------------------------------------------ hkjm::hkjm() { try { // Initialize the NX Open C++ API environment hkjm::theSession = NXOpen::Session::GetSession(); hkjm::theUI = UI::GetUI(); theDlxFileName = "hkjm.dlx"; theDialog = hkjm::theUI->CreateDialog(theDlxFileName); // Registration of callback functions theDialog->AddApplyHandler(make_callback(this, &hkjm::apply_cb)); theDialog->AddOkHandler(make_callback(this, &hkjm::ok_cb)); theDialog->AddUpdateHandler(make_callback(this, &hkjm::update_cb)); theDialog->AddInitializeHandler(make_callback(this, &hkjm::initialize_cb)); theDialog->AddDialogShownHandler(make_callback(this, &hkjm::dialogShown_cb)); } catch(exception& ex) { //---- Enter your exception handling code here ----- throw; } } //------------------------------------------------------------------------------ // Destructor for NX Styler class //------------------------------------------------------------------------------ hkjm::~hkjm() { if (theDialog != NULL) { delete theDialog; theDialog = NULL; } } //------------------------------- DIALOG LAUNCHING --------------------------------- // // Before invoking this application one needs to open any part/empty part in NX // because of the behavior of the blocks. // // Make sure the dlx file is in one of the following locations: // 1.) From where NX session is launched // 2.) $UGII_USER_DIR/application // 3.) For released applications, using UGII_CUSTOM_DIRECTORY_FILE is highly // recommended. This variable is set to a full directory path to a file // containing a list of root directories for all custom applications. // e.g., UGII_CUSTOM_DIRECTORY_FILE=$UGII_BASE_DIR\ugii\menus\custom_dirs.dat // // You can create the dialog using one of the following way: // // 1. USER EXIT // // 1) Create the Shared Library -- Refer "Block UI Styler programmer's guide" // 2) Invoke the Shared Library through File->Execute->NX Open menu. // //------------------------------------------------------------------------------ extern "C" DllExport void ufusr(char *param, int *retcod, int param_len) { hkjm *thehkjm = NULL; try { UF_initialize(); //开发的许可函数,初始化 thehkjm = new hkjm(); // The following method shows the dialog immediately thehkjm->Show(); } catch(exception& ex) { //---- Enter your exception handling code here ----- hkjm::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } if(thehkjm != NULL) { delete thehkjm; thehkjm = NULL; }UF_terminate(); //释放许可函数,结束化 } //------------------------------------------------------------------------------ // This method specifies how a shared image is unloaded from memory // within NX. This method gives you the capability to unload an // internal NX Open application or user exit from NX. Specify any // one of the three constants as a return value to determine the type // of unload to perform: // // // Immediately : unload the library as soon as the automation program has completed // Explicitly : unload the library from the "Unload Shared Image" dialog // AtTermination : unload the library when the NX session terminates // // // NOTE: A program which associates NX Open applications with the menubar // MUST NOT use this option since it will UNLOAD your NX Open application image // from the menubar. //------------------------------------------------------------------------------ extern "C" DllExport int ufusr_ask_unload() { //return (int)Session::LibraryUnloadOptionExplicitly; return (int)Session::LibraryUnloadOptionImmediately; //return (int)Session::LibraryUnloadOptionAtTermination; } //------------------------------------------------------------------------------ // Following method cleanup any housekeeping chores that may be needed. // This method is automatically called by NX. //------------------------------------------------------------------------------ extern "C" DllExport void ufusr_cleanup(void) { try { //---- Enter your callback code here ----- } catch(exception& ex) { //---- Enter your exception handling code here ----- hkjm::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } int hkjm::Show() { try { theDialog->Show(); } catch(exception& ex) { //---- Enter your exception handling code here ----- hkjm::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return 0; } //------------------------------------------------------------------------------ //---------------------Block UI Styler Callback Functions-------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //Callback Name: initialize_cb //------------------------------------------------------------------------------ void hkjm::initialize_cb() { try { group0 = dynamic_cast<NXOpen::BlockStyler::Group*>(theDialog->TopBlock()->FindBlock("group0")); hk2edge = dynamic_cast<NXOpen::BlockStyler::CurveCollector*>(theDialog->TopBlock()->FindBlock("hk2edge")); hk1edge = dynamic_cast<NXOpen::BlockStyler::CurveCollector*>(theDialog->TopBlock()->FindBlock("hk1edge")); hk1sd = dynamic_cast<NXOpen::BlockStyler::ExpressionBlock*>(theDialog->TopBlock()->FindBlock("hk1sd")); hk2sd = dynamic_cast<NXOpen::BlockStyler::ExpressionBlock*>(theDialog->TopBlock()->FindBlock("hk2sd")); group = dynamic_cast<NXOpen::BlockStyler::Group*>(theDialog->TopBlock()->FindBlock("group")); hkdj = dynamic_cast<NXOpen::BlockStyler::ExpressionBlock*>(theDialog->TopBlock()->FindBlock("hkdj")); hk2jd = dynamic_cast<NXOpen::BlockStyler::ExpressionBlock*>(theDialog->TopBlock()->FindBlock("hk2jd")); hk1jd = dynamic_cast<NXOpen::BlockStyler::ExpressionBlock*>(theDialog->TopBlock()->FindBlock("hk1jd")); vector0 = dynamic_cast<NXOpen::BlockStyler::SpecifyVector*>(theDialog->TopBlock()->FindBlock("vector0")); bodySelect0 = dynamic_cast<NXOpen::BlockStyler::BodyCollector*>(theDialog->TopBlock()->FindBlock("bodySelect0")); color1 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color1")); color2 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color2")); } catch(exception& ex) { //---- Enter your exception handling code here ----- hkjm::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } //------------------------------------------------------------------------------ //Callback Name: dialogShown_cb //This callback is executed just before the dialog launch. Thus any value set //here will take precedence and dialog will be launched showing that value. //------------------------------------------------------------------------------ void hkjm::dialogShown_cb() { try { //---- Enter your callback code here ----- } catch(exception& ex) { //---- Enter your exception handling code here ----- hkjm::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } //------------------------------------------------------------------------------ //Callback Name: apply_cb //------------------------------------------------------------------------------ // 应用按钮回调函数 - 读取所有控件数据 int hkjm::apply_cb() { int errorCode = 0; std::string logMsg; try { // ===== 1. 获取曲线选择器1的值 ===== std::vector<Curve*> curves1; if (hk1edge) { PropertyList* props = hk1edge->GetProperties(); std::vector<TaggedObject*> selObjs = props->GetTaggedObjectVector("SelectedObjects"); for (TaggedObject* obj : selObjs) { if (Curve* curve = dynamic_cast<Curve*>(obj)) { curves1.push_back(curve); logMsg += "曲线1: " + std::string(curve->JournalIdentifier()) + "\n"; // 示例:设置曲线颜色为186号色 UF_OBJ_set_color(obj->Tag(), 186); } } // 更新控件中的选择对象(如果需要保留修改) props->SetTaggedObjectVector("SelectedObjects", selObjs); delete props; // 必须删除属性对象 } // ===== 2. 获取曲线选择器2的值 ===== std::vector<Curve*> curves2; if (hk2edge) { PropertyList* props = hk2edge->GetProperties(); std::vector<TaggedObject*> selObjs = props->GetTaggedObjectVector("SelectedObjects"); for (TaggedObject* obj : selObjs) { if (Curve* curve = dynamic_cast<Curve*>(obj)) { curves2.push_back(curve); logMsg += "曲线2: " + std::string(curve->JournalIdentifier()) + "\n"; } } props->SetTaggedObjectVector("SelectedObjects", selObjs); delete props; } // ===== 3. 获取hk1sd表达式值 ===== double hk1sdValue = 0.0; if (hk1sd) { PropertyList* props = hk1sd->GetProperties(); hk1sdValue = props->GetDouble("Value"); logMsg += "hk1sd值: " + std::to_string(hk1sdValue) + "\n"; // 示例:设置新值 // props->SetDouble("Value", hk1sdValue * 2); delete props; } // ===== 4. 获取hk2sd表达式值 ===== double hk2sdValue = 0.0; if (hk2sd) { PropertyList* props = hk2sd->GetProperties(); hk2sdValue = props->GetDouble("Value"); logMsg += "hk2sd值: " + std::to_string(hk2sdValue) + "\n"; delete props; } // ===== 5. 获取hkdj表达式值 ===== double hkdjValue = 0.0; if (hkdj) { PropertyList* props = hkdj->GetProperties(); hkdjValue = props->GetDouble("Value"); logMsg += "hkdj值: " + std::to_string(hkdjValue) + "\n"; delete props; } // ===== 6. 获取hk1jd表达式值 ===== double hk1jdValue = 0.0; if (hk1jd) { PropertyList* props = hk1jd->GetProperties(); hk1jdValue = props->GetDouble("Value"); logMsg += "hk1jd值: " + std::to_string(hk1jdValue) + "\n"; delete props; } // ===== 7. 获取hk2jd表达式值 ===== double hk2jdValue = 0.0; if (hk2jd) { PropertyList* props = hk2jd->GetProperties(); hk2jdValue = props->GetDouble("Value"); logMsg += "hk2jd值: " + std::to_string(hk2jdValue) + "\n"; delete props; } // ===== 8. 获取矢量方向 ===== Vector3d directionVector(0.0, 0.0, 1.0); // 默认Z方向 if (vector0) { PropertyList* props = vector0->GetProperties(); directionVector = props->GetVector("Vector"); logMsg += "矢量方向: (" + std::to_string(directionVector.X) + ", " + std::to_string(directionVector.Y) + ", " + std::to_string(directionVector.Z) + ")\n"; delete props; } // ===== 9. 获取选中的实体 ===== std::vector<Body*> bodies; if (bodySelect0) { PropertyList* props = bodySelect0->GetProperties(); std::vector<TaggedObject*> selObjs = props->GetTaggedObjectVector("SelectedObjects"); for (TaggedObject* obj : selObjs) { if (Body* body = dynamic_cast<Body*>(obj)) { bodies.push_back(body); logMsg += "实体: " + std::string(body->JournalIdentifier()) + "\n"; } } props->SetTaggedObjectVector("SelectedObjects", selObjs); delete props; } // ===== 10. 获取颜色选择器1的颜色 ===== int colorIndex1 = 0; // 默认黑色 if (color1) { PropertyList* colorProps = color1->GetProperties(); std::vector<int> colors = colorProps->GetIntegerVector("Value"); if (!colors.empty()) { colorIndex1 = colors[0]; logMsg += "颜色1索引: " + std::to_string(colorIndex1) + "\n"; // 示例:设置新颜色 // std::vector<int> newColors = {186}; // colorProps->SetIntegerVector("Value", newColors); } delete colorProps; } // ===== 11. 获取颜色选择器2的颜色 ===== int colorIndex2 = 0; // 默认黑色 if (color2) { PropertyList* colorProps = color2->GetProperties(); std::vector<int> colors = colorProps->GetIntegerVector("Value"); if (!colors.empty()) { colorIndex2 = colors[0]; logMsg += "颜色2索引: " + std::to_string(colorIndex2) + "\n"; } delete colorProps; } // ===== 输出所有获取的值 ===== theUI->NXMessageBox()->Show("控件值获取结果", NXMessageBox::DialogTypeInformation, logMsg.c_str()); } catch (std::exception& ex) { errorCode = 1; std::string errorMsg = "获取控件值错误: "; errorMsg += ex.what(); theUI->NXMessageBox()->Show("错误", NXMessageBox::DialogTypeError, errorMsg.c_str()); } catch (...) { errorCode = 1; theUI->NXMessageBox()->Show("错误", NXMessageBox::DialogTypeError, "未知获取控件值错误"); } return errorCode; } //------------------------------------------------------------------------------ //Callback Name: update_cb //------------------------------------------------------------------------------ int hkjm::update_cb(NXOpen::BlockStyler::UIBlock* block) { try { if(block == hk2edge) { //---------Enter your code here----------- } else if(block == hk1edge) { //---------Enter your code here----------- } else if(block == hk1sd) { //---------Enter your code here----------- } else if(block == hk2sd) { //---------Enter your code here----------- } else if(block == hkdj) { //---------Enter your code here----------- } else if(block == hk2jd) { //---------Enter your code here----------- } else if(block == hk1jd) { //---------Enter your code here----------- } else if(block == vector0) { //---------Enter your code here----------- } else if(block == bodySelect0) { //---------Enter your code here----------- } else if(block == color1) { //---------Enter your code here----------- } else if(block == color2) { //---------Enter your code here----------- } } catch(exception& ex) { //---- Enter your exception handling code here ----- hkjm::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return 0; } //------------------------------------------------------------------------------ //Callback Name: ok_cb //------------------------------------------------------------------------------ int hkjm::ok_cb() { int errorCode = 0; try { errorCode = apply_cb(); } catch(exception& ex) { //---- Enter your exception handling code here ----- errorCode = 1; hkjm::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return errorCode; } //------------------------------------------------------------------------------ //Function Name: GetBlockProperties //Description: Returns the propertylist of the specified BlockID //------------------------------------------------------------------------------ PropertyList* hkjm::GetBlockProperties(const char *blockID) { return theDialog->GetBlockProperties(blockID); }错误提示:严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E0289 没有与参数列表匹配的构造函数 "std::basic_string<_Elem, _Traits, _Alloc>::basic_string [其中 _Elem=char, _Traits=std::char_traits<char>, _Alloc=std::allocator<char>]" 实例 hkjm D:\NXopen\BaiduSyncdisk\studio\hkjm\hkjm.cpp 251 错误(活动) E0289 没有与参数列表匹配的构造函数 "std::basic_string<_Elem, _Traits, _Alloc>::basic_string [其中 _Elem=char, _Traits=std::char_traits<char>, _Alloc=std::allocator<char>]" 实例 hkjm D:\NXopen\BaiduSyncdisk\studio\hkjm\hkjm.cpp 271 错误(活动) E0289 没有与参数列表匹配的构造函数 "std::basic_string<_Elem, _Traits, _Alloc>::basic_string [其中 _Elem=char, _Traits=std::char_traits<char>, _Alloc=std::allocator<char>]" 实例 hkjm D:\NXopen\BaiduSyncdisk\studio\hkjm\hkjm.cpp 353
08-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值