使用C語言實現簡單的通用的鏈表

来源:https://www.cnblogs.com/maiyat/archive/2023/06/07/17464270.html
-Advertisement-
Play Games

在數據結構中,我們已經學習到了簡單的靜態鏈表以及單鏈表和雙鏈表,它們各有優缺點,但是有個共同的問題是他們呢無法存儲不同的數據。下麵提供了一種方法,可以將不同節點的數據鏈接起來。 下麵的代碼都是基礎的C語言代碼,涉及到的知識點基本覆蓋到C語言學習的所有知識面,尤其是使用了巨集,減少了重覆的代碼。 無論是 ...


在數據結構中,我們已經學習到了簡單的靜態鏈表以及單鏈表和雙鏈表,它們各有優缺點,但是有個共同的問題是他們呢無法存儲不同的數據。下麵提供了一種方法,可以將不同節點的數據鏈接起來。

下麵的代碼都是基礎的C語言代碼,涉及到的知識點基本覆蓋到C語言學習的所有知識面,尤其是使用了巨集,減少了重覆的代碼。

無論是C語言大佬還是C語言萌新,都可以食用此鏈表,理解起來可能很複雜,以下是源碼,建議好好理解。

Main.c

#include "stdafx.h"
#include"Teacher.h"
#include "Student.h"
#include"MainCmd.h"

int main()
{
    CALL_PROC(Main, MainCmd)

    return 0;
}

Stdafx.h

#pragma once
#include<iostream>
using namespace std;

Teacher.h

#pragma once
#include"List.h"
#include"CmdMap.h"

DECLEAR_PROC(Teacher)

struct TEACHER
{
    LINKER linker;

    char szName[20];
    char szAddr[20];
    int nAge;
};

extern LINKER* g_pTeacher;

LINKER* CreateTeacher();
void InputTeacher(LINKER* pLink);
void OutputTeacher(const LINKER* pLink);
LINKER* FindTeacher(LINKER* pHead);

void CreateTeacherList();
void AddTeacher();
void DeleteTeacher();
void FindTeacherNode();
void InsertTeacher();
void ShowTeacherList();
void ClearTeacherList();

Teacher.cpp

#include"Teacher.h"
#include"Student.h"
#include"stdafx.h"
#include"CmdFun.h"

FUN_TABLE g_TeacherTable = { CreateTeacher,&InputTeacher,&OutputTeacher,&FindTeacher };

LINKER* CreateTeacher()
{
    char szName[12] = "";
    cout << "請輸入創建的結點類型:(Student Or Teacher)";
    cin >> szName;
    if (!strcmp(szName, "Student"))
    {
        STUDENT* pNew = new STUDENT;
        if (NULL != pNew)
        {
            pNew->linker.pFunTab = &g_StudentTable;
            pNew->linker.pNext = NULL;
            pNew->linker.pPrev = NULL;
        }
        return (LINKER*)pNew;
    }
    if (!strcmp(szName, "Teacher"))
    {
        TEACHER* pNew = new TEACHER;
        if (NULL != pNew)
        {
            pNew->linker.pFunTab = &g_TeacherTable;
            pNew->linker.pNext = NULL;
            pNew->linker.pPrev = NULL;
        }
        return (LINKER*)pNew;
    }

    return NULL;
}

void InputTeacher(LINKER* pLink)
{
    TEACHER* pTemp = (TEACHER*)pLink;
    cout << "請輸入姓名:";
    cin >> pTemp->szName;
    cout << "請輸入住址:";
    cin >> pTemp->szAddr;
    cout << "請輸入年齡:";
    cin >> pTemp->nAge;

}

void OutputTeacher(const LINKER* pLink)
{
    TEACHER* pTemp = (TEACHER*)pLink;
    cout << "***********************" << endl;
    cout << "姓名:" << pTemp->szName << endl;
    cout << "住址:" << pTemp->szAddr << endl;
    cout << "年齡:" << pTemp->nAge << endl;
}

LINKER* FindTeacher(LINKER* pHead)
{
    TEACHER* pTemp = (TEACHER*)pHead;

    cout << "請輸入要查找的姓名:";
    char szBuf[20];
    cin >> szBuf;

    while (NULL != pTemp->linker.pNext)
    {
        if (0 == strcmp(szBuf, pTemp->szName))
        {
            return (LINKER*)pTemp;
        }
        pTemp = (TEACHER*)pTemp->linker.pNext;
    }

    return NULL;
}

