C/C++字符串定义的五种写法 和 C/C++字符串隐藏技术深度剖析

文章目录

  • C/C++字符串定义的五种写法:深入理解内存与语义
  • 从逆向工程角度看:C/C++字符串隐藏技术深度剖析
    • 引言
    • [1. 逆向工程基础:如何定位字符串](#1. 逆向工程基础:如何定位字符串)
      • [1.1 静态分析中的字符串提取](#1.1 静态分析中的字符串提取)
      • [1.2 字符串在二进制中的存储形式](#1.2 字符串在二进制中的存储形式)
    • [2. 五种字符串定义方式的逆向可见性分析](#2. 五种字符串定义方式的逆向可见性分析)
      • [2.1 字符串常量指针 - **高度可见**](#2.1 字符串常量指针 - 高度可见)
      • [2.2 字符数组(逐个字符)- **中等可见**](#2.2 字符数组(逐个字符)- 中等可见)
      • [2.3 字符串指针数组 - **高度可见**](#2.3 字符串指针数组 - 高度可见)
      • [2.4 二维字符数组(字面量)- **中等可见**](#2.4 二维字符数组(字面量)- 中等可见)
      • [2.5 二维字符数组(逐个字符)- **较好隐藏**](#2.5 二维字符数组(逐个字符)- 较好隐藏)
    • [3. 字符串隐藏技术深度剖析](#3. 字符串隐藏技术深度剖析)
      • [3.1 运行时动态构建](#3.1 运行时动态构建)
      • [3.2 XOR 加密](#3.2 XOR 加密)
      • [3.3 多段分散 + 动态组合](#3.3 多段分散 + 动态组合)
      • [3.4 高级隐藏:混淆 + 多重加密](#3.4 高级隐藏:混淆 + 多重加密)
    • [4. 实战对比:相同字符串的不同定义方式](#4. 实战对比:相同字符串的不同定义方式)
      • [4.1 明文方式(易被逆向)](#4.1 明文方式(易被逆向))
      • [4.2 简单隐藏方式](#4.2 简单隐藏方式)
      • [4.3 高级隐藏方式](#4.3 高级隐藏方式)
    • [5. 逆向工程视角的字符串隐藏评估](#5. 逆向工程视角的字符串隐藏评估)
      • [5.1 各种方法的隐藏效果评分](#5.1 各种方法的隐藏效果评分)
      • [5.2 逆向工程师的应对策略](#5.2 逆向工程师的应对策略)
    • [6. 实战建议:根据需求选择合适方案](#6. 实战建议:根据需求选择合适方案)
      • [6.1 不同场景的隐藏需求](#6.1 不同场景的隐藏需求)
      • [6.2 性能与安全的平衡](#6.2 性能与安全的平衡)
    • [7. 总结](#7. 总结)
      • [7.1 各种定义方式的逆向可见性总结](#7.1 各种定义方式的逆向可见性总结)
      • [7.2 最终建议](#7.2 最终建议)

C/C++字符串定义的五种写法:深入理解内存与语义

引言

在C/C++编程中,字符串的定义方式多种多样,每种方式背后都涉及不同的内存布局、可修改性和使用场景。很多初学者(甚至一些有经验的开发者)都可能对这些写法感到困惑。本文将深入剖析五种常见的字符串定义方式,帮助您彻底理解它们的区别。

文章目录

  • C/C++字符串定义的五种写法:深入理解内存与语义
  • 从逆向工程角度看:C/C++字符串隐藏技术深度剖析
    • 引言
    • [1. 逆向工程基础:如何定位字符串](#1. 逆向工程基础:如何定位字符串)
      • [1.1 静态分析中的字符串提取](#1.1 静态分析中的字符串提取)
      • [1.2 字符串在二进制中的存储形式](#1.2 字符串在二进制中的存储形式)
    • [2. 五种字符串定义方式的逆向可见性分析](#2. 五种字符串定义方式的逆向可见性分析)
      • [2.1 字符串常量指针 - **高度可见**](#2.1 字符串常量指针 - 高度可见)
      • [2.2 字符数组(逐个字符)- **中等可见**](#2.2 字符数组(逐个字符)- 中等可见)
      • [2.3 字符串指针数组 - **高度可见**](#2.3 字符串指针数组 - 高度可见)
      • [2.4 二维字符数组(字面量)- **中等可见**](#2.4 二维字符数组(字面量)- 中等可见)
      • [2.5 二维字符数组(逐个字符)- **较好隐藏**](#2.5 二维字符数组(逐个字符)- 较好隐藏)
    • [3. 字符串隐藏技术深度剖析](#3. 字符串隐藏技术深度剖析)
      • [3.1 运行时动态构建](#3.1 运行时动态构建)
      • [3.2 XOR 加密](#3.2 XOR 加密)
      • [3.3 多段分散 + 动态组合](#3.3 多段分散 + 动态组合)
      • [3.4 高级隐藏:混淆 + 多重加密](#3.4 高级隐藏:混淆 + 多重加密)
    • [4. 实战对比:相同字符串的不同定义方式](#4. 实战对比:相同字符串的不同定义方式)
      • [4.1 明文方式(易被逆向)](#4.1 明文方式(易被逆向))
      • [4.2 简单隐藏方式](#4.2 简单隐藏方式)
      • [4.3 高级隐藏方式](#4.3 高级隐藏方式)
    • [5. 逆向工程视角的字符串隐藏评估](#5. 逆向工程视角的字符串隐藏评估)
      • [5.1 各种方法的隐藏效果评分](#5.1 各种方法的隐藏效果评分)
      • [5.2 逆向工程师的应对策略](#5.2 逆向工程师的应对策略)
    • [6. 实战建议:根据需求选择合适方案](#6. 实战建议:根据需求选择合适方案)
      • [6.1 不同场景的隐藏需求](#6.1 不同场景的隐藏需求)
      • [6.2 性能与安全的平衡](#6.2 性能与安全的平衡)
    • [7. 总结](#7. 总结)
      • [7.1 各种定义方式的逆向可见性总结](#7.1 各种定义方式的逆向可见性总结)
      • [7.2 最终建议](#7.2 最终建议)

1. 字符串常量指针

cpp 复制代码
const char* status_message = "Operation successful";

内存分析

  • 字符串内容"Operation successful" 存储在程序的只读数据段(常量区)
  • 指针变量status_message 存储在上,占用4或8字节(取决于系统位数)
  • 生命周期:字符串常量在整个程序运行期间都存在

特点

  • 只读:不能修改字符串内容(const修饰)
  • 可重指向:指针本身可以指向其他字符串
  • 内存效率高:相同字符串常量可能被多个指针共享
  • 内容不可修改:任何修改尝试都会导致运行时错误

示例

cpp 复制代码
status_message = "New message";  // ✅ 可以,指针重新指向
// status_message[0] = 'O';      // ❌ 错误:不能修改只读内存

2. 字符数组(逐个字符初始化)

cpp 复制代码
char command_buffer[] = {'l','o','g','i','n','_','u','s','e','r','\0'};

内存分析

  • 存储位置 :完全在上分配
  • 数组大小:由初始化列表自动确定(这里是11字节)
  • 初始化方式 :逐个字符指定,需要手动添加\0

特点

  • 完全可修改:可以任意修改数组中的字符
  • 自动管理:栈上的内存会自动释放
  • 手动添加'\0':容易忘记导致字符串函数出错
  • 固定大小:不能存储超过数组大小的字符串

示例

cpp 复制代码
command_buffer[0] = 'L';           // ✅ 可以修改
command_buffer[1] = 'O';           // ✅ 修改为大写
cout << command_buffer;             // 输出:"LOgin_user"

3. 字符串指针数组

cpp 复制代码
const char* menu_options[] = {
    "1. Start Game",
    "2. Load Game", 
    "3. Settings",
    "4. Exit"
};

内存分析

  • 数组本身 :存储在上,每个元素是一个指针(4或8字节)
  • 字符串内容 :每个字符串存储在只读数据段
  • 指针指向:数组中的每个指针指向只读区中的字符串

特点

  • 内存效率高:字符串只存一份,多个指针可共享
  • 灵活:可以重新排列指针顺序,或指向新字符串
  • 只读内容:字符串本身不能修改(const修饰)
  • 适合菜单、选项等固定字符串集合

示例

cpp 复制代码
menu_options[0] = "0. New Option";  // ✅ 可以,指针重指向
// menu_options[0][0] = '0';        // ❌ 错误:不能修改只读内存

4. 二维字符数组(字符串字面量初始化)

cpp 复制代码
char user_database[3][20] = {
    "admin",
    "guest_user", 
    "test_account"
};

内存分析

  • 存储位置 :连续的3×20字节内存块在
  • 初始化过程 :字符串字面量被复制到数组中
  • 空间占用:每行固定20字节,即使字符串较短

特点

  • 完全可修改:每个字符都可以修改
  • 自动添加'\0':编译器自动在末尾添加结束符
  • 内存浪费:短字符串也会占用完整行大小
  • 适合用户数据库、配置项等需要修改的字符串集合

示例

cpp 复制代码
user_database[0][0] = 'A';          // ✅ 可以修改
user_database[0][1] = 'D';          // 修改为"Admin"
strcpy(user_database[0], "root");    // ✅ 可以复制新字符串

5. 二维字符数组(逐个字符初始化)

cpp 复制代码
char system_logs[3][20] = {
    {'S','t','a','r','t','u','p',' ','O','K','\0'},
    {'I','n','i','t',' ','D','e','v','i','c','e','s','\0'},
    {'L','o','a','d',' ','C','o','n','f','i','g','\0'}
};

内存分析

  • 与第4种方式完全相同的内存布局
  • 只是初始化方式不同:逐个字符指定

特点

  • 精确控制:可以精确指定每个字符
  • 可修改:内容完全可修改
  • 繁琐:写法冗长,容易出错
  • 手动'\0':需要自己添加字符串结束符
  • 难以维护:修改字符串内容很麻烦

示例

cpp 复制代码
system_logs[0][0] = 's';            // ✅ 可以修改
// 但不方便修改整个字符串
// system_logs[0] = "New log";      // ❌ 错误:不能直接赋值

6. 内存布局对比

示意图

复制代码
只读数据段(常量区):
0x1000: "Operation successful"
0x1020: "1. Start Game"
0x1030: "2. Load Game"
0x1040: "3. Settings"
0x1050: "4. Exit"

栈内存:
0x7ff0: status_message = 0x1000
0x7ff8: command_buffer = [l][o][g][i][n][_][u][s][e][r][\0]
0x8000: menu_options[0] = 0x1020
0x8008: menu_options[1] = 0x1030
0x8010: menu_options[2] = 0x1040
0x8018: menu_options[3] = 0x1050
0x8020: user_database[0] = [a][d][m][i][n][\0][ ][ ][ ]...
0x8034: user_database[1] = [g][u][e][s][t][_][u][s][e][r][\0][ ]...
0x8048: user_database[2] = [t][e][s][t][_][a][c][c][o][u][n][t][\0]...

内存占用对比(示例数据)

定义方式 存储位置 占用空间 可修改
const char* p = "Hello" 指针在栈(8B),字符串在只读区(6B) 14B
char arr[] = "Hello" 栈上连续6B 6B
const char* arr[] 指针数组(4×8=32B),字符串在只读区 32B + 字符串
char arr[3][10] 栈上连续30B 30B

7. 完整示例代码

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

int main() {
    // 1. 字符串常量指针
    const char* status_message = "Operation successful";
    cout << "1. 字符串常量指针: " << status_message << endl;
    // status_message[0] = 'o';  // 错误!不能修改
    
    // 2. 字符数组(逐个字符)
    char command_buffer[] = {'l','o','g','i','n','_','u','s','e','r','\0'};
    command_buffer[0] = 'L';  // 可以修改
    command_buffer[1] = 'O';
    cout << "2. 字符数组: " << command_buffer << endl;
    
    // 3. 字符串指针数组
    const char* menu_options[] = {
        "1. Start Game",
        "2. Load Game",
        "3. Settings",
        "4. Exit"
    };
    cout << "3. 指针数组第一个选项: " << menu_options[0] << endl;
    
    // 4. 二维字符数组(字面量初始化)
    char user_database[3][20] = {
        "admin",
        "guest_user",
        "test_account"
    };
    strcpy(user_database[0], "root");  // 可以修改
    cout << "4. 二维数组第一个用户: " << user_database[0] << endl;
    
    // 5. 二维字符数组(逐个字符)
    char system_logs[3][20] = {
        {'S','t','a','r','t','u','p',' ','O','K','\0'},
        {'I','n','i','t',' ','D','e','v','i','c','e','s','\0'},
        {'L','o','a','d',' ','C','o','n','f','i','g','\0'}
    };
    system_logs[0][0] = 's';  // 可以修改
    cout << "5. 二维数组第一个日志: " << system_logs[0] << endl;
    
    // 验证内存地址
    cout << "\n=== 内存地址验证 ===" << endl;
    cout << "status_message 指向地址: " << (void*)status_message << endl;
    cout << "command_buffer 地址: " << (void*)command_buffer << endl;
    cout << "menu_options[0] 指向地址: " << (void*)menu_options[0] << endl;
    cout << "user_database[0] 地址: " << (void*)user_database[0] << endl;
    
    return 0;
}

8. 总结与选择建议

快速决策树







需要定义字符串
需要修改内容吗?
需要多个字符串吗?
使用 const char*
字符串长度固定吗?
使用字符数组
使用二维字符数组
使用指针数组

详细选择指南

使用场景 推荐写法 原因
错误信息、提示语 const char* 只读、可共享、内存效率高
需要修改的单个字符串 char[] 可修改、栈上分配
菜单选项、命令列表 const char*[] 只读集合、内存效率高
用户数据库、配置表 char[][N] 需要修改、固定长度
精确控制每个字符 char[][] + 逐个字符 特殊格式需求

关键要点

  1. 只读 vs 可写 :有const的字符串常量不能修改,没有const的数组可以修改
  2. 内存位置:字符串常量在只读段,字符数组在栈上
  3. 结束符'\0':字符串字面量自动带'\0',字符列表需要手动添加
  4. 内存效率:指针数组节省空间(共享字符串),二维数组占用连续空间
  5. 灵活性:指针数组可以重新排列,二维数组大小固定

理解这些区别不仅能帮助您写出更正确的代码,还能在性能优化和内存管理方面做出更好的决策。希望本文对您有所帮助!



从逆向工程角度看:C/C++字符串隐藏技术深度剖析

引言

在软件逆向工程领域,字符串往往是最关键的突破口。恶意软件分析师、漏洞研究者、破解者通常会从字符串入手分析程序功能。本文将深入探讨不同字符串定义方式在逆向视角下的表现,以及如何通过特定技术隐藏字符串,增加逆向分析难度。


1. 逆向工程基础:如何定位字符串

1.1 静态分析中的字符串提取

逆向工程师通常使用以下工具提取字符串:

  • Linux : strings 命令
  • Windows: IDA Pro、Ghidra 的字符串窗口
  • 通用: 十六进制编辑器直接查看二进制

1.2 字符串在二进制中的存储形式

bash 复制代码
# 使用 strings 命令查看编译后的程序
$ strings myprogram
Operation successful
login_user
1. Start Game
2. Load Game
3. Settings
4. Exit
admin
guest_user
test_account
Startup OK
Init Devices
Load Config

2. 五种字符串定义方式的逆向可见性分析

2.1 字符串常量指针 - 高度可见

cpp 复制代码
const char* status_message = "Operation successful";

逆向视角

  • 极易被发现 :字符串完整地存储在.rodata
  • strings命令直接显示
  • ✅ 在IDA中自动识别为字符串

二进制中的样子

assembly 复制代码
.rodata:0000000000402000 4F 70 65 72 61 74 69 6F 6E 20 73 75 63 63 65 73 Operation succes
.rodata:0000000000402010 73 66 75 6C 00                               sful.

2.2 字符数组(逐个字符)- 中等可见

cpp 复制代码
char command_buffer[] = {'l','o','g','i','n','_','u','s','e','r','\0'};

逆向视角

  • ⚠️ 部分隐藏:字符作为立即数存储在代码段
  • ⚠️ 不会出现在.rodata
  • ⚠️ strings命令可能不会直接显示

二进制中的样子

assembly 复制代码
.text:0000000000401150 6C 6F 67 69 6E 5F 75 75 73 65 72 00  ; login_user
; 注意:这些字节在代码段中,可能被误认为是指令

2.3 字符串指针数组 - 高度可见

cpp 复制代码
const char* menu_options[] = {
    "1. Start Game",
    "2. Load Game",
    // ...
};

逆向视角

  • 极易被发现 :所有字符串都在.rodata
  • ✅ 字符串表清晰可见
  • ✅ 可以轻易看出程序功能

2.4 二维字符数组(字面量)- 中等可见

cpp 复制代码
char user_database[3][20] = {
    "admin",
    "guest_user",
    "test_account"
};

逆向视角

  • ⚠️ 部分隐藏 :字符串在.data段(可读写)
  • ⚠️ 仍然以明文形式存在
  • ⚠️ strings命令仍能提取

2.5 二维字符数组(逐个字符)- 较好隐藏

cpp 复制代码
char system_logs[3][20] = {
    {'S','t','a','r','t','u','p',' ','O','K','\0'},
    // ...
};

逆向视角

  • 较好隐藏:字符作为立即数分散在代码段
  • ✅ 不会形成连续的字符串表
  • ⚠️ 熟练的逆向工程师仍可识别模式

3. 字符串隐藏技术深度剖析

3.1 运行时动态构建

cpp 复制代码
// 隐藏字符串 - 运行时拼接
char password[20];
password[0] = 's';
password[1] = 'e';
password[2] = 'c';
password[3] = 'r';
password[4] = 'e';
password[5] = 't';
password[6] = '\0';

逆向难度 :⭐⭐⭐
优点 :字符串不在二进制中连续出现
缺点:代码模式明显,可被自动化脚本识别

3.2 XOR 加密

cpp 复制代码
// 加密的字符串数据
unsigned char encrypted_key[] = {
    0x1D, 0x2A, 0x3B, 0x18, 0x0F, 0x3E, 0x2C, 0x00
};

void decrypt(char* dest, unsigned char* src, char key) {
    while (*src) {
        *dest++ = *src++ ^ key;
    }
    *dest = '\0';
}

// 使用
char real_key[20];
decrypt(real_key, encrypted_key, 0x5A);

逆向难度 :⭐⭐⭐⭐
优点 :字符串完全加密,需要动态分析或识别解密算法
缺点:解密密钥和算法本身可能被识别

3.3 多段分散 + 动态组合

cpp 复制代码
// 字符串片段分散在代码各处
const char* part1 = "ad";
const char* part2 = "mi";
const char* part3 = "n";

// 运行时组合
char username[10];
strcpy(username, part1);
strcat(username, part2);
strcat(username, part3);

逆向难度 :⭐⭐⭐
优点 :破坏字符串连续性
缺点:仍存在多个可识别的字符串片段

3.4 高级隐藏:混淆 + 多重加密

cpp 复制代码
// 复杂混淆示例
class StringObfuscator {
private:
    static const unsigned char _key = 0x7F;
    
    template<size_t N>
    struct ObfuscatedString {
        char data[N];
        
        constexpr ObfuscatedString(const char* str) {
            for(size_t i = 0; i < N; i++) {
                data[i] = str[i] ^ _key;
            }
        }
    };
    
public:
    template<size_t N>
    static const char* get(const ObfuscatedString<N>& obf) {
        static char decrypted[N];
        for(size_t i = 0; i < N; i++) {
            decrypted[i] = obf.data[i] ^ _key;
        }
        return decrypted;
    }
};

// 使用
#define OBF_STRING(str) StringObfuscator::get( \
    StringObfuscator::ObfuscatedString<sizeof(str)>(str))

int main() {
    // 字符串在二进制中是加密的
    const char* hidden = OBF_STRING("SuperSecretPassword123");
    cout << hidden << endl;
}

逆向难度 :⭐⭐⭐⭐⭐
优点 :字符串完全加密,需要理解整个混淆机制
缺点:增加代码复杂度和运行时开销


4. 实战对比:相同字符串的不同定义方式

4.1 明文方式(易被逆向)

cpp 复制代码
// 编译后 strings 直接显示
const char* api_url = "https://api.example.com/v1/secret";
const char* api_key = "sk_live_123456789abcdef";

4.2 简单隐藏方式

cpp 复制代码
// 编译后 strings 看不到完整字符串
char api_url[50];
api_url[0] = 'h'; api_url[1] = 't'; api_url[2] = 't'; api_url[3] = 'p';
// ... 继续逐个字符

4.3 高级隐藏方式

cpp 复制代码
// 编译后完全看不到明文字符串
unsigned char encrypted_api[] = {
    0x1A, 0x2B, 0x38, 0x3D, 0x2E, 0x3F, 0x28, 0x31,  // 加密数据
    0x2C, 0x3B, 0x1E, 0x2D, 0x3C, 0x1F, 0x2A, 0x39,
    0x00
};

void secure_api_call() {
    char real_url[50];
    for(int i = 0; encrypted_api[i]; i++) {
        real_url[i] = encrypted_api[i] ^ 0x55;
    }
    // 使用 real_url
}

5. 逆向工程视角的字符串隐藏评估

5.1 各种方法的隐藏效果评分

方法 静态分析难度 动态分析难度 实现复杂度 性能影响
字符串常量 ⭐ (极易)
逐个字符数组 ⭐⭐ ⭐⭐ ⭐⭐
XOR加密 ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐
多段组合 ⭐⭐ ⭐⭐⭐ ⭐⭐
多重混淆 ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
动态解密 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐

5.2 逆向工程师的应对策略

作为防御者(代码作者),需要了解攻击者的方法:

  1. API监控 :监控敏感API调用(如CreateFileRegOpenKeyEx
  2. 内存转储:在字符串解密后dump内存
  3. 调试跟踪:动态调试追踪解密过程
  4. 模式识别:识别常见的XOR、Base64等模式

6. 实战建议:根据需求选择合适方案

6.1 不同场景的隐藏需求

cpp 复制代码
// 场景1:开源软件 - 不需要隐藏
const char* version = "v1.2.3";

// 场景2:商业软件 - 基本混淆即可
char license_key[] = {0x45, 0x23, 0x67, ...};  // 简单XOR

// 场景3:恶意软件 - 需要强混淆
class AdvancedObfuscator {
    // 多重加密、动态解密、反调试检查
};

// 场景4:保护API密钥 - 中等强度
class APIKeyProtector {
    static const char* getKey() {
        static bool decrypted = false;
        static char key[64];
        if(!decrypted) {
            // 多层解密
            xor_decrypt(first_layer, key1);
            base64_decode(second_layer, key2);
            decrypted = true;
        }
        return key;
    }
};

6.2 性能与安全的平衡

cpp 复制代码
// 缓存解密结果,避免重复解密
class StringCache {
private:
    unordered_map<string, string> cache;
    
public:
    const char* get(const char* encrypted, char key) {
        auto it = cache.find(encrypted);
        if(it != cache.end()) {
            return it->second.c_str();
        }
        
        string decrypted;
        // 解密过程
        cache[encrypted] = decrypted;
        return cache[encrypted].c_str();
    }
};

7. 总结

7.1 各种定义方式的逆向可见性总结

定义方式 strings可见 内存连续 修改难度 逆向难度
const char* ✅ 完全可见 只读 极低
char[]字面量 ✅ 完全可见 可写
char[]逐个字符 ⚠️ 部分可见 可写
const char*[] ✅ 完全可见 指针不连续 只读
char[][]字面量 ✅ 完全可见 可写
char[][]逐个字符 ⚠️ 可能隐藏 可写

7.2 最终建议

  1. 常规应用:无需刻意隐藏,使用最清晰的写法
  2. 保护敏感信息:至少使用XOR加密
  3. 高安全性要求:使用多层混淆 + 动态解密
  4. 反逆向工程:结合反调试、代码混淆、字符串加密等多重手段

记住:没有绝对安全的字符串隐藏,只能增加逆向分析的难度和时间成本。选择适合你应用场景的平衡点才是关键。


本文仅供学习研究使用,请勿用于非法目的。在保护自己代码的同时,也要尊重他人的知识产权。

相关推荐
sycmancia2 小时前
C++——初始化列表的使用
开发语言·c++
白太岁2 小时前
Redis:(3) Lua 与 Redis、基于连接池的 Facade 模式封装
数据库·c++·redis·lua·外观模式
『往事』&白驹过隙;2 小时前
系统编程的内存零拷贝(Zero-Copy)技术
linux·c语言·网络·c++·物联网·iot
量子炒饭大师2 小时前
【C++入门】Cyber高维的蜂巢意识 —— 【类与对象】static 成员
开发语言·c++·静态成员变量·static成员
ShineWinsu2 小时前
对于stack和queue经典算法题目:155. 最小栈、JZ31 栈的压入、弹出序列和102. 二叉树的层序遍历的解析
数据结构·c++·算法·面试·力扣·笔试·牛客网
SWAGGY..2 小时前
【c++初阶】:(1)c++入门基础知识
开发语言·c++
0 0 03 小时前
CCF-CSP 40-3 图片解码(decode)【C++】考点:矩阵翻转/旋转
开发语言·c++·矩阵
星火开发设计3 小时前
序列式容器:list 双向链表的特性与用法
开发语言·前端·数据结构·数据库·c++·链表·list
程序员敲代码吗3 小时前
Qt Quick中QML与C++交互详解及场景切换实现
c++·qt·交互