AES对称加密算法原理、C++代码示例

        

目录

基础介绍

一、特点

二、原理

代码示例

Crypto++库

为什么需要安全的密钥管理?

生成密钥

用秘钥加解密

Microsoft CryptoAPI

注意点

OpenSSL 1.1版本

代码解释:

总结


        介绍AES加密以及代码示例        

基础介绍

        高级加密标准(AES,全称:Advanced Encryption Standard)是一种对称加密算法,由美国国家标准与技术研究院(NIST)于2001年发布。它取代了数据加密标准(DES),成为许多政府、企业和机构广泛使用的标准加密方法。AES的主要特点如下:

一、特点

  1. 对称加密:AES是一种对称密钥算法,这意味着加密和解密使用的是同一把密钥。

  2. 块加密:它是一种块加密算法,将数据分割成固定大小的块进行处理。每个数据块都是128位(16字节)。

  3. 可变的密钥长度:AES支持128位、192位和256位的密钥长度。密钥长度越长,安全性越高,但处理的复杂性和计算开销也随之增加。

  4. 结构:AES基于替换-置换网络结构,经过多次重复的轮次进行加密。每一轮包含多种操作,如字节替换、行移位、列混淆和轮密钥加法等。

  5. 轮次数:加密过程的轮次取决于密钥长度,128位密钥需要10轮,192位密钥需要12轮,256位密钥需要14轮。

  6. 安全性:AES经过多年的严格审查,被认为是目前最安全和有效的加密标准之一。其设计使其对多种已知攻击方式具有很好的抵抗能力。

        AES适用于各种需要加密的场合,如互联网通信、无线网络、云存储、数据库保护等。

二、原理

        AES(高级加密标准)是一种分组加密算法,基于替代-置换网络原理。它通过多轮的数学运算,将明文转换为密文。以下是AES的主要原理:

  1. 初始密钥扩展:密钥扩展算法将用户输入的密钥扩展成多个轮密钥,供每一轮加密和解密操作使用。

  2. 分组与轮次数:AES以固定长度128位(16字节)的分组为单位处理数据。根据密钥长度不同,AES的轮数分别是:

    • 10轮:128位密钥
    • 12轮:192位密钥
    • 14轮:256位密钥
  3. 初始轮密钥加:在加密的第一步,原始的明文分组与第一个轮密钥进行异或操作(AddRoundKey),以打乱原始数据。

  4. 主要轮次操作:每轮的操作包含四个主要步骤:

    • 字节代替(SubBytes):使用一个预计算的S盒(替换盒)替换每个字节,将每个输入字节映射到另一个字节,从而增加混淆性。
    • 行移位(ShiftRows):将数据块中每一行的数据循环移位,行号越高移动的位数越多,从而进一步混淆数据。
    • 列混合(MixColumns):将每一列作为一个多项式,在一个预定义的有限域上与一个固定的多项式相乘,进一步打乱数据。此操作不适用于最后一轮加密。
    • 轮密钥加(AddRoundKey):将当前轮次的密钥与经过前面操作处理的数据分组进行异或运算。
  5. 最后一轮:与之前的轮次类似,但不进行列混合操作,以简化最后一轮处理。

        经过所有轮次操作后,最终的输出即为密文。解密过程则反向执行上述步骤,使用逆向的S盒和列混合矩阵。

具体过程可以看:

https://www.cnblogs.com/ffy11/p/16882128.html

代码示例

Crypto++库

Crypto++ Library 8.9 | Free C++ Class Library of Cryptographic Schemes

