DES加密的C++实现(带每轮加密的中间结果)

也可从我的github上下载整个工程:https://github.com/archimekai/DESEnciphererNew/

免责声明:
This software comes with ABSOLUTELY NO WARRANTY.

main.cpp

#include "DESUtility.h"
#include <iostream>
#include <string>


using namespace std;
using namespace DESUtility;

void main() {
    cout << "Hello world!\n";
    Encipherer encipherer = Encipherer();
    char key[8] = { 'S', 'E', 'C', 'U', 'R', 'I', 'T', 'Y' };
    string text = string("NETWORK INFORMATION SECURITY");
    //string text = string("a");
    encipherer.setKey((unsigned char *)key);
    unsigned char * result = encipherer.encipher(text);
    printf("\nEnciphered text:");
    for (int i = 0; i < encipherer.ciphertextSize; ++i) {
        printf("%02X", result[i]);
        if ((i + 1) % 2 == 0) printf(" ");
    }
    printf("\n");

    elemType * decipered = encipherer.decipher(result, encipherer.ciphertextSize);
    printf("\nPlain text:");
    for (int i = 0; i < encipherer.ciphertextSize; ++i) {
        printf("%c", decipered[i]);
    }

    system("pause");
}

DESUtility.h

#pragma once
#define BLOCK_SIZE 64 // 一块密文的长度
#define BLOCK_HALF_SIZE (BLOCK_SIZE/2)
#define BLOCK_elemType 8
#define E_SIZE 48 // 经过选择拓展之后的位数
#define ROUND_N 16 // 加密的轮数
#define KEY_LEN 64 // 密钥长度
#define KEY_LEN_AFTER_P1 56  // 经过置换选择之后的密钥长度
#define KEY_HALF_LEN_AFTER_P1 (KEY_LEN_AFTER_P1/2)
#define SUB_KEY_LEN 48
#define ELEM_TYPE_BIT_SIZE 8
#define DEBUG // 输出中间结果
//#define DEBUG_ROUND
typedef unsigned char elemType;
//typedef unsigned char textType; //文本的类型

#include<string>


using namespace std;

namespace DESUtility {
    class Encipherer {
    public:
        unsigned char * encipher(string text);
        void setKey(unsigned char key[KEY_LEN / 8]);
        int ciphertextSize; // 密文长度
        elemType* decipher(elemType* compactBlock, int len); // blocks为压缩过的密文
        void encipherBlock(elemType block[BLOCK_SIZE]);
        void decipherBlock(elemType block[BLOCK_SIZE], elemType text[8]);
        Encipherer() { ; }
        Encipherer(unsigned char key[KEY_LEN / 8]) {
            this->setKey(key);
        }
    private:  
        elemType key[KEY_LEN]; // 秘钥
        elemType subkeys[KEY_LEN_AFTER_P1 * ROUND_N]; //子密钥
        int char2block(unsigned char* ch, elemType block[BLOCK_SIZE], int len);
        int block2hex(elemType block[BLOCK_SIZE], elemType converted[BLOCK_SIZE / ELEM_TYPE_BIT_SIZE]);
        void printConvertedBlock(elemType converted[BLOCK_SIZE / ELEM_TYPE_BIT_SIZE]);
        void printSparseBlock(elemType block[BLOCK_SIZE]);

        void initialPermutation(elemType* block, elemType* temp64);
        void initialPermutation(elemType block[BLOCK_SIZE]);
        void reversePermutation(elemType* block, elemType* temp64);
        void reversePermutation(elemType block[BLOCK_SIZE]);
        //void encipherBlock(elemType block[BLOCK_SIZE]);

        void genSubKey();

