【C++ 从基础到项目实战】C++(二):数组、字符串与结构体——组织数据的容器

📌 阅读时长:25分钟 | 关键词:C++、数组、二维数组、C风格字符串、std::string、结构体、枚举

引言

上一篇文章我们学会了用指针和引用来操控单个变量。但现实中,我们往往要处理一堆数据------全班 50 个学生的成绩、一段文本、一个商品的信息。这篇就来学习 C++ 组织数据的核心工具:数组、字符串和结构体。

一、一维数组:同类型数据的集合

1.1 声明与初始化

cpp 复制代码
int scores[5] = {80, 90, 75, 85, 95};  // 完整初始化
int nums[5] = {1, 2};                   // 部分初始化:剩余自动补 0
int data[] = {10, 20, 30};              // 省略大小,编译器自动推断为 3

1.2 下标访问与遍历

C++ 数组下标从 0 开始,访问越界会导致未定义行为(程序崩溃或数据错乱):

cpp 复制代码
int arr[5] = {10, 20, 30, 40, 50};

// for 循环遍历
for (int i = 0; i < 5; i++) {
    std::cout << arr[i] << " ";
}
// 输出:10 20 30 40 50

计算数组元素的平均值:

cpp 复制代码
int numbers[5] = {10, 20, 30, 40, 50};
int sum = 0;
for (int i = 0; i < 5; i++) {
    sum += numbers[i];
}
double avg = static_cast<double>(sum) / 5;
std::cout << "平均值为: " << avg << std::endl;  // 30

1.3 数组名 = 指向首元素的指针

数组名在大多数情况下会退化为指向首元素的常量指针:

cpp 复制代码
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // p 指向 arr[0]

std::cout << arr[2] << std::endl;    // 3
std::cout << *(p + 2) << std::endl;  // 3(等价写法)
表达式 含义
arr 数组首元素地址
*arr 首元素的值
arr + i 第 i 个元素的地址
*(arr + i) 第 i 个元素的值(等价于 arr[i]

二、二维数组与行指针

2.1 内存布局:按行优先

二维数组在内存中是按行连续 存储的,例如 int m[2][3]

复制代码
内存布局:m[0][0] m[0][1] m[0][2] m[1][0] m[1][1] m[1][2]

2.2 行指针:指向一行的指针

cpp 复制代码
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};

// matrix 退化为指向第一行的行指针(类型:int (*)[3])
int (*p_row)[3] = matrix;

std::cout << matrix[1][2] << std::endl;            // 6
std::cout << *(*(p_row + 1) + 2) << std::endl;     // 6(行指针方式)

// p_row + 1 → 跳过一整行(3个int),指向第二行
// *(p_row + 1) → 第二行的首地址(int* 类型)
// *(p_row + 1) + 2 → 第二行第 3 个元素的地址
// *(*(p_row + 1) + 2) → 第二行第 3 个元素的值

2.3 指针数组 vs 数组指针

这是一对容易混淆的概念------注意括号位置

cpp 复制代码
int *ptr_arr[5];      // 指针数组:5个指针的数组,每个指向int
int (*arr_ptr)[5];    // 数组指针:1个指针,指向包含5个int的数组
类型 本质 示例含义
int *p[5] 数组 有 5 个 int* 元素的数组
int (*p)[5] 指针 指向「含 5 个 int 的数组」的指针

三、字符串:从 C 风格到 std::string

3.1 C 风格字符串

C 风格字符串本质是字符数组 ,以空字符 \0 作为结束标志:

cpp 复制代码
char str1[] = "hello";                          // 自动在末尾加 '\0',数组大小为 6
char str2[6] = {'h', 'e', 'l', 'l', 'o', '\0'}; // 手动添加尾零
char str3[10] = "world";                        // 剩余 4 个位置补 '\0'

std::cout << strlen(str1) << std::endl;  // 5(不计算 '\0')

关于 '\0'' ' 的区别:

字符 ASCII 码 含义
'\0' 0 字符串结束标记(非打印字符),不计算长度
' ' 32 普通空格字符(打印字符),计算长度

空字符串 "" 只包含一个 '\0',长度为 0。

3.2 std::string:现代 C++ 的首选

C 风格字符串容易出错(缓冲区溢出、忘记 \0),std::string 类自动管理内存,更安全方便:

cpp 复制代码
#include <string>

std::string s1 = "hello";
std::string s2;
std::cin >> s2;                            // 输入字符串

std::cout << s1.length() << std::endl;     // 获取长度:5
std::cout << s1 + " " + s2 << std::endl;   // 字符串拼接:hello world

// 像访问数组一样访问单个字符
std::cout << s1[0] << std::endl;           // 'h'
s1[0] = 'H';                               // 修改

四、结构体:自定义你的复合数据类型

4.1 什么是结构体?

结构体允许你将不同类型的数据打包成一个有意义的整体:

cpp 复制代码
struct Student {
    std::string name;   // 姓名
    int id;             // 学号
    float score;        // 成绩
};

4.2 创建和使用

cpp 复制代码
Student s1;
s1.name = "张三";
s1.id = 2023001;
s1.score = 95.5;

std::cout << "姓名: " << s1.name << std::endl;
std::cout << "成绩: " << s1.score << std::endl;

4.3 C++ struct vs class

特性 struct class
默认成员权限 public private
默认继承方式 public private
能包含函数 ✅ 可以 ✅ 可以
约定用法 简单数据集合 复杂行为封装

💡 语法上两者几乎等价,只是默认权限不同。平时用 struct 存数据,用 class 做封装。

五、枚举:给整数起个有意义的名字

枚举把一组整型常量变成有意义的名称,告别"魔法数字":

cpp 复制代码
enum Weekday {
    Monday,     // 0
    Tuesday,    // 1
    Wednesday,  // 2
    Thursday,   // 3
    Friday,     // 4
    Saturday,   // 5
    Sunday      // 6
};

Weekday today = Wednesday;
if (today == Wednesday) {
    std::cout << "今天星期三!" << std::endl;
}
// 输出:今天星期三!

也可以手动指定值:

cpp 复制代码
enum Status { Success = 0, Warning = 10, Error = 20 };

小结

序号 知识点 一句话总结
1 一维数组 同类型数据连续存储,下标从 0 开始,越界会引发未定义行为
2 二维数组 按行优先存储,数组名退化为行指针
3 指针数组 vs 数组指针 看括号位置------*p[n] 是数组,(*p)[n] 是指针
4 C 风格字符串 字符数组 + \0 结尾
5 std::string 现代 C++ 字符串,自动管理内存,推荐使用
6 结构体 把不同类型数据打包成一个整体
7 枚举 给整型常量起名,提高可读性

下一篇文章,我们将进入 C++ 的核心------函数进阶:重载、默认参数、内联函数、回调与递归等高级用法。


本文是「C++ 从基础到项目实战」系列的第 2 篇。关注我,不错过后续更新。

相关推荐
博客180014 小时前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴15 小时前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake
众少成多积小致巨1 天前
JNI (Java Native Interface) 技术手册中文参考指南
android·java·c++
clint4565 天前
C++进阶(1)——前景提要
c++
夜悊6 天前
C++代码示例:进制数简单生成工具
c++
郝学胜_神的一滴6 天前
CMake 021: IF 条件判据详诠
c++·cmake
_wyt0016 天前
洛谷 B3930 [GESP202312 五级] 烹饪问题 题解
c++·gesp
LDR0066 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术6 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
码云数智-园园6 天前
C++20 Modules 模块详解
java·开发语言·spring