#include <iostream>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>int main() {using namespace CryptoPP;// 设置密钥和初始化向量,AES的密钥长度可以是16、24或32字节。byte key[AES::DEFAULT_KEYLENGTH], iv[AES::BLOCKSIZE];memset(key, 0x01, AES::DEFAULT_KEYLENGTH);memset(iv, 0x01, AES::BLOCKSIZE);// 明文字符串std::string plain = "Hello, World!";std::string cipher, recovered;// 加密try {CBC_Mode< AES >::Encryption encryptor;encryptor.SetKeyWithIV(key, sizeof(key), iv);// 使用StringSink和StreamTransformationFilter来处理加密StringSource(plain, true,new StreamTransformationFilter(encryptor,new StringSink(cipher)));} catch(const CryptoPP::Exception& e) {std::cerr << e.what() << std::endl;exit(1);}// 解密try {CBC_Mode< AES >::Decryption decryptor;decryptor.SetKeyWithIV(key, sizeof(key), iv);// 使用StringSink和StreamTransformationFilter来处理解密StringSource(cipher, true,new StreamTransformationFilter(decryptor,new StringSink(recovered)));} catch(const CryptoPP::Exception& e) {std::cerr << e.what() << std::endl;exit(1);}// 输出结果std::cout << "Plain Text: " << plain << std::endl;std::cout << "Cipher Text: " << cipher << std::endl;std::cout << "Recovered Text: " << recovered << std::endl;return 0;
}

        在给出的C++示例代码中,密钥(key)和初始化向量(iv)是在程序的开始部分定义和初始化的。这里使用的是非常简单的示例值,通常在实际应用中,你需要使用更加安全的方式来生成和存储这些密钥。以下是代码中相关部分的细节:

byte key[AES::DEFAULT_KEYLENGTH], iv[AES::BLOCKSIZE];
memset(key, 0x01, AES::DEFAULT_KEYLENGTH);
memset(iv, 0x01, AES::BLOCKSIZE);

在这段代码中:

  • key 是用于AES加密和解密的密钥,其长度由 AES::DEFAULT_KEYLENGTH 定义,对于AES通常是16字节(128位)。
  • iv 是初始化向量,用于块密码的工作模式,如CBC模式。它的大小是 AES::BLOCKSIZE,对于AES是16字节。

为什么需要安全的密钥管理?

        在实际应用中,密钥的生成、存储和管理是非常关键的,因为密钥的安全性直接影响到加密系统的整体安全性。以下是一些密钥管理的最佳实践:

  1. 密钥生成:应该使用安全的随机数生成器来生成密钥。
  2. 密钥存储:密钥不应该硬编码在源代码中,而应该使用安全的密钥存储解决方案,例如使用硬件安全模块(HSM)、密钥管理服务(KMS)或其他加密存储方式。
  3. 密钥周期:密钥应该定期更换,以减少被破解的风险。
  4. 密钥的分发和撤销:应有安全的机制来控制密钥的分发给使用者以及在不再需要时撤销密钥。

生成密钥

生成加密和解密的密钥 - .NET | Microsoft Learn

AES加密算法的密钥如何生成?-腾讯云开发者社区

密码学--AES轮函数和密钥生成的步骤呈现_aes密钥生成-CSDN博客

以下是一个符合AES加密标准的256位(32字节)的密钥示例,以十六进制形式表示

9F74ED4BF9A45F990F9058818C559C51A2887A1C2D82B7ADC42619F908ABAC01

        为了安全地生成一个密钥,最好使用一个加密安全的伪随机数生成器(CSPRNG)。Crypto++库提供了多种安全的随机数生成器可以使用。

#include <cryptopp/osrng.h> // 包含随机数生成器的头文件
#include <iostream>int main() {using namespace CryptoPP;// 创建一个随机数生成器AutoSeededRandomPool prng;// 生成密钥SecByteBlock key(AES::DEFAULT_KEYLENGTH);prng.GenerateBlock(key, key.size());// 输出密钥,以十六进制形式查看(实际使用时不应打印密钥)std::cout << "Generated AES key: ";for (int i = 0; i < key.size(); ++i) {std::cout << std::hex << (int)key[i];}std::cout << std::endl;return 0;
}

用秘钥加解密