CMD_MAP_BEGIN(Teacher)
CMD(Create, 創建, CreateTeacherList)
CMD(Add, 添加, AddTeacher)
CMD(Delete, 刪除, DeleteTeacher)
CMD(Find, 查找, FindTeacherNode)
CMD(Insert, 插入, InsertTeacher)
CMD(Show, 創建, ShowTeacherList)
CMD(Clear, 清空, ClearTeacherList)
CMD(Back, 返回, NULL)
CMD_MAP_END()


LINKER* g_pTeacher = NULL;

CmdFun(Teacher)

Student.h

#pragma once
#include"List.h"
#include"CmdMap.h"

DECLEAR_PROC(Student)

struct STUDENT
{
    LINKER linker;

    char szID[20];
    char chSex;
    int nGrade;
};

struct STAFF
{
    LINKER linker;

    char szID[20];
    char chSex;
    int nGrade;
};

LINKER* CreateStudent();
void InputStudent(LINKER* pLink);
void OutputStudent(const LINKER* pLink);
LINKER* FindStudent(LINKER* pHead);

void CreateStudentList();
void AddStudent();
void DeleteStudent();
void FindStudentNode();
void InsertStudent();
void ShowStudentList();
void ClearStudentList();

Student.cpp

#include"Student.h"
#include"Teacher.h"
#include"stdafx.h"
#include"CmdFun.h"

FUN_TABLE g_StudentTable = { &CreateStudent,&InputStudent,&OutputStudent,&FindStudent };

LINKER* CreateStudent()
{
    char szName[12] = "";
    cout << "請輸入創建的結點類型:(Student Or Teacher)";
    cin >> szName;
    if (!strcmp(szName, "Student"))
    {
        STUDENT* pNew = new STUDENT;
        if (NULL != pNew)
        {
            pNew->linker.pFunTab = &g_StudentTable;
            pNew->linker.pNext = NULL;
            pNew->linker.pPrev = NULL;
        }
        return (LINKER*)pNew;
    }
    if (!strcmp(szName, "Teacher"))
    {
        TEACHER* pNew = new TEACHER;
        if (NULL != pNew)
        {
            pNew->linker.pFunTab = &g_TeacherTable;
            pNew->linker.pNext = NULL;
            pNew->linker.pPrev = NULL;
        }
        return (LINKER*)pNew;
    }

    return NULL;
}

void InputStudent(LINKER* pLink)
{
    STUDENT* pTemp = (STUDENT*)pLink;
    cout << "請輸入ID:";
    cin >> pTemp->szID;
    cout << "請輸入性別:";
    cin >> pTemp->chSex;
    cout << "請輸入分數:";
    cin >> pTemp->nGrade;

}

void OutputStudent(const LINKER* pLink)
{
    STUDENT* pTemp = (STUDENT*)pLink;
    cout << "***********************" << endl;
    cout << "ID:" << pTemp->szID << endl;
    cout << "性別:" << pTemp->chSex << endl;
    cout << "分數:" << pTemp->nGrade << endl;
}

LINKER* FindStudent(LINKER* pHead)
{
    if (NULL == pHead)
    {
        return NULL;
    }

    STUDENT* pTemp = (STUDENT*)pHead;

    cout << "請輸入要查找的ID:";
    char szBuf[20];
    cin >> szBuf;

    while (NULL != pTemp)
    {
        if (0 == strcmp(szBuf, pTemp->szID))
        {
            return (LINKER*)pTemp;
        }
        pTemp = (STUDENT*)pTemp->linker.pNext;
    }

    return NULL;
}

CMD_MAP_BEGIN(Student)
CMD(Create, 創建, CreateStudentList)
CMD(Add, 添加, AddStudent)
CMD(Delete, 刪除, DeleteStudent)
CMD(Find, 查找, FindStudentNode)
CMD(Insert, 插入, InsertStudent)
CMD(Show, 創建, ShowStudentList)
CMD(Clear, 清空, ClearStudentList)
CMD(Back, 返回, NULL)
CMD_MAP_END()

LINKER* g_pStudent = NULL;

//CmdFun(Student)

