请关注我!我将后续上传视频讲解!(保姆级程度)
一、数组 --- Array
数组是同类型数据的连续存储结构 ,通过 "类型+数组名+长度" 声明,元素通过下标访问(从0开始),核心特点是"连续存储、同类型、固定长度(静态联编)"。
1.1 数组的声明与初始化
-
C++ 数组初始化方式对照表
初始化方式 语法示例 说明 传统初始化(带 =)int arr1[5] = {1,2,3,4,5};初始化所有元素,长度必须≥初始化值数量 部分初始化 int arr2[5] = {1,2};未初始化元素默认为0 省略长度(编译器推断) int arr3[] = {1,2,3};长度由初始化值数量决定(此处为3) C++11列表初始化(无 =)int arr4[5]{1,2,3,4,5};禁止缩窄转换(如 int arr{3.14}报错)全部初始化为0 int arr5[5] = {0};或int arr5[5]{};第一个元素为0,其余默认0 -
代码示例
cpp#include <iostream> using namespace std; int main() { // 1. 基本声明与初始化 int scores[5] = {90, 85, 95, 88, 92}; // 传统初始化 double weights[] = {65.5, 72.3, 58.9}; // 省略长度(编译器推断为3) char chars[4]{'a', 'b', 'c', 'd'}; // C++11列表初始化 // 2. 部分初始化与默认值 int nums[5] = {1, 2}; // 未初始化元素默认为0 → [1,2,0,0,0] int zeros[3]{}; // 全部初始化为0 → [0,0,0] // 3. 访问数组元素(下标从0开始) cout << "scores[0] = " << scores[0] << endl; // 90 cout << "weights[2] = " << weights[2] << endl;// 58.9 // 4. 遍历数组(结合for循环) cout << "chars数组元素:"; for (int i = 0; i < 4; ++i) { cout << chars[i] << " "; // 输出:a b c d } cout << endl; // 5. 数组长度计算(sizeof(数组名)/sizeof(元素类型)) int arr_len = sizeof(scores) / sizeof(int); cout << "scores数组长度:" << arr_len << endl; // 5 return 0; }
1.2 数组的核心特性
- 固定长度 :数组长度在编译时确定(静态联编),无法在运行时修改(如
int n=5; int arr[n];报错,需用动态数组解决); - 连续存储 :元素在内存中连续排列,下标访问本质是"数组首地址+偏移量"(如
arr[i]等价于*(arr+i)); - 无边界检查 :编译器不检查下标是否越界(如
arr[10]在长度为5的数组中访问,可能导致内存损坏)。
1.3 结合 cin、cout 和 const
-
用
cin输入数组元素,cout输出数组cpp#include <iostream> using namespace std; int main() { const int LEN = 3; // 第三章const:限定数组长度为常量 int arr[LEN]; // 第二章cin:输入数组元素 cout << "请输入" << LEN << "个整数:"; for (int i = 0; i < LEN; ++i) { cin >> arr[i]; // 逐个输入元素 } // 第二章cout:输出数组元素 cout << "你输入的数组:"; for (int i = 0; i < LEN; ++i) { cout << arr[i] << " "; // 输出:如输入1 2 3 → 1 2 3 } cout << endl; return 0; } -
const限定"只读数组"(元素不可修改)cpp#include <iostream> using namespace std; int main() { // 第三章const:限定数组元素只读(初始化后不可修改) const int months[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; // 第二章cout:输出只读数组 cout << "1月天数:" << months[0] << endl; // 31 cout << "2月天数:" << months[1] << endl; // 28 // months[1] = 29; // 错误:const数组元素不可修改 return 0; }
二、字符串 --- String
2.1 C-风格字符串
本质是"以\0(ASCII码0)结尾的字符数组",\0是字符串结束标志,否则会导致"内存越界访问"。
-
声明与初始化
cpp#include <iostream> #include <cstring> // 字符串处理函数(strlen、strcpy等) using namespace std; int main() { // 1. 直接用字符串常量初始化(自动添加\0) char str1[10] = "hello"; // 存储:'h','e','l','l','o','\0',0,0,0,0 char str2[] = "world"; // 长度由编译器推断(6:5个字符+1个\0) // 2. 手动添加\0(必须) char str3[6] = {'h','i','\0'}; // 正确:显式添加\0 // char str4[2] = {'h','i'}; // 错误:无\0,不是合法C-风格字符串 // 3. 字符串长度计算(strlen:不包含\0;sizeof:包含所有字符) cout << "str1长度(strlen):" << strlen(str1) << endl; // 5(不含\0) cout << "str1占用内存(sizeof):" << sizeof(str1) << endl; // 10(数组总长度) // 4. 字符串拼接(strcat:目标数组必须足够大) char str5[20] = "Hello, "; strcat(str5, str2); // 拼接str2到str5 → "Hello, world" cout << "拼接后str5:" << str5 << endl; // 5. 字符串复制(strcpy:避免目标数组溢出) char str6[10]; strcpy(str6, "copy"); // 复制"copy"到str6 → "copy\0" cout << "str6:" << str6 << endl; return 0; } -
cin/cout处理C-风格字符串cpp#include <iostream> #include <cstring> using namespace std; int main() { char name[20]; char greeting[50] = "Hello, "; // 第二章cin:输入字符串(遇空格/换行结束) cout << "请输入你的名字:"; cin >> name; // 如输入"Zhang San",仅读取"Zhang"(空格截断) // 字符串拼接+第二章cout输出 strcat(greeting, name); cout << greeting << "!" << endl; // 输出:Hello, Zhang! // 解决空格问题:用cin.getline()读取整行(第二章知识点) char full_name[30]; cin.ignore(); // 忽略上一次cin遗留的换行符 cout << "请输入你的全名:"; cin.getline(full_name, 30); // 读取整行(含空格) cout << "全名:" << full_name << endl; // 如输入"Zhang San",完整读取 return 0; }
2.2 C++ string 类(推荐)
string类是C++标准库提供的字符串类型,封装了字符数组的操作,支持"自动内存管理、赋值、拼接"等便捷操作,无需手动处理\0。
-
string类的基本用法-
声明与初始化
string类的初始化方式灵活,支持多种语法,涵盖传统C++和C++11新增的列表初始化。初始化方式 语法示例 说明 默认初始化 string str;创建空字符串,长度为0,内存占用为默认(如16字节) 字符串常量初始化 string str = "hello";用C-风格字符串初始化,自动添加 \0(底层维护)构造函数初始化 string str("world");显式调用构造函数,效果与 string str = "world"一致列表初始化(C++11) string str{"C++11"};支持空列表初始化( string str{};),等价于默认初始化截取子串初始化 string str("abcdef", 2, 3);从索引2开始,截取3个字符("cde") 重复字符初始化 string str(5, 'a');创建包含5个'a'的字符串("aaaaa") 拷贝初始化 string str1 = str2;/string str1(str2);用已有的 string对象拷贝初始化新对象 -
核心成员函数
string类的成员函数覆盖字符串的常见操作,以下是最常用的函数。成员函数 功能描述 示例( string str = "hello world";)size()/length()获取字符串长度(不含底层 \0)str.size()→ 11empty()判断字符串是否为空(长度为0返回 true)str.empty()→falseclear()清空字符串(长度变为0,内存可能保留) str.clear();→str.empty()→truec_str()转换为C-风格字符串(返回 const char*)cout << str.c_str();→ 输出"hello world"substr(pos, len)截取子串:从 pos开始,长度为len(len省略则取到末尾)str.substr(6, 5)→ "world"find(sub, pos)从 pos开始查找子串sub,返回首次出现的索引(未找到返回string::npos)str.find("world")→ 6replace(pos, len, sub)从 pos开始,替换len个字符为substr.replace(5, 1, "-")→ "hello-world"push_back(ch)在字符串末尾追加单个字符 str.push_back('!')→ "hello world!"append(str)在字符串末尾追加另一个 string或char*str.append("!!!")→ "hello world!!!" -
运算符重载
string类重载了多种运算符,语法与基本类型一致,降低使用成本。运算符 功能描述 示例 =赋值:将右侧字符串赋值给左侧 string对象string str1; str1 = "test";→ str1 = "test"+拼接:将两个字符串合并为一个新 string对象string str = "a" + "b";→ 错误(需至少一个string);string str = string("a") + "b";→ "ab"+=追加:将右侧字符串追加到左侧 string末尾string str = "a"; str += "b";→ "ab"==/!=比较:按字符ASCII码逐位比较,区分大小写 "abc" == "Abc"→false;"abc" != "abd"→true</>/<=/>=大小比较:按字典序(ASCII码顺序) "apple" < "banana"→true('a' < 'b')[]下标访问:获取/修改指定索引的字符(无边界检查) string str = "abc"; str[1] = 'x';→ "axc"at(pos)安全访问:获取/修改指定索引的字符(有边界检查,越界抛 out_of_range异常)str.at(1) = 'y';→ "ayc";str.at(10)→ 抛异常 -
注意事项
-
头文件依赖 :使用
string类必须包含<string>头文件,且string位于std名称空间(需加using namespace std;或显式写std::string)。错误示例:
#include <cstring>(仅用于C-风格字符串,不包含string类)。 -
与C-风格字符串的转换 :
string转char*: 通过c_str()成员函数,返回const char*(不可修改,若string被修改,返回的指针可能失效)。
char*转string: 直接赋值(string str = "hello";)或通过构造函数(string str("world");),string会自动处理\0。 -
空字符串判断 :推荐用
empty()成员函数(效率更高),而非size() == 0(两者效果一致,但empty()是专门优化的接口)。 -
下标访问的边界问题:
[]运算符无边界检查,若访问索引超出size()-1,会导致未定义行为(如内存损坏)。- 安全访问用
at(pos),越界时会抛出std::out_of_range异常,便于调试。
-
string的长度与容量 :
size()/length(): 返回字符串的实际字符数(不含底层\0)。
capacity(): 返回string当前分配的内存可存储的字符数(大于等于size()),扩容时capacity()会翻倍(减少内存分配次数)。若需释放多余内存,可调用
shrink_to_fit()(C++11),但该函数仅为"建议",编译器可能忽略。 -
字符串拼接的陷阱 :
直接用
"a" + "b"会报错,因为两个操作数都是char*类型,C++不会自动转换为string;需显式将其中一个转为string(如string("a") + "b")。
-
-
-
string类的代码示例-
基本初始化与常用操作
cpp#include <iostream> #include <string> // 必须包含string头文件 using namespace std; // 引入std名称空间,避免频繁写std::string int main() { // 1. 多种初始化方式 string str1; // 默认初始化:空字符串 string str2 = "hello"; // 字符串常量初始化 string str3("world"); // 构造函数初始化 string str4{"C++11 list"}; // C++11列表初始化 string str5(3, '!'); // 重复字符初始化:"!!!" string str6 = str2 + " " + str3; // 拼接初始化:"hello world" // 2. 输出字符串(直接用cout,无需处理\0) cout << "str2: " << str2 << endl; // 输出:str2: hello cout << "str6: " << str6 << endl; // 输出:str6: hello world cout << "str5: " << str5 << endl; // 输出:str5: !!! // 3. 核心成员函数使用 cout << "\n--- 核心成员函数 ---" << endl; cout << "str6长度(size()): " << str6.size() << endl; // 输出:11 cout << "str1是否为空(empty()): " << boolalpha << str1.empty() << endl; // 输出:true cout << "str6的子串(substr(6,5)): " << str6.substr(6, 5) << endl; // 输出:world cout << "str6中查找\"world\"(find()): " << str6.find("world") << endl; // 输出:6 // 4. 运算符重载使用 cout << "\n--- 运算符重载 ---" << endl; str2 += " C++"; // 追加字符串:str2 = "hello C++" cout << "str2追加后: " << str2 << endl; // 输出:str2追加后: hello C++ string str7 = str2; // 赋值运算符:str7 = "hello C++" if (str2 == str7) { // 比较运算符:判断是否相等 cout << "str2 == str7" << endl; // 输出:str2 == str7 } str7[6] = 'c'; // 下标访问:修改字符(str7 = "hello c++") cout << "str7修改后: " << str7 << endl; // 输出:str7修改后: hello c++ // 5. 清空与重新赋值 cout << "\n--- 清空与重新赋值 ---" << endl; str1 = "I'm a new string"; // 空字符串赋值 cout << "str1赋值后: " << str1 << endl; // 输出:str1赋值后: I'm a new string str1.clear(); // 清空字符串 cout << "str1清空后是否为空: " << str1.empty() << endl; // 输出:true return 0; } -
与C-风格字符串的转换
cpp#include <iostream> #include <string> #include <cstring> // 用于C-风格字符串函数(如strlen) using namespace std; int main() { // 1. C-风格字符串转string(直接赋值/构造) const char* c_str = "C-style string"; // C-风格字符串(const char*) string str1 = c_str; // 直接赋值转换 string str2(c_str, 7); // 截取前7个字符:"C-style" cout << "str1(C-风格转string): " << str1 << endl; // 输出:C-style string cout << "str2(截取C-风格字符串): " << str2 << endl; // 输出:C-style // 2. string转C-风格字符串(通过c_str()) string str3 = "Convert to C-style"; const char* converted_c_str = str3.c_str(); // 必须用const char*接收 cout << "\nstr3转C-风格字符串: " << converted_c_str << endl; // 输出:Convert to C-style cout << "C-风格字符串长度(strlen): " << strlen(converted_c_str) << endl; // 输出:18 // 注意:c_str()返回的指针有效期与str3绑定,若str3被修改,指针可能失效 str3 += "!!!"; // 修改str3,converted_c_str可能变为野指针 // cout << converted_c_str << endl; // 危险:可能输出乱码或崩溃,需重新调用c_str() converted_c_str = str3.c_str(); // 重新获取指针 cout << "str3修改后转C-风格: " << converted_c_str << endl; // 输出:Convert to C-style!!! return 0; } -
安全访问与异常处理
cpp#include <iostream> #include <string> #include <stdexcept> // 用于捕获out_of_range异常 using namespace std; int main() { string str = "hello world"; // 1. 下标访问(无边界检查,越界会导致未定义行为) cout << "str[4](合法下标): " << str[4] << endl; // 输出:o // cout << str[20] << endl; // 危险:下标越界,可能崩溃或输出乱码 // 2. at()访问(有边界检查,越界抛异常) cout << "\n--- at()安全访问 ---" << endl; try { cout << "str.at(4)(合法下标): " << str.at(4) << endl; // 输出:o str.at(20) = 'x'; // 越界,抛出out_of_range异常 } catch (const out_of_range& e) { // 捕获异常并处理 cout << "访问异常: " << e.what() << endl; // 输出:访问异常: basic_string::at: __n (which is 20) >= this->size() (which is 11) } // 3. 空字符串的安全判断 string empty_str; if (empty_str.empty()) { // 推荐用empty(),而非size() == 0 cout << "\nempty_str is empty" << endl; // 输出:empty_str is empty } return 0; } -
字符串的查找与替换
cpp#include <iostream> #include <string> using namespace std; int main() { string str = "I like C++, C++ is easy to learn!"; // 1. 查找子串(find()) cout << "--- 查找子串 ---" << endl; size_t pos1 = str.find("C++"); // 首次出现"C++"的索引 if (pos1 != string::npos) { // 判断是否找到(string::npos表示未找到) cout << "首次找到\"C++\"的索引: " << pos1 << endl; // 输出:7 } size_t pos2 = str.find("C++", pos1 + 1); // 从pos1+1开始查找下一个"C++" if (pos2 != string::npos) { cout << "第二次找到\"C++\"的索引: " << pos2 << endl; // 输出:11 } // 2. 替换子串(replace()) cout << "\n--- 替换子串 ---" << endl; string new_str = "C++20"; // 从pos1开始,替换3个字符为new_str("C++"→"C++20") str.replace(pos1, 3, new_str); cout << "替换后str: " << str << endl; // 输出:I like C++20, C++ is easy to learn! // 3. 查找单个字符(find_first_of()) size_t pos3 = str.find_first_of("aeiou"); // 首次出现元音字母的索引 if (pos3 != string::npos) { cout << "\n首次出现元音字母的索引: " << pos3 << endl; // 输出:1 cout << "首次出现的元音字母: " << str[pos3] << endl; // 输出:i } return 0; }
-
-
const限定只读string与cin/coutcpp#include <iostream> #include <string> using namespace std; int main() { // 第三章const:限定string对象只读(不可修改内容) const string fixed_str = "固定字符串"; // fixed_str = "修改"; // 错误:const限定不可修改 // 第二章cin:输入string(支持空格,无需指定长度) string user_input; cout << "请输入一段文本(含空格):"; getline(cin, user_input); // 读取整行(比cin.getline()更简洁) // 第二章cout:输出拼接结果 string result = fixed_str + " → " + user_input; cout << "结果:" << result << endl; // 如输入"test" → 固定字符串 → test return 0; }
三、结构 --- Structure
结构是不同类型数据的组合 ,通过struct关键字定义,可存储多个不同类型的成员(如整型、字符串、指针等),核心特点是 "封装不同类型数据,形成自定义复合类型"。
3.1 结构的声明与使用
-
基本语法: 定义结构类型→创建结构变量→访问成员
cpp#include <iostream> #include <string> using namespace std; // 1. 定义结构类型(外部声明,所有函数可使用) struct Student { // 成员变量(不同类型) string name; // string类成员 int age; // 整型成员 double score; // 浮点型成员 }; // 注意分号 int main() { // 2. 创建结构变量并初始化 Student s1 = {"Zhang San", 18, 92.5}; // 传统初始化 Student s2{"Li Si", 19, 88.0}; // C++11列表初始化 Student s3; // 默认初始化(成员为默认值) // 3. 访问成员(用成员运算符.) s3.name = "Wang Wu"; s3.age = 17; s3.score = 95.0; // 4. 输出结构成员(结合第二章cout) cout << "学生1:" << endl; cout << "姓名:" << s1.name << endl; cout << "年龄:" << s1.age << endl; cout << "成绩:" << s1.score << endl; // 5. 结构赋值(成员逐一赋值) Student s4 = s1; // s4的name、age、score与s1完全相同 cout << "学生4姓名:" << s4.name << endl; // Zhang San return 0; } -
结构数组(数组元素为结构)
cpp#include <iostream> #include <string> using namespace std; struct Book { string title; string author; double price; }; int main() { // 定义结构数组并初始化 Book books[2] = { {"C++ Primer Plus", "Stephen Prata", 89.0}, {"Effective C++", "Scott Meyers", 78.5} }; // 遍历结构数组(结合for循环与cout) cout << "图书列表:" << endl; for (int i = 0; i < 2; ++i) { cout << "书名:" << books[i].title << endl; cout << "作者:" << books[i].author << endl; cout << "价格:" << books[i].price << "元" << endl; cout << "------------------------" << endl; } return 0; }
3.2 const限定只读结构与cin输入
cpp
#include <iostream>
#include <string>
using namespace std;
struct Product {
string name;
double price;
int stock;
};
// 函数参数:const限定结构(防止函数修改结构成员)
void printProduct(const Product& p) { // 引用传递(避免拷贝,后续章节讲解)
cout << "商品名称:" << p.name << endl;
cout << "商品价格:" << p.price << "元" << endl;
cout << "库存数量:" << p.stock << endl;
// p.price = 100; // 错误:const限定不可修改
}
int main() {
Product p;
// 第二章cin:输入结构成员
cout << "请输入商品信息:" << endl;
cout << "名称:";
cin >> p.name;
cout << "价格:";
cin >> p.price;
cout << "库存:";
cin >> p.stock;
// 调用函数输出(const结构作为参数)
printProduct(p);
return 0;
}
四、共用体 --- Union
共用体是同一内存空间存储不同类型数据的结构 ,所有成员共享同一块内存,同一时间只能存储一个成员的值,核心特点是 "节省内存(适合多类型数据不同时使用的场景)"。
4.1 共用体的声明与使用
cpp
#include <iostream>
#include <string>
using namespace std;
// 定义共用体(成员共享内存)
union Data {
int i; // 4字节
double d; // 8字节
char c; // 1字节
}; // 共用体大小为最大成员的大小(此处为8字节)
int main() {
Data data;
// 1. 存储int类型
data.i = 100;
cout << "存储int:" << data.i << endl; // 100
// cout << data.d << endl; // 错误:当前存储的是int,读取double为垃圾值
// 2. 存储double类型(覆盖int的值)
data.d = 3.14;
cout << "存储double:" << data.d << endl; // 3.14
// cout << data.i << endl; // 错误:当前存储的是double,读取int为垃圾值
// 3. 存储char类型(覆盖double的值)
data.c = 'A';
cout << "存储char:" << data.c << endl; // A
cout << "char的ASCII码:" << static_cast<int>(data.c) << endl; // 65
// 4. 共用体大小(等于最大成员的大小)
cout << "共用体Data大小:" << sizeof(data) << endl; // 8(double的大小)
return 0;
}
4.2 共用体结合enum(枚举)与cout
cpp
#include <iostream>
#include <string>
using namespace std;
// 枚举:标识共用体当前存储的类型(后续"枚举"章节讲解)
enum DataType { INT, DOUBLE, CHAR };
union Value {
int i;
double d;
char c;
};
struct TaggedValue {
DataType type; // 标识当前存储的类型
Value val; // 共用体:存储实际值
};
int main() {
TaggedValue tv;
// 存储int类型
tv.type = INT;
tv.val.i = 200;
// 存储double类型
// tv.type = DOUBLE;
// tv.val.d = 5.67;
// 根据类型输出(结合第二章cout)
switch (tv.type) {
case INT:
cout << "值(int):" << tv.val.i << endl; // 200
break;
case DOUBLE:
cout << "值(double):" << tv.val.d << endl;
break;
case CHAR:
cout << "值(char):" << tv.val.c << endl;
break;
default:
cout << "未知类型" << endl;
}
return 0;
}
五、枚举 --- Enumeration
枚举是用户定义的整数类型 ,通过enum关键字定义一组"符号常量"(枚举量),核心作用是 "用有意义的名称替代魔法数字,提升代码可读性"。
5.1 枚举的声明与使用
-
基本枚举(不限定作用域)
cpp#include <iostream> using namespace std; // 1. 定义枚举类型(枚举量默认值:0,1,2,3,4) enum Color { RED, GREEN, BLUE, YELLOW, PURPLE }; // 2. 显式指定枚举量值 enum Weekday { MON = 1, TUE, WED, THU, FRI, SAT, SUN }; // TUE=2,依次递增 int main() { // 3. 创建枚举变量 Color c = BLUE; Weekday day = MON; // 4. 输出枚举量(本质是整数,结合第二章cout) cout << "BLUE对应的整数:" << BLUE << endl; // 2(默认值) cout << "当前颜色:" << c << endl; // 2(BLUE) cout << "周一对应的整数:" << day << endl; // 1(MON=1) // 5. 枚举量比较(本质是整数比较) if (c == BLUE) { cout << "当前颜色是蓝色" << endl; // 成立 } // 6. 枚举量赋值(只能赋值枚举量,不能直接赋值整数) c = RED; // 正确 // c = 0; // 错误:需强制转换 c = static_cast<Color>(0); // 正确:强制转换(0对应RED) return 0; } -
C++11作用域内枚举(
enum class,推荐)避免枚举量名称冲突(如不同枚举中的
RED冲突),需显式指定作用域。cpp#include <iostream> using namespace std; // 作用域内枚举:枚举量需通过"枚举名::枚举量"访问 enum class Fruit { APPLE, BANANA, ORANGE }; enum class Color { RED, GREEN, BLUE }; // 与Fruit的RED不冲突 int main() { Fruit f = Fruit::APPLE; Color c = Color::RED; // 输出:需强制转换为整数(作用域内枚举不自动隐式转换) cout << "Fruit::APPLE = " << static_cast<int>(f) << endl; // 0 cout << "Color::RED = " << static_cast<int>(c) << endl; // 0 // 错误:不同枚举的枚举量不可比较 // if (f == c) {} // 编译器报错 return 0; }
5.2 const与枚举结合(固定枚举映射)
cpp
#include <iostream>
using namespace std;
// 枚举:月份
enum Month { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
int main() {
// 第三章const:限定每月天数为常量(与枚举映射)
const int DAYS_IN_MONTH[] = {31,28,31,30,31,30,31,31,30,31,30,31};
// 输入月份(第二章cin)
int input_month;
cout << "请输入月份(1-12):";
cin >> input_month;
// 转换为枚举(需检查合法性)
if (input_month < 1 || input_month > 12) {
cout << "无效月份" << endl;
return 1;
}
Month m = static_cast<Month>(input_month - 1); // 1→JAN(0)
// 输出天数(第二章cout)
cout << input_month << "月有" << DAYS_IN_MONTH[m] << "天" << endl; // 如输入2→28
return 0;
}
六、指针 --- Pointer
指针是存储内存地址的变量 ,核心作用是 "间接访问内存、实现动态内存管理、传递大型数据(避免拷贝)" ,语法关键是"*(解引用,访问地址对应的值)"和"&(取地址,获取变量的内存地址)"。
6.1 指针的声明与基本操作
cpp
#include <iostream>
using namespace std;
int main() {
// 1. 声明指针(类型需与指向的变量一致)
int num = 100;
int* p_num = # // p_num存储num的地址(&是取地址运算符)
double pi = 3.14;
double* p_pi = π
// 2. 解引用指针(*p访问地址对应的值)
cout << "num的值:" << num << endl; // 100
cout << "p_num指向的值:" << *p_num << endl; // 100(解引用)
cout << "num的地址:" << &num << endl; // 如0x0065fd40
cout << "p_num存储的地址:" << p_num << endl;// 如0x0065fd40
// 3. 修改指针指向的值(通过解引用)
*p_num = 200;
cout << "修改后num的值:" << num << endl; // 200
// 4. 指针算术(指针+1,偏移量为指向类型的大小)
int arr[3] = {1,2,3};
int* p_arr = arr; // 数组名本质是首元素地址(arr = &arr[0])
cout << "p_arr指向的值:" << *p_arr << endl; // 1(arr[0])
p_arr++; // 指针+1,偏移4字节(int大小),指向arr[1]
cout << "p_arr++后指向的值:" << *p_arr << endl; // 2(arr[1])
return 0;
}
6.2 动态内存管理 --- new/delete
指针的核心应用之一是"动态内存分配"------在运行时(而非编译时)分配内存,通过new申请内存,delete释放内存,避免内存泄漏。
-
动态分配基本类型
cpp#include <iostream> using namespace std; int main() { // 1. 动态分配int(new返回内存地址,赋值给指针) int* p_int = new int; // 申请4字节内存 *p_int = 50; // 给动态内存赋值 cout << "动态int的值:" << *p_int << endl; // 50 // 2. 动态分配double double* p_double = new double(3.14); // 初始化:分配内存并赋值3.14 cout << "动态double的值:" << *p_double << endl; // 3.14 // 3. 释放动态内存(必须!避免内存泄漏) delete p_int; // 释放int内存 delete p_double; // 释放double内存 p_int = nullptr; // 指针置空(避免野指针) p_double = nullptr; return 0; } -
动态分配数组(
new[]/delete[])cpp#include <iostream> using namespace std; int main() { int n; // 第二章cin:输入数组长度(运行时确定,动态联编) cout << "请输入数组长度:"; cin >> n; // 动态分配数组(new[],返回首元素地址) int* p_dyn_arr = new int[n]; // 分配n个int的连续内存 // 给动态数组赋值 for (int i = 0; i < n; ++i) { p_dyn_arr[i] = i * 10; // 如n=3 → [0,10,20] } // 第二章cout:输出动态数组 cout << "动态数组元素:"; for (int i = 0; i < n; ++i) { cout << p_dyn_arr[i] << " "; // 0 10 20 } cout << endl; // 释放动态数组(必须用delete[],不能用delete) delete[] p_dyn_arr; p_dyn_arr = nullptr; return 0; }
6.3 const 限定指针与动态结构
cpp
#include <iostream>
#include <string>
using namespace std;
struct Person {
string name;
int age;
};
int main() {
// 1. 动态分配结构(new+结构)
Person* p_person = new Person;
// 第二章cin:输入结构成员(指针访问成员用->)
cout << "请输入姓名:";
cin >> p_person->name; // 指针访问成员:->(替代.)
cout << "请输入年龄:";
cin >> p_person->age;
// 2. const限定指针(两种场景)
const Person* p_const_person = p_person; // 指向的结构不可修改(成员只读)
// p_const_person->age = 20; // 错误:成员不可修改
Person* const const_p_person = p_person; // 指针本身不可修改(地址固定)
// const_p_person = new Person; // 错误:指针地址不可修改
// 第二章cout:输出结构成员
cout << "姓名:" << p_const_person->name << endl; // 如"Zhang"
cout << "年龄:" << p_const_person->age << endl; // 如18
// 释放动态结构
delete p_person;
p_person = nullptr;
return 0;
}
七、数组的替代品 --- vector/array
C++标准库提供了更安全、灵活的数组替代品:vector(动态数组,堆内存)和array(固定长度数组,栈内存),解决了原生数组"无边界检查、长度固定"的问题。
7.1 模板类vector(动态数组)
cpp
#include <iostream>
#include <vector> // 必须包含vector头文件
using namespace std;
int main() {
// 1. 声明与初始化
vector<int> vec1; // 空vector(长度0)
vector<int> vec2(5, 0); // 长度5,所有元素为0 → [0,0,0,0,0]
vector<int> vec3 = {1,2,3,4,5}; // 传统初始化
vector<int> vec4{6,7,8}; // C++11列表初始化
// 2. 动态添加元素(自动扩容)
vec1.push_back(10); // vec1 → [10]
vec1.push_back(20); // vec1 → [10,20]
// 3. 访问元素(下标或at(),at()有边界检查)
cout << "vec3[2] = " << vec3[2] << endl; // 3(无边界检查)
cout << "vec3.at(2) = " << vec3.at(2) << endl; // 3(有边界检查,越界抛异常)
// 4. 长度与遍历
cout << "vec1长度:" << vec1.size() << endl; // 2
cout << "vec1元素:";
for (int i = 0; i < vec1.size(); ++i) {
cout << vec1[i] << " "; // 10 20
}
cout << endl;
return 0;
}
7.2 模板类array(C++11,固定长度)
cpp
#include <iostream>
#include <array> // 必须包含array头文件
using namespace std;
int main() {
// 1. 声明与初始化(长度必须是常量,静态联编)
array<int, 5> arr1 = {1,2,3,4,5}; // 传统初始化
array<int, 5> arr2{6,7,8,9,10}; // C++11列表初始化
array<int, 5> arr3; // 默认初始化(元素为随机值)
// 2. 赋值(同类型同长度array可直接赋值)
arr3 = arr1; // arr3 → [1,2,3,4,5]
// 3. 访问与遍历(支持下标、at(),有边界检查)
cout << "arr2.at(3) = " << arr2.at(3) << endl; // 9
cout << "arr3元素:";
for (auto val : arr3) { // 范围for循环(C++11)
cout << val << " "; // 1 2 3 4 5
}
cout << endl;
// 4. 长度(固定,size()为编译时常量)
cout << "arr1长度:" << arr1.size() << endl; // 5
return 0;
}
7.3 vector结合cin/cout与const
cpp
#include <iostream>
#include <vector>
using namespace std;
// 函数参数:const限定vector(只读,防止修改)
void printVector(const vector<double>& vec) {
cout << "vector元素:";
for (double val : vec) {
cout << val << " "; // 第二章cout输出
}
cout << endl;
}
int main() {
vector<double> vec;
double input;
// 第二章cin:输入元素,直到输入非数字
cout << "请输入若干小数(输入非数字结束):";
while (cin >> input) {
vec.push_back(input); // 动态添加元素
}
// 输出vector(调用函数,const参数)
printVector(vec);
// 计算平均值(结合第三章算术运算)
double sum = 0.0;
for (double val : vec) {
sum += val;
}
if (!vec.empty()) {
cout << "平均值:" << sum / vec.size() << endl; // 如输入1.1 2.2 → 1.65
}
return 0;
}