#include <iostream>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>
#include <cryptopp/hex.h>
#include <cryptopp/secblock.h>int main() {using namespace CryptoPP;// 用于AES的256位密钥(以十六进制字符串形式表示)std::string hexKey = "9F74ED4BF9A45F990F9058818C559C51A2887A1C2D82B7ADC42619F908ABAC01";// 将十六进制字符串转换为字节数组SecByteBlock key(AES::MAX_KEYLENGTH);StringSource(hexKey, true, new HexDecoder(new ArraySink(key, key.size())));// 初始化向量(固定16字节),此处为了简单演示使用全0byte iv[AES::BLOCKSIZE] = {0};// 要加密的明文std::string plaintext = "This is a secret message that needs encryption!";std::string ciphertext, decryptedtext;// 加密try {CBC_Mode<AES>::Encryption encryption;encryption.SetKeyWithIV(key, key.size(), iv);StringSource(plaintext, true,new StreamTransformationFilter(encryption,new StringSink(ciphertext)));} catch (const Exception &e) {std::cerr << "Encryption error: " << e.what() << std::endl;return 1;}// 解密try {CBC_Mode<AES>::Decryption decryption;decryption.SetKeyWithIV(key, key.size(), iv);StringSource(ciphertext, true,new StreamTransformationFilter(decryption,new StringSink(decryptedtext)));} catch (const Exception &e) {std::cerr << "Decryption error: " << e.what() << std::endl;return 1;}// 输出结果std::cout << "Plaintext: " << plaintext << std::endl;std::cout << "Ciphertext (hex): ";std::string hexCiphertext;StringSource(ciphertext, true, new HexEncoder(new StringSink(hexCiphertext)));std::cout << hexCiphertext << std::endl;std::cout << "Decrypted text: " << decryptedtext << std::endl;return 0;
}

Microsoft CryptoAPI

        使用Microsoft CryptoAPI进行AES加密和解密涉及到Windows平台特有的API调用。下面是一个C++示例代码,展示如何使用你提供的256位AES密钥在Windows平台上使用CryptoAPI进行数据的加密和解密。

        首先,确保你的项目链接了Crypt32.libAdvapi32.lib库。

#include <windows.h>
#include <wincrypt.h>
#include <iostream>
#include <vector>
#include <string>// 用于处理错误的帮助函数
void HandleError(const char* message) {std::cerr << message << " Error Code: " << GetLastError() << std::endl;exit(1);
}int main() {HCRYPTPROV hProv = 0;HCRYPTKEY hKey = 0;HCRYPTHASH hHash = 0;// 密钥(以十六进制字符串形式提供)std::string hexKey = "9F74ED4BF9A45F990F9058818C559C51A2887A1C2D82B7ADC42619F908ABAC01";std::vector<BYTE> key;for (size_t i = 0; i < hexKey.length(); i += 2) {std::string byteString = hexKey.substr(i, 2);BYTE b = (BYTE)strtol(byteString.c_str(), nullptr, 16);key.push_back(b);}// 初始化CryptoAPIif (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {HandleError("Error during CryptAcquireContext.");}// 创建哈希对象if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {HandleError("Error during CryptCreateHash.");}// 哈希密钥数据if (!CryptHashData(hHash, key.data(), key.size(), 0)) {HandleError("Error during CryptHashData.");}// 从哈希生成密钥if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) {HandleError("Error during CryptDeriveKey.");}// 明文数据std::string plaintext = "This is a secret message!";std::vector<BYTE> data(plaintext.begin(), plaintext.end());DWORD dataSize = data.size();// 加密数据if (!CryptEncrypt(hKey, 0, TRUE, 0, data.data(), &dataSize, data.size())) {HandleError("Error during CryptEncrypt.");}// 解密数据if (!CryptDecrypt(hKey, 0, TRUE, 0, data.data(), &dataSize)) {HandleError("Error during CryptDecrypt.");}std::string decryptedText((char*)data.data(), dataSize);std::cout << "Decrypted text: " << decryptedText << std::endl;// 清理if (hKey) CryptDestroyKey(hKey);if (hHash) CryptDestroyHash(hHash);if (hProv) CryptReleaseContext(hProv, 0);return 0;
}

注意点

  1. 密钥处理:上述代码直接从十六进制字符串转换密钥。在实际使用中,可能需要更复杂的密钥管理策略。
  2. 错误处理:这个示例中的HandleError函数会输出错误信息并退出程序。实际应用中可能需要更复杂的错误恢复逻辑。
  3. 库链接:确保在项目配置中添加Crypt32.libAdvapi32.lib,以便正确链接所需的Windows加密库。

        此代码示例演示了如何使用CryptoAPI在Windows平台上执行AES加密和解密操作。这种方法利用了Windows内置的安全功能,可以方便地集成到基于Windows的应用程序中。

OpenSSL 1.1版本

        在使用OpenSSL 1.1版本进行AES加密和解密时,首先确保你的开发环境配置了OpenSSL库。下面是一个C++示例,展示如何使用提供的256位AES密钥(以十六进制字符串形式表示)进行AES加密和解密。