        void round(elemType block[BLOCK_SIZE], int iterCount);
        void extend(elemType block[BLOCK_HALF_SIZE], elemType tempE[E_SIZE]);
        void shiftLeft(elemType* block, int len, int shiftCount);
        void shiftLeftOneBit(elemType* block, int len);
        void replaceSelection2(elemType CD[KEY_LEN_AFTER_P1], elemType target[SUB_KEY_LEN]);
        void xorWithKey(elemType blockE[E_SIZE], int iterCount);
        void xorWithLAndSwapLR(elemType block[BLOCK_SIZE]);
        void selectCompression(elemType blockE[E_SIZE], elemType target[BLOCK_HALF_SIZE]);
        void permutation(elemType input[BLOCK_HALF_SIZE], elemType target[BLOCK_HALF_SIZE]);
        void swapLR(elemType block[BLOCK_SIZE]);

        //void decipherBlock(elemType block[BLOCK_SIZE], elemType text[8]);
        //void num2bits();
    };
}

DESUtility.cpp

#include "DESUtility.h"
#include <iostream>
using namespace std;
namespace DESUtility {
#pragma region constant parameters

    //初始置换表IP   
    int IP_Table[64] = { 57,49,41,33,25,17,9,1,
        59,51,43,35,27,19,11,3,
        61,53,45,37,29,21,13,5,
        63,55,47,39,31,23,15,7,
        56,48,40,32,24,16,8,0,
        58,50,42,34,26,18,10,2,
        60,52,44,36,28,20,12,4,
        62,54,46,38,30,22,14,6 };

    //逆初始置换表IP^-1   
    int IP_1_Table[64] = { 39,7,47,15,55,23,63,31,
        38,6,46,14,54,22,62,30,
        37,5,45,13,53,21,61,29,
        36,4,44,12,52,20,60,28,
        35,3,43,11,51,19,59,27,
        34,2,42,10,50,18,58,26,
        33,1,41,9,49,17,57,25,
        32,0,40,8,48,16,56,24 };

    //扩充置换表E   
    int E_Table[E_SIZE] = { 31, 0, 1, 2, 3, 4,
        3,  4, 5, 6, 7, 8,
        7,  8,9,10,11,12,
        11,12,13,14,15,16,
        15,16,17,18,19,20,
        19,20,21,22,23,24,
        23,24,25,26,27,28,
        27,28,29,30,31, 0 };

    //置换函数P   
    int P_Table[BLOCK_HALF_SIZE] = { 15,6,19,20,28,11,27,16,
        0,14,22,25,4,17,30,9,
        1,7,23,13,31,26,2,8,
        18,12,29,5,21,10,3,24 };

    //S盒   
    int S[8][4][16] =//S1   
    { { { 14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7 },
    { 0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8 },
    { 4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0 },
    { 15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13 } },
        //S2   
    { { 15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10 },
    { 3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5 },
    { 0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15 },
    { 13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9 } },
        //S3   
    { { 10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8 },
    { 13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1 },
    { 13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7 },
    { 1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12 } },
        //S4   
    { { 7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15 },
    { 13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9 },
    { 10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4 },
    { 3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14 } },
        //S5   
    { { 2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9 },
    { 14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6 },
    { 4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14 },
    { 11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3 } },
        //S6   
    { { 12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11 },
    { 10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8 },
    { 9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6 },
    { 4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13 } },
        //S7   
    { { 4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1 },
    { 13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6 },
    { 1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2 },
    { 6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12 } },
        //S8   
    { { 13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7 },
    { 1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2 },
    { 7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8 },
    { 2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11 } } };
    //置换选择1   
    int PC_1[KEY_LEN_AFTER_P1] = { 56,48,40,32,24,16,8,
        0,57,49,41,33,25,17,
        9,1,58,50,42,34,26,
        18,10,2,59,51,43,35,
        62,54,46,38,30,22,14,
        6,61,53,45,37,29,21,
        13,5,60,52,44,36,28,
        20,12,4,27,19,11,3 };

    //置换选择2   
    int PC_2[SUB_KEY_LEN] = { 13,16,10,23,0,4,2,27,
        14,5,20,9,22,18,11,3,
        25,7,15,6,26,19,12,1,
        40,51,30,36,46,54,29,39,
        50,44,32,46,43,48,38,55,
        33,52,45,41,49,35,28,31 };