void CreateStudentList() { switch (CreatList(&g_pStudent, CreateStudent)) { case ELIST_MEMORY_FAIL: cout << "動態記憶體分配失敗" << endl; break; case ELIST_OK: cout << "創建鏈表成功" << endl; break; case ELIST_PARAM: cout << "傳參不合理" << endl; break; case ELIST_CREATE_FAIL: cout << "鏈表已存在,創建鏈表失敗" << endl; break; default: break; } } void AddStudent() { switch (Add(g_pStudent)) { case ELIST_MEMORY_FAIL: cout << "動態記憶體分配失敗" << endl; break; case ELIST_OK: cout << "增加結點成功" << endl; break; case ELIST_NOTEXIST: cout << "鏈表不存在" << endl; break; default: break; } } void DeleteStudent() { LINKER* pNode = FindStudent(g_pStudent); switch (DeleteNode(&g_pStudent, pNode)) { case ELIST_OK: cout << "刪除結點成功" << endl; break; case ELIST_PARAM: cout << "沒有找到要刪除的結點" << endl; break; case ELIST_NOTEXIST: cout << "鏈表不存在" << endl; break; default: break; } } void FindStudentNode() { LINKER* pNode = FindStudent(g_pStudent); if (NULL != pNode) { cout << "查找成功,該結點信息如下:" << endl; OutputStudent(pNode); } else { cout << "查找失敗" << endl; } } void InsertStudent() { LINKER* pNode = FindStudent(g_pStudent); if (NULL == pNode) { cout << "沒有找到要插入的位置" << endl; } int mode; cout << "輸入1表示前插輸入0表示後插:"; cin >> mode; switch (Insert(&g_pStudent, pNode, (MODE)mode)) { case ELIST_MEMORY_FAIL: cout << "動態記憶體分配失敗" << endl; break; case ELIST_OK: cout << "插入成功" << endl; break; case ELIST_NOTFIND: cout << "沒有找到要插入的位置,插入失敗" << endl; break; case ELIST_PARAM: cout << "傳入的參數有誤" << endl; break; case ELIST_NOTEXIST: cout << "鏈表不存在,插入失敗!" << endl; break; default: break; } } void ShowStudentList() { switch (ShowList(g_pStudent)) { case ELIST_PARAM: cout << "鏈表不存在" << endl; break; case ELIST_OK: cout << "鏈表已全部顯示" << endl; break; default: break; } } void ClearStudentList() { switch (ClearList(&g_pStudent)) { case ELIST_PARAM: cout << "鏈表不存在" << endl; break; case ELIST_NOTEXIST: cout << "鏈表清空鏈表失敗" << endl; break; case ELIST_OK: cout << "清空鏈表成功" << endl; break; default: break; } }

MainCmd.h

#pragma once
#include"CmdMap.h"

DECLEAR_PROC(Main);

MainCmd.cpp

#include"stdafx.h"
#include"MainCmd.h"
#include"Student.h"
#include"Teacher.h"

void Teacher();
void Student();

CMD_MAP_BEGIN(Main)
CMD(Teacher, 老師, &Teacher)
CMD(Student, 學生, &Student)
CMD(Exit, 退出, NULL)
CMD_MAP_END()

void Teacher()
{
    system("cls");
    CALL_PROC(Teacher, Teacher);
    system("cls");
}

void Student()
{
    system("cls");
    CALL_PROC(Student, Student);
    system("cls");
}

List.h

#pragma once

#define ELIST_OK 1
#define ELIST_CREATE_FAIL -1
#define ELIST_MEMORY_FAIL -2
#define ELIST_NOTEXIST -3
#define ELIST_PARAM -4
#define ELIST_NOTFIND -5

struct LINKER;
struct FUN_TABLE
{
    LINKER* (*pfnCreateNode)();
    void (*pfnInput)(LINKER* pNode);
    void (*pfnOutput)(const LINKER* pNode);
    LINKER* (*pfnFind)(LINKER* pHead);
};

extern FUN_TABLE g_TeacherTable;
extern FUN_TABLE g_StudentTable;


struct LINKER
{
    FUN_TABLE* pFunTab;

    LINKER* pNext;
    LINKER* pPrev;
};

enum MODE { before = 1, after = 0 };

int CreatList(LINKER** ppHead, LINKER* (*pfnCreateNode)());
int Add(LINKER* pHead);
int DeleteNode(LINKER** ppHead, LINKER* pNode);
LINKER* FindNode(LINKER* pHead);
int Insert(LINKER** ppHead, LINKER* pNode, MODE mode);
int ShowList(LINKER* pHead);
int ClearList(LINKER** ppHead);

List.cpp

#include "List.h"
#include"stdafx.h"

int CreatList(LINKER** ppHead, LINKER* (*pfnCreateNode)())
{
    if (NULL == ppHead)
    {
        return ELIST_PARAM;
    }
    if (NULL != *ppHead)
    {
        return ELIST_CREATE_FAIL;
    }

    LINKER* pNew = pfnCreateNode();
    if (NULL == pNew)
    {
        return ELIST_MEMORY_FAIL;
    }

    pNew->pFunTab->pfnInput(pNew);
    *ppHead = pNew;

    return ELIST_OK;
}