#include <iostream>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <vector>
#include <string>// Helper function to convert hex string to byte array
// 辅助函数:用于将十六进制字符串转换为字节数组
std::vector<unsigned char> hex_to_bytes(const std::string& hex) {std::vector<unsigned char> bytes;// 每两个字符代表一个字节for (unsigned int i = 0; i < hex.length(); i += 2) {std::string byteString = hex.substr(i, 2);unsigned char byte = (unsigned char)strtol(byteString.c_str(), nullptr, 16);bytes.push_back(byte); // 将字节添加到结果数组中}return bytes;
}int main() {// 定义并初始化AES的256位密钥,以十六进制字符串形式表示std::string hexKey = "9F74ED4BF9A45F990F9058818C559C51A2887A1C2D82B7ADC42619F908ABAC01";// 使用辅助函数将密钥从十六进制字符串转换为字节数组std::vector<unsigned char> key = hex_to_bytes(hexKey);// 初始化向量(IV):AES块大小为16字节// 这里为了演示,初始化为全0。实际应用中应使用随机生成的IV。unsigned char iv[AES_BLOCK_SIZE] = {};// 明文需要被加密的内容std::string plaintext = "This is a secret message!";// 将明文字符串转换为字节数组std::vector<unsigned char> plaintext_bytes(plaintext.begin(), plaintext.end());// 为密文和解密后的明文预留空间,长度至少比明文长一个块std::vector<unsigned char> ciphertext(plaintext.size() + AES_BLOCK_SIZE);std::vector<unsigned char> decryptedtext(plaintext.size() + AES_BLOCK_SIZE);// 使用OpenSSL EVP接口进行加密操作// 创建EVP加密上下文EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();if (!ctx) {std::cerr << "Failed to create EVP_CIPHER_CTX" << std::endl;return 1;}// 初始化加密操作,指定使用AES-256-CBC算法,传入密钥和IVif (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key.data(), iv)) {std::cerr << "Encryption initialization failed" << std::endl;EVP_CIPHER_CTX_free(ctx);return 1;}int len; // 存储每次操作的结果长度int ciphertext_len; // 最终密文长度// 加密明文并将结果存储到密文数组中if (1 != EVP_EncryptUpdate(ctx, ciphertext.data(), &len, plaintext_bytes.data(), plaintext_bytes.size())) {std::cerr << "Encryption failed" << std::endl;EVP_CIPHER_CTX_free(ctx);return 1;}ciphertext_len = len; // 保存已加密的字节数// 处理最终的填充块if (1 != EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len)) {std::cerr << "Final encryption block failed" << std::endl;EVP_CIPHER_CTX_free(ctx);return 1;}ciphertext_len += len; // 更新密文的最终长度// 释放EVP加密上下文EVP_CIPHER_CTX_free(ctx);// 创建EVP解密上下文ctx = EVP_CIPHER_CTX_new();if (!ctx) {std::cerr << "Failed to create EVP_CIPHER_CTX for decryption" << std::endl;return 1;}// 初始化解密操作,使用与加密时相同的算法、密钥和IVif (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key.data(), iv)) {std::cerr << "Decryption initialization failed" << std::endl;EVP_CIPHER_CTX_free(ctx);return 1;}// 解密密文if (1 != EVP_DecryptUpdate(ctx, decryptedtext.data(), &len, ciphertext.data(), ciphertext_len)) {std::cerr << "Decryption failed" << std::endl;EVP_CIPHER_CTX_free(ctx);return 1;}int decryptedtext_len = len; // 更新已解密的长度// 处理最后的填充块if (1 != EVP_DecryptFinal_ex(ctx, decryptedtext.data() + len, &len)) {std::cerr << "Final decryption block failed" << std::endl;EVP_CIPHER_CTX_free(ctx);return 1;}decryptedtext_len += len; // 更新解密后的最终长度// 释放EVP解密上下文EVP_CIPHER_CTX_free(ctx);// 输出加密和解密结果std::cout << "Plaintext: " << plaintext << std::endl;std::cout << "Decrypted text: " << std::string(decryptedtext.begin(), decryptedtext.begin() + decryptedtext_len) << std::endl;return 0;
}