    //对左移次数的规定   
    int MOVE_TIMES[ROUND_N] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 };
#pragma endregion


    unsigned char * Encipherer::encipher(string text) {
        const int len = text.size();
#ifdef DEBUG
        cout << "Text length: " << len <<"\n";
#endif // DEBUG

        unsigned char temp[8] = { 0 };
        elemType block[BLOCK_SIZE] = { 0 };
        int size = 0;
        if (len % 8 == 0) {
            size = len;
        }
        else {
            size = ((int)(len / 8)) * 8 + 8;
        }
#ifdef DEBUG
        cout << "Enciphered block size(bytes):" << size << "\n";
#endif // DEBUG

        unsigned char * resultBlock = (unsigned char *)malloc(sizeof(unsigned char) * size); // 为结果的紧致表示
        memset(resultBlock, 0, sizeof(unsigned char) * size);
        int i = 0;
        int blockNo = -1;
        for (i = 0; i < len; ++i) {
            temp[i % 8] = text.at(i);
            if ((i + 1) % 8 == 0) {
                blockNo = (i + 1) / 8 - 1;
#ifdef DEBUG
                cout << "\n====Now encipher block no." << blockNo << "====\n";
                cout << "Text to be enciphered: ";
                for (int k = 0; k < 8; ++k) {
                    cout << temp[k];
                }
                cout << "\n";
#endif // DEBUG
                char2block(temp, block, 8);
#ifdef DEBUG
                cout << "converted text:\n ";
                printSparseBlock(block);
                cout << "\n";
#endif // DEBUG
                encipherBlock(block);
                block2hex(block, resultBlock + blockNo * 8);
#ifdef DEBUG
                cout << "====Enciphered block no." << blockNo << "====\n";
                cout << "====Enciphered text:====\n";
                printConvertedBlock(resultBlock + blockNo * 8);
                cout << "\n";
#endif // DEBUG
                memset(temp, 0, sizeof(unsigned char) * 8);
                memset(block, 0, sizeof(elemType) * BLOCK_SIZE);
            }
        }
        if (len % 8 != 0) {
            ++blockNo;
#ifdef DEBUG
            cout << "\n====Now encipher block no." << blockNo << "====\n";
            cout << "Text to be enciphered: ";
            for (int k = 0; k < 8; ++k) {
                printf("%c", temp[k]);
            }
            cout << "\n";
#endif // DEBUG
            // 再加密一次
            char2block(temp, block, 8);
#ifdef DEBUG
            cout << "converted text:\n ";
            printSparseBlock(block);
            cout << "\n";
#endif // DEBUG
            encipherBlock(block);
            block2hex(block, resultBlock + blockNo * 8);
#ifdef DEBUG
            cout << "====Enciphered block no." << blockNo << "====\n";
            cout << "====Enciphered text:====\n";
            printConvertedBlock(resultBlock + blockNo * 8);
            cout << "\n";
#endif // DEBUG
        }
        ciphertextSize = size;
        return resultBlock; // memory leak

    }

    void Encipherer::setKey(unsigned char key[KEY_LEN / 8]) {
        char2block(key, this->key, KEY_LEN / 8);
        genSubKey();
    }

    // 输入的为经过紧致的密文,需要先转换为稀疏的密文
    // len必须是8的倍数
    elemType * Encipherer::decipher(elemType * compactBlock, int len) {
        int sparseLen = len * ELEM_TYPE_BIT_SIZE;
        elemType * block = (elemType *)malloc(sizeof(elemType) * sparseLen);
        for (int i = 0; i < len; ++i) {
            for (int j = 0; j < ELEM_TYPE_BIT_SIZE; ++j) {
                block[i * ELEM_TYPE_BIT_SIZE + j] = (compactBlock[i] >> j) % 2;
            }
        }
        elemType * result = (elemType *)malloc(sizeof(elemType) * len);
        memset(result, 0, sizeof(elemType) * len); // malloc 一定要记得初始化!!
        for (int i = 0; i < len / 8; ++i) {
            decipherBlock(block + i * BLOCK_SIZE, (elemType *)(result + 8 * i));
        }
        return result;
    }


    // 将C风格字符串序列转化为block,返回成功转化的个数,该值一般为8
    // len: ch 中还有几个字符
    int Encipherer::char2block(unsigned char * ch, elemType block[BLOCK_SIZE], int len) {
        int ncharsToConvert = BLOCK_SIZE / ELEM_TYPE_BIT_SIZE;
        int i;
        for (i = 0; i < ncharsToConvert && i < len; ++i) {
            for (int j = 0; j < 8; ++j) {
                // 一个char一般是8个bit
                block[i * 8 + j] = (ch[i] >> j) % 2;
            }
        }
        return i;
    }

    // converted为block的压缩表示
    int Encipherer::block2hex(elemType block[BLOCK_SIZE], elemType converted[BLOCK_SIZE / ELEM_TYPE_BIT_SIZE]) {
        for (int i = 0; i < BLOCK_SIZE / ELEM_TYPE_BIT_SIZE; ++i) {
            for (int j = 0; j < ELEM_TYPE_BIT_SIZE; ++j) {
                converted[i] += block[i * ELEM_TYPE_BIT_SIZE + j] << j;
            }
        }
        return 0;
    }

    void Encipherer::printConvertedBlock(elemType converted[BLOCK_SIZE / ELEM_TYPE_BIT_SIZE]) {
        for (int i = 0; i < BLOCK_SIZE / ELEM_TYPE_BIT_SIZE; ++i) {
            printf("%02X", converted[i]);
            if ((i + 1) % 2 == 0) printf(" ");
        }
    }

    void Encipherer::printSparseBlock(elemType block[BLOCK_SIZE]){
        elemType compactBlock[BLOCK_SIZE / ELEM_TYPE_BIT_SIZE] = { 0 };
        block2hex(block, compactBlock);
        printConvertedBlock(compactBlock);
    }



    // 初始置换
    void Encipherer::initialPermutation(elemType* block, elemType* temp64) {
        for (int i = 0; i < BLOCK_SIZE; ++i) {
            temp64[i] = block[IP_Table[i]];
        }
    }

    void Encipherer::initialPermutation(elemType block[BLOCK_SIZE]) {
        elemType temp[BLOCK_SIZE] = { 0 };
        for (int i = 0; i < BLOCK_SIZE; ++i) {
            temp[i] = block[IP_Table[i]];
        }
        memcpy(block, temp, sizeof(elemType) * BLOCK_SIZE);
    }

    // 初始置换逆置换
    void Encipherer::reversePermutation(elemType* block, elemType* temp64) {
        for (int i = 0; i < BLOCK_SIZE; ++i) {
            temp64[i] = block[IP_1_Table[i]];
        }
    }

    void Encipherer::reversePermutation(elemType block[BLOCK_SIZE]) {
        elemType temp[BLOCK_SIZE] = { 0 };
        for (int i = 0; i < BLOCK_SIZE; ++i) {
            temp[i] = block[IP_1_Table[i]];
        }
        memcpy(block, temp, sizeof(elemType) * BLOCK_SIZE);
    }

    // 加密一个块
    void Encipherer::encipherBlock(elemType block[BLOCK_SIZE]) {
        initialPermutation(block);
#ifdef DEBUG
        cout << "Enciphered block after initialPermutation:\n";
        printSparseBlock(block);
        cout << "\n";
#endif // DEBUG
        for (int i = 0; i < ROUND_N; ++i) {
            round(block, i);
#ifdef DEBUG
            cout << "Enciphered block after round " << i <<":\n";
            printSparseBlock(block);
            cout << "\n";
#endif // DEBUG
        }
        swapLR(block);
#ifdef DEBUG
        cout << "Enciphered block after left-right-swap:\n";
        printSparseBlock(block);
        cout << "\n";
#endif // DEBUG
        reversePermutation(block);
#ifdef DEBUG
        cout << "Enciphered block after reversePermutation:\n";
        printSparseBlock(block);
        cout << "\n";
#endif // DEBUG
    }

    //产生16个子密钥。每当设置新秘钥时调用
    void Encipherer::genSubKey() {
        elemType temp[KEY_LEN_AFTER_P1] = { 0 };
        // 置换选择 1
        for (int i = 0; i < KEY_LEN_AFTER_P1; ++i) {
            temp[i] = key[PC_1[i]]; // TODO 严格来说这里需要对key的正确性进行验证
        }

        for (int i = 0; i < ROUND_N; ++i) {
            // 循环左移  C
            shiftLeft(temp, KEY_HALF_LEN_AFTER_P1, MOVE_TIMES[i]);
            // 循环左移 D
            shiftLeft(temp + KEY_HALF_LEN_AFTER_P1, KEY_HALF_LEN_AFTER_P1, MOVE_TIMES[i]);
            // 置换选择 2 
            replaceSelection2(temp, subkeys + i * SUB_KEY_LEN);
        }

    }

    // 一轮加密
    void Encipherer::round(elemType block[BLOCK_SIZE], int iterCount) {
        elemType eletemps_R[BLOCK_HALF_SIZE] = { 0 };
        memcpy(eletemps_R, block + BLOCK_HALF_SIZE, sizeof(elemType) * BLOCK_HALF_SIZE); // 应该在每轮开始时就把右32位保存起来
        elemType extended[E_SIZE] = { 0 };
        extend(block + BLOCK_HALF_SIZE, extended);
#ifdef DEBUG_ROUND
        printSparseBlock(block);
        cout << "\n";
#endif //DEBUG_ROUND
        xorWithKey(extended, iterCount);
        selectCompression(extended, block + BLOCK_HALF_SIZE);
#ifdef DEBUG_ROUND
        printSparseBlock(block);
        cout << "\n";
#endif //DEBUG_ROUND
        elemType permutated[BLOCK_HALF_SIZE];
        permutation(block + BLOCK_HALF_SIZE, permutated);
#ifdef DEBUG_ROUND
        printSparseBlock(block);
        cout << "\n";
#endif //DEBUG_ROUND
        memcpy(block + BLOCK_HALF_SIZE, permutated, sizeof(elemType) * BLOCK_HALF_SIZE);
#ifdef DEBUG_ROUND
        printSparseBlock(block);
        cout << "\n";
#endif //DEBUG_ROUND
        xorWithLAndSwapLR(block);
        memcpy(block, eletemps_R, sizeof(elemType) * BLOCK_HALF_SIZE);
#ifdef DEBUG_ROUND
        printSparseBlock(block);
        cout << "\n";
#endif //DEBUG_ROUND
    }

    //选择扩展运算
    // blockE:48个字节的elemType数组
    void Encipherer::extend(elemType blockE[BLOCK_HALF_SIZE], elemType tempE[E_SIZE]) {  // 运行的时候会检查写在[48]的数字
        for (int i = 0; i < E_SIZE; ++i) {
            tempE[i] = blockE[E_Table[i]];
        }
    }

    //循环左移
    // shiftcount 
    void Encipherer::shiftLeft(elemType* block, int len, int shiftCount) {
        for (int i = 0; i < shiftCount; ++i) {
            shiftLeftOneBit(block, len);
        }
    }
    // 循环左移一位
    void Encipherer::shiftLeftOneBit(elemType* block, int len) {
        if (len <= 1) return;
        elemType temp = block[len - 1];
        block[len - 1] = block[0];
        for (int i = 1; i <= len - 2; ++i) {
            block[i - 1] = block[i];
        }
        block[len - 2] = temp;
    }

    // 置换选择2
    void Encipherer::replaceSelection2(elemType CD[KEY_LEN_AFTER_P1], elemType target[SUB_KEY_LEN]) {
        for (int i = 0; i < SUB_KEY_LEN; ++i) {
            target[i] = CD[PC_2[i]];
        }
    }

    // 与 子密钥异或,异或的结果仍然存在block里面
    // iterCount 从1开始
    void Encipherer::xorWithKey(elemType blockE[E_SIZE], int iterCount) {
        for (int i = 0; i < E_SIZE; ++i) {
            blockE[i] = blockE[i] ^ subkeys[(iterCount - 1) * SUB_KEY_LEN + i];
        }
    }

    // 选择压缩运算
    void Encipherer::selectCompression(elemType blockE[E_SIZE], elemType target[BLOCK_HALF_SIZE]) {
        for (int i = 0; i < 6; ++i) {
            //for (int j = 0; j < 8; ++j) {
            int row = blockE[i * 6] * 2 + blockE[i * 6 + 5];
            int col = blockE[i * 6 + 1] * 8 +
                blockE[i * 6 + 2] * 4 +
                blockE[i * 6 + 3] * 2 +
                blockE[i * 6 + 4];
            int out = S[i][row][col];
            for (int k = 0; k < 4; ++k) {
                target[i * 4 + k] = (elemType)((out >> (3 - k)) % 2);
            }
            //}
        }
    }

    // 每轮加密中的置换运算
    void Encipherer::permutation(elemType input[BLOCK_HALF_SIZE], elemType target[BLOCK_HALF_SIZE]) {
        for (int i = 0; i < BLOCK_HALF_SIZE; ++i) {
            target[i] = input[P_Table[i]];
        }
    }

    void Encipherer::swapLR(elemType block[BLOCK_SIZE]) {
        elemType temp;
        for (int i = 0; i < BLOCK_HALF_SIZE; ++i) {
            temp = block[i];
            block[i] = block[i + BLOCK_HALF_SIZE];
            block[i + BLOCK_HALF_SIZE] = temp;
        }
    }

    void Encipherer::decipherBlock(elemType block[BLOCK_SIZE], elemType text[8]) {
#ifdef DEBUG
        cout << "In decipherBlock:\n";
        printSparseBlock(block);
        cout << "\n";
#endif // DEBUG
        // 解密过程与加密过程完全类似
        initialPermutation(block);
#ifdef DEBUG
        cout << "Deciphered block after initialPermutation:\n";
        printSparseBlock(block);
        cout << "\n";
#endif // DEBUG
        // 16轮迭代
        for (int i = ROUND_N - 1; i >= 0; --i) {
            round(block, i);
#ifdef DEBUG
            cout << "Deciphered block after round " << i << ":\n";
            printSparseBlock(block);
            cout << "\n";
#endif // DEBUG
        }
        swapLR(block);
#ifdef DEBUG
        cout << "Deciphered block after left-right-swap:\n";
        printSparseBlock(block);
        cout << "\n";
#endif // DEBUG
        reversePermutation(block);
#ifdef DEBUG
        cout << "Dnciphered block after reversePermutation:\n";
        printSparseBlock(block);
        cout << "\n";
#endif // DEBUG
        block2hex(block, text);
    }

    void Encipherer::xorWithLAndSwapLR(elemType block[BLOCK_SIZE]) {
        for (int i = 0; i < BLOCK_HALF_SIZE; ++i) {
            block[BLOCK_HALF_SIZE + i] = block[BLOCK_HALF_SIZE + i] ^ block[i];
        }

        //for (int i = 0; i < BLOCK_HALF_SIZE; ++i) {
        //  elemType temp = block[i];
        //  block[i] = block[BLOCK_HALF_SIZE + i];
        //  block[BLOCK_HALF_SIZE + i] = temp;
        //}
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值