int Add(LINKER* pHead)
{
    if (NULL == pHead)
    {
        return ELIST_NOTEXIST;
    }
    while (NULL != pHead->pNext)
    {
        pHead = pHead->pNext;
    }

    LINKER* pNew = pHead->pFunTab->pfnCreateNode();
    if (NULL == pNew)
    {
        return ELIST_MEMORY_FAIL;
    }

    pNew->pFunTab->pfnInput(pNew);
    pHead->pNext = pNew;
    pNew->pPrev = pHead;

    return ELIST_OK;
}

int DeleteNode(LINKER** ppHead, LINKER* pNode)
{
    if (NULL == ppHead || NULL == pNode)
    {
        return ELIST_PARAM;
    }
    if (NULL == *ppHead)
    {
        return ELIST_NOTEXIST;
    }

    if (NULL == pNode->pPrev)
    {
        *ppHead = pNode->pNext;
    }
    else
    {
        pNode->pPrev->pNext = pNode->pNext;
    }
    if (NULL != pNode->pNext)
    {
        pNode->pNext->pPrev = pNode->pPrev;
    }

    delete pNode;
    pNode = NULL;

    return ELIST_OK;
}

LINKER* FindNode(LINKER* pHead)
{
    if (NULL == pHead)
    {
        return NULL;
    }

    return pHead->pFunTab->pfnFind(pHead);

}

int Insert(LINKER** ppHead, LINKER* pNode, MODE mode)
{
    if (NULL == ppHead)
    {
        return ELIST_PARAM;
    }
    if (NULL == *ppHead)
    {
        return ELIST_NOTEXIST;
    }
    if (NULL == pNode)
    {
        return ELIST_NOTFIND;
    }

    LINKER* pNew = (*ppHead)->pFunTab->pfnCreateNode();
    if (NULL == pNew)
    {
        return ELIST_MEMORY_FAIL;
    }
    pNew->pFunTab->pfnInput(pNew);

    if (1 == mode)
    {
        if (NULL == pNode->pPrev)
        {
            *ppHead = pNew;
        }
        else
        {
            pNode->pPrev->pNext = pNew;
        }
        pNew->pPrev = pNode->pPrev;
        pNew->pNext = pNode;
        pNode->pPrev = pNew;
    }
    else if (0 == mode)
    {
        if (NULL != pNode->pNext)
        {
            pNode->pNext->pPrev = pNew;
        }
        pNew->pNext = pNode->pNext;
        pNew->pPrev = pNode;
        pNode->pNext = pNew;
    }
    else
    {
        return ELIST_PARAM;
    }

    return ELIST_OK;
}

int ClearList(LINKER** ppHead)
{
    if (NULL == ppHead)
    {
        return ELIST_PARAM;
    }
    if (NULL == *ppHead)
    {
        return ELIST_NOTEXIST;
    }

    LINKER* pTemp = *ppHead;
    while (NULL != pTemp)
    {
        *ppHead = pTemp->pNext;
        delete pTemp;
        pTemp = *ppHead;
    }

    return ELIST_OK;
}

int ShowList(LINKER* pHead)
{
    if (NULL == pHead)
    {
        return ELIST_PARAM;
    }
    while (NULL != pHead)
    {
        pHead->pFunTab->pfnOutput(pHead);
        pHead = pHead->pNext;
    }
    cout << endl;

    return ELIST_OK;
}

CmdFun.h

#pragma once
#pragma once
#include"stdafx.h"
#include"List.h"