代码解释:

  1. 初始化上下文:加密和解密的核心是EVP_CIPHER_CTX结构,通过EVP_CIPHER_CTX_new()来分配和初始化上下文。
  2. 加密初始化:通过EVP_EncryptInit_ex()指定加密算法、密钥和IV。
  3. 加密数据:使用EVP_EncryptUpdate()加密主要部分,EVP_EncryptFinal_ex()处理填充块。
  4. 解密初始化:类似加密操作,通过EVP_DecryptInit_ex()初始化。
  5. 解密数据:用EVP_DecryptUpdate()解密主要部分,用EVP_DecryptFinal_ex()处理填充块。
  6. 错误处理:代码在每个主要操作后都有错误处理,输出错误消息并释放资源。

这样使用OpenSSL可以确保数据的加密和解密安全有效。

总结

        AES (Advanced Encryption Standard) 是一种对称加密算法,由 NIST 于 2001 年发布,取代了 DES。它通过多轮数学操作将明文转换为密文,密钥长度为 128、192 或 256 位。主要步骤包括字节代替、行移位、列混合和轮密钥加。关键的密钥管理实践包括随机生成、妥善存储、定期更换和安全分发。可通过 C++ 的 Crypto++ 库、Microsoft CryptoAPI 和 OpenSSL 实现 AES 加密与解密。加密技术应确保数据安全,代码示例强调了正确的上下文初始化和错误处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/11210.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

知识付费系统怎么安装教程,教师课堂教学该掌握哪些表达技巧?

课堂教学语言表达是教学艺术的一个基本且重要的组成部分。教师向学生传道、授业、解惑以及师生之间信息的传递和情感的交流&#xff0c;都离不开运用教学语言这一有力的工具&#xff0c;在课堂上&#xff0c;教师通过情趣盎然的表述&#xff0c;鞭辟入里的分析&#xff0c;恰到…

VR030AA080V01V02比例减压阀控制器

MAGNET-SCHULTZ比例阀是一种用于液压控制系统的装置&#xff0c;它能够根据输入信号自动调节输出的比例&#xff0c;常应用于流量、压力和温度等参数的控制。机械制造业中BEUEC比例放大器用于确保机械操作的精准度和重复性。MAGNET-SCHULTZ比例阀VR030AA080V01V01、VR030AA080V…

聚观早报 | 比亚迪海狮07 EV上市;苹果将升级Siri

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 5月13日消息 比亚迪海狮07 EV上市 苹果将升级Siri OpenAI开发全新技术 沃尔沃EX30车型将上市 SpaceX计划新建发…

ICLR 2024落幕,一文了解ICLR + 历年(2017-2024) 论文整理(含源码!)

来源: AINLPer公众号&#xff08;每日干货分享&#xff01;&#xff01;&#xff09; 编辑: ShuYini 校稿: ShuYini 时间: 2024-5-13 引言 最近这几天&#xff0c;相信大家都或多或少的刷到了ICLR 2024这个关键词。对于刚刚入门的小伙伴或对此并没有深入的理解&#xff0c;只知…

p6spy-starter springboot快速引入p6spy简单配置即可自动替换数据源

p6spy-starter 通过属性配置便可以自动替换springboot数据源中p6spy的配置(支持常见数据库).项目地址 https://github.com/joker-pper/p6spy-starter 功能介绍 仅对springboot中的环境变量配置进行自动替换 (p6spy使用方式与原来一致) 无需改变原数据源配置内容便可实现引入…

【C++】————类与对象(上)-基础知识

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 类的两种定义方式&#xff1a; 成员变量命名规则的建议&#xff1a; 4.类的访问限定符及封装 4.1 访问限定符 ​编辑 【面试题】问题&#xff1a;C中struct和class的区别是什么&#xff1f; 4.2 封装 【面试…

李廉洋:5.13黄金原油消息面面和行情分析,必看策略。

黄金方面&#xff1a;月初公布的美国非农等就业市场数据比较弱势&#xff0c;显示美国就业市场开始走软&#xff0c;美联储在就业市场开始变差的背景下&#xff0c;存在提前降息的可能性&#xff0c;这有利于推动金价走高。The         近期公布的美国5月密歇根大学消费者…

创新案例|为何农夫山泉创新战略升级为一家零售科技公司

农夫山泉上市的消息被公之于众后&#xff0c;几乎所有人都将目光投向了这家国内家喻户晓的饮料公司&#xff0c;谁都想第一时间内窥探它的庐山真面目。 当然&#xff0c;在此之前已经有多路消息通过旁敲侧击&#xff0c;从管窥中获取了一些农夫山泉的真实数据。 去年6月&…

Maven:Maven基础

Maven apache旗下的一个开源项目,一款用于管理和构建java项目的工具 什么是Maven 一个项目管理和构建工具,基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建,报告和文档. Maven的作用 依赖管理 方便快捷的管理项目依赖的资源jar包,避免版本冲突问题 统一…

加州大学欧文分校英语高级语法专项课程01:Verb Tenses and Passives 学习笔记

Verb Tenses and Passives Course Certificate Course Intro 本文是学习 Verb Tenses and Passives 这门课的学习笔记。 文章目录 Verb Tenses and PassivesWeek 01: Simple, Progressive, and Perfect Verb Tenses ReviewLearning Objectives Present Perfect Tense Review L…

【动态规划四】子序列问题

目录 leetcode题目 一、最长递增子序列 二、摆动序列 三、最长递增子序列的个数 四、最长数对链 五、最长定差子序列 六、最长的斐波那契子序列的长度 七、最长等差数列 八、等差数列划分 II leetcode题目 一、最长递增子序列 300. 最长递增子序列 - 力扣&#xff0…

Java入门——继承和多态(中)

组合 和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果. public class Student { ... } public class Teacher { ... } public class School { public Student[] students; public Teacher[] teachers; } 组合并没有涉及到特殊的语法(诸如 ex…

2023愚人杯 )————被遗忘的反序列化

<?php# 当前目录中有一个txt文件哦 error_reporting(0); show_source(__FILE__); include("check.php");class EeE{public $text;public $eeee;public function __wakeup(){if ($this->text "aaaa"){echo lcfirst($this->text);}}public functi…

量化交易:日内网格交易策略.md

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 本文将详细介绍日内网格交易策略的原理&#xff0c;并结合Python代码示例&#xff0c;展示如何在掘金平台上实现这一策略。 策略原理 日内网格交易策略的核心思想是在一天的交易时间内&#xff0c;通过设置多个买卖…

HttpServletRequest对象

1.作用 主要作用是用来接收客户端发送过来的请求信息&#xff0c;由servlet容器封装好传递给service()方法 2.常用方法 常用方法描述StringBuffer getRequestURL()获取客户端发送请求时的完整URLString getRequestURI()获取请求行中的资源名称部分&#xff08;项目名称开始&…

C#字符串的拼接

在C#中有多种拼接字符串的方式&#xff0c;今天小编就分享一些比较常用的。 方法1 string str "123"; str str "456"; 运行结果: "123456" 方法2 字符串与数字拼接 会将数字默认为字符串进行拼接 string str "123"; str str 1;…

【谷粒商城】02安装和配置git

1.下载和安装git 地址&#xff1a;https://git-scm.com/download/win 傻瓜式安装 2.配置git DELLLJL MINGW64 ~/Desktop $ git config --global user.name "yufuabu"DELLLJL MINGW64 ~/Desktop $ git config --global user.email "463999534qq.com"DELL…

详解循环队列——链表与数组双版本

前言&#xff1a;本节内容主要是讲解循环队列。 在本篇中会讲到两个版本——数组版本、链表版本。本篇内容适合正在学习数据结构队列章节或者已经学过队列但对循环队列感觉模糊的友友们 。 首先先来看一下什么是循环队列 什么是循环队列 因为是刚开始讲解&#xff0c; 所以我们…

git知识总结

要知道 本地回退后&#xff0c;反悔了&#xff0c;可以恢复。前提是已经提交了&#xff0c;提交了就丢不了。 git reflog git reset --hard commitId 以前git push不让推&#xff0c;就是没有对应关系。第一次推要setxxx参数。 前奏 设置用户名和邮箱&#xff0c;设置错…

新闻标题抓取

要从新闻⽹站⾸⻚抓取最新的新闻标题和链接&#xff0c;可以使⽤ requests 库获取⽹⻚内容&#xff0c;然后利⽤ BeautifulSoup 解析HTML&#xff0c;提取新闻标题和相应的链接。 由于新闻⽹站的结构可能不断变化&#xff0c;且每个⽹站的结构不同&#xff0c;这⾥提供的代码仅…