#define CmdFun(name)\
void Create##name##List()\
{\
    switch (CreatList(&g_p##name, Create##name))\
    {\
    case ELIST_MEMORY_FAIL:\
        cout << "動態記憶體分配失敗" << endl;\
        break;\
    case ELIST_OK:\
        cout << "創建鏈表成功" << endl;\
        break;\
    case ELIST_PARAM:\
        cout << "傳參不合理" << endl;\
        break;\
    case ELIST_CREATE_FAIL:\
        cout << "鏈表已存在,創建鏈表失敗" << endl;\
        break;\
    default:\
        break;\
    }\
}\
void Add##name()\
{\
    switch (Add(g_p##name))\
    {\
    case ELIST_MEMORY_FAIL:\
        cout << "動態記憶體分配失敗" << endl;\
        break;\
    case ELIST_OK:\
        cout << "增加結點成功" << endl;\
        break;\
    case ELIST_NOTEXIST:\
        cout << "鏈表不存在" << endl;\
        break;\
    default:\
        break;\
    }\
}\
\
void Delete##name()\
{\
    LINKER* pNode = Find##name(g_p##name);\
\
    switch (DeleteNode(&g_p##name, pNode))\
    {\
    case ELIST_OK:\
        cout << "刪除結點成功" << endl;\
        break;\
    case ELIST_PARAM:\
        cout << "沒有找到要刪除的結點" << endl;\
        break;\
    case ELIST_NOTEXIST:\
        cout << "鏈表不存在" << endl;\
        break;\
    default:\
        break;\
    }\
}\
\
void Find##name##Node()\
{\
    LINKER* pNode = Find##name(g_p##name);\
    if (NULL != pNode)\
    {\
        cout << "查找成功,該結點信息如下:" << endl;\
        Output##name(pNode);\
    }\
    else\
    {\
        cout << "查找失敗" << endl;\
    }\
}\
\
void Insert##name()\
{\
    LINKER* pNode = Find##name(g_p##name);\
    if (NULL == pNode)\
    {\
        cout << "沒有找到要插入的位置" << endl;\
    }\
\
    int mode;\
    cout << "輸入1表示前插輸入0表示後插:";\
    cin >> mode;\
\
    switch (Insert(&g_p##name, pNode, (MODE)mode))\
    {\
    case ELIST_MEMORY_FAIL:\
        cout << "動態記憶體分配失敗" << endl;\
        break;\
    case ELIST_OK:\
        cout << "插入成功" << endl;\
        break;\
    case ELIST_NOTFIND:\
        cout << "沒有找到要插入的位置,插入失敗" << endl;\
        break;\
    case ELIST_PARAM:\
        cout << "傳入的參數有誤" << endl;\
        break;\
    case ELIST_NOTEXIST:\
        cout << "鏈表不存在,插入失敗!" << endl;\
        break;\
    default:\
        break;\
    }\
}\
\
void Show##name##List()\
{\
    switch (ShowList(g_p##name))\
    {\
    case ELIST_PARAM:\
        cout << "鏈表不存在" << endl;\
        	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • [toc] # 一、爬取目標 本次爬取的目標是,愛奇藝電視劇類目下的10個榜單:[電視劇風雲榜-愛奇藝風雲榜](https://www.iqiyi.com/ranks1/2/0) ​![愛奇藝頁面](https://img2023.cnblogs.com/blog/2864563/202306/28 ...
  • # 引擎下載地址 https://cocos2d-x.org/download/ 也可以在 github 下載 https://github.com/cocos2d/cocos2d-x/tags # 手冊地址 https://docs.cocos2d-x.org/cocos2d-x/v3/zh/ # ...
  • //個人學習筆記用 - 題目: 給定一個排序數組和一個目標值,在數組中找到目標值,並返回其索引。如果目標值不存在於數組中,返回它將會被按順序插入的位置。 請必須使用時間複雜度為 O(log n) 的演算法。 參考題解--代碼隨想錄 - 暴力解法: ~~~c++ class Solution { pub ...
  • # 數據結構 in Golang:Hash Tables(哈希表) ### 場景 - 水果店的價格表: - 蘋果 Apple:3元 - 香蕉 Banana:4元 - 桃子 Peach:2元 - 梨 Pear:3元 - 找到一種水果的價格: - 可以使用 binary search,通過名稱來查找,耗 ...
  • 某日二師兄參加XXX科技公司的C++工程師開發崗位第8面: > 面試官:C++中,函數的參數應該傳值還是傳引用? > > 二師兄:要看參數的用途。如果是出參,必須傳引用。如果是入參,主要考慮參數類型的大小,來決定傳值還是傳引用。 > > 面試官:為什麼不使用指針? > > 二師兄:傳指針也稱之為傳引 ...
  • **# Properties類** - **基本介紹** ![](https://img2023.cnblogs.com/blog/3008601/202306/3008601-20230604103622859-1793594469.png) 1. 專門用於讀寫配置文件的集合類 配置文件的格式: ...
  • ## SpringMVC如何接受請求參數(普通類型參數/對象類型參數/數組/json數據等) 1、普通類型參數 (1)在可以在方法參數上使用@RequestParam註解來綁定請求參數,此註解允許指定請求參數的名稱,以及是否是必須傳的參數。 ~~~java @RequestMapping("/exa ...
  • # 安裝 略 # hello world > 1. 文檔地址: [https://marketplace.visualstudio.com/items?itemName=humao.rest-client](https://marketplace.visualstudio.com/items?ite ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...