文章目录
- 数组
- vector
- 字符串
- 输入输出
- 结构体
- 枚举
- 指针
- 引用
- 综合案例
数组
- 相同类型的数据的集合{ },通过索引访问元素;
- 在内存中连续存储,属于顺序表;
- 插入、删除时间复杂度 O ( n ) O(n) O(n),访问复杂度 O ( 1 ) O(1) O(1)
- 定义数组,首先确定内部的数据类型,并指定长度(常量),初始化时只能使用{ }来初始化;
// 定义
int arr[30] = {1, 2, 3}; // 后面的值默认为0,初始值个数不能超过长度// 不指定长度时,需要初始化
double score[] = {79.5, 80.5, 90}; // 访问数组,注意索引越界问题
for(int i=0; i < sizeof(arr) / sizeof(arr[0]) ; i++){cout << "arr[" << i << "]:" << arr[i] << endl;
}// 仅仅获取元素
for(int e:arr){cout << e << endl;
}
- 数组内部嵌套数组,即二维数组
// 定义二维数组
int arr[2][3] = {{1,2,3},{4,5,5}};// 遍历
int rowCount = sizeof(arr) / sizeof(arr[0]);
int colCount = sizeof(arr[0]) / sizeof(arr[0][0]);
for(int i=0; i<rowCount; i++){for(int j=0; j<colCount; j++){cout << arr[i][j] << endl;}
}// 元素遍历
for(auto& row:arr){ // 复合数据类型需要 &引用for(auto e:row){ // auto 自动类型cout <<e << endl; }
}
- 数组实现 选择排序
int main() {int arr[] = {4, 3, 2, 1, 5};// 选择排序O(n^2)// 每次选择最大值或者最小值,放在最后一位// n个数 做n-1次选择int arrLen = sizeof(arr) / sizeof(arr[0]);int n = arrLen - 1;int temp;while (n >= 1) { // 控制选择次数int max_idx = 0; // for (int i = 1; i <= n; i++) {if (arr[i] > arr[max_idx]) {max_idx = i;}}// 交换if (max_idx != n) {// 交换temp = arr[n];arr[n] = arr[max_idx];arr[max_idx] = temp;}n--;}for (int i = 0; i < arrLen; i++) {cout << arr[i] << endl;}
- 数组实现 冒泡排序
int main() {int arr[] = {4, 3, 2, 1, 5};// 冒泡排序 O(n^2)// 每次将较大值向后一位冒泡// n个数 做n-1轮冒泡int arrLen = sizeof(arr) / sizeof(arr[0]);int temp;for (int i = 0; i < arrLen - 1; i++) { // 控制冒泡的轮数// 控制冒泡for (int j = 0; j < arrLen - 1 - i; j++) {if (arr[j] > arr[j + 1]) {temp = arr[j + 1];arr[j + 1] = arr[j];arr[j] = temp;}}}for (int i = 0; i < arrLen; i++) {cout << arr[i] << endl;}// system("dir");system("pause");return 0;
}
vector
- 数组的长度固定,且越界操作可能带来未知的风险,故对数组扩展,得到vector,array;
- vector容器,也是相同类型的数据的集合,长度可变,但性能降低;
- array容器,也是相同类型的数据的集合,长度固定,但性能降低;
#include <vector>
#include <array>
using namespace std; // 必须包含头文件,并使用std int main() {// 容器是对数组的扩展,不定长用vector, 定长用array (也是扩展的数组)// 拷贝初始化vector<int> cont1 = {1, 2, 3}; vector<float> cont2{ 34.5, 46.7 }; // 赋值号可省略// 直接初始化vector<double> cont3(5); // 指定长度为5 可以继续添加数据,扩展长度vector<string> cont4(3, "jack"); // 长度为3,且默认值均为"jack"// 容器 通过索引访问,修改for (int i = 0; i < cont1.size(); i++) {cout << cont1[i] << "\t";}// 添加cont1.push_back(100); // 尾部添加//cont1.pop_back(); // 尾部删除for (int e : cont1) {cout << e << " ";}// 基于数组扩展的array , 固定长度array<string, 5> userList = { "jack", "tom", "lucy" }; // 赋值也可省略// array<string, 5> userList; // userList = { "jack", "tom", "lucy" }; // 先声明,再赋值 userList.size() 长度for (string e : userList) {cout << e << " ";}return 0;
}
字符串
- string类型,也是一个容器,内容可变,通过索引访问每个字符;
- size()方法获取长度,size() - 1是最后一个索引;同数组,也不能越界访问/赋值
- 支持两种for循环
#include <string>
using namespace std;int main() {// c++ 中的string是可变的容器,而python的str是不可变的容器string name; //初始化为空string sex = "male"; //拷贝初始化string addr("wuhan province"); // 直接初始化// 普通的forfor (int i = 0; i < addr.size(); i++) {cout << addr[i] << " "; // 索引访问每个字符}// 元素遍历的forfor (char e : addr) {cout << e << " ";}return 0;
}
- 字符串的拼接
- 字符串变量 + 字符串变量;
- 字符串变量 + 字符串字面量;
字符串字面量 + 字符串字面量
(X); 不同于python
- 字符串的比较
- ==、> >= < <= 逐字符比较;
- c风格的字符串,字符类型的数组;
- {‘a’,‘b’, ‘c’, ‘\0’} , \0为结束字符
- {‘a’,‘b’, ‘c’, ‘\0’} , \0为结束字符
输入输出
- cin 控制台输入,捕获字符串,遇空格则将空格前的整体作为一个字符串,赋值给变量;
string name;
string last_name;
cout << "input your name:"; // 控制台输出
cin >> name ; // 输入"jack li", 只能捕获到 "jack"
cin >> name >> last_name; // 捕获到"li" 赋值给 last_name
- getline 获取一行
string name;
getline(cin, name); // 获取一行,并赋值给name
- cin.get() 获取一个字符
char sex;
sex = cin.get(); // or cin.get(sex)
- fstream 文件操作
- 包含头文件<fstream>;
- ifstream readFile(“xxx.txt”) 读取文件;
- ofstream toFile(“target.txt”) 写入到文件;
- 案例,输入用户的姓名,年龄,学历,性别,电话,保存到 user.txt 文件中,并读取该文件,逐行打印;
#include <iostream>
#include <string> // 字符串的 头文件
#include <fstream> // 文件操作的头文件
using namespace std;// 枚举 性别
enum Sex {Male, // 默认从0开始, 也可以赋值指定从2、4等开始Female
};int main() {// 姓名 学历 手机号string name, stuLevel, phone;int age = 18;string ageLabel = to_string(age); // 整型转为字符串// 性别string sex_label;enum Sex sex = Male;// 用户输入cout << "input your name:";getline(cin, name); // 获取一行 回车则结束本次输入cout << "input your stuLevel:";cin >> stuLevel;cout << "input your phone:";cin >> phone;cout << "input your age and sex separated with whitespace:";cin >> age >> sex_label; // 捕获多个空格分割的字符串// 枚举 重新赋值if (sex_label == "0")sex = Male; // 对应int数值elsesex = Female;// 字符串拼接string totalContent = "姓名:";totalContent += name + "\n" + "年龄:";totalContent += ageLabel + "\n" + "性别:"; // 必须字符串对象开头 开始拼接totalContent += sex_label + "\n" + "学历:";totalContent += stuLevel + "\n" + "手机号:";totalContent += phone;system("cd C:\\Users\\lenovo\\Desktop");// 写入文件ofstream writeToFile("C:\\Users\\lenovo\\Desktop\\user.txt");// << 流输出 到文件对象中writeToFile << totalContent;// 关闭文件对象writeToFile.close();// 读取文件ifstream readFileObj("C:\\Users\\lenovo\\Desktop\\user.txt");//逐单词 读取/*string word;while (readFileObj >> word) {cout << word << endl;}*/// 逐行读取string oneLine;while (getline(readFileObj, oneLine)) {cout << oneLine << endl;}//逐字符读取/*char c;while (readFileObj.get(c)) {cout << c << endl;}*/return 0;
}
结构体
- 结构体是一个复合的数据类型,可以存储不同的数据类型;
- 内部可以定义基本类型;
- 也可以定义结构体类型;
- 通过
.
访问内部属性,并可修改; - 定义学生结构体,包含学生的基本信息;
- 姓名
- 年龄
- 班级
- 同学s
#include <iostream>
#include <string> // 字符串的 头文件
#include <fstream> // 文件操作的头文件
#include <vector> // 变长容器
using namespace std;// 班级结构体
struct StuClass { // 使用struct关键字 定义结构体string name; // 班级的名字int stuNum;string classMaster;
}; // 此行 }后面还可以声明变量,只是不常用// 学生结构体
struct StuInfo {string name;int age;StuClass myClass;vector<StuInfo> myClassmates; // 同学
};//输出一个学生的信息
void printStu(StuInfo stu) {cout << "姓名:" << stu.name << endl;cout << "年龄:" << stu.age << endl;cout << "班级:" << stu.myClass.name << endl;cout << "同学数:" << stu.myClassmates.size() << endl;
}int main() { // 结构体类 c++ 可以直接使用,c中需要带着struct一起使用// 创建班级StuClass class1 = { "三年级01", 30, "teacher wang" }; // 赋值可以省略//创建学生StuInfo stu1 = { "jack", 23, class1, {} };StuInfo stu2 = { "tom", 18, class1, {} };// 为stu2 添加一个同学stu2.myClassmates.push_back(stu1);// 输出学生信息printStu(stu1);printStu(stu2);return 0;
}
枚举
- 把可以取的值,都一 一地列举出来;
- 使用关键字enum定义枚举;
// 如之前使用的性别的枚举
enum Sex{Male, // 默认从0开始, 可以在任意项处指定起始值Female, // 1
}//定义变量
Sex sex = Male; // 以枚举项 赋值
Sex sex1 = Sex(2); // 以整数的强制类型转换赋值,不能直接复制int// 枚举 周工作日
enum WEEK {Mon,Tue,Wed,Thu = 10, // 从10开始Fri,Sat,Sun
};
指针
- 变量即存储数据的地址空间的名字;
- 指针即存储数据的地址空间的地址,即指针变量 存放的是地址;
- 地址占用8bytes;
int main() { int a = 10;int* p; // 指针变量p = &a; // 指针变量 赋值a的地址cout << "指针:" << p << endl;cout << "指针的值:" << *p << endl;// 指针操作改值*p = 20;cout << "修改后的值:" << *p << endl;return 0;
}
- 未初始化的指针,即无效指针(野指针),不可直接使用;
- 空指针,指针赋值nullptr / NULL / 0; 声明指针,必须初始化;
- void* 指针,可以赋值任意类型的地址,但不能解引用;
- int** p ,指向指针的指针;解引用使用** ;
- const int* p, 指向常量的指针,只能赋值常量的地址;
- int* const p, 常量指针, 不可改变量p的地址;
int main() { // 常量const int a = 4, b = 5;// 指向常量的指针const int* p = &a;cout << *p << endl;p = &b;cout << *p << endl;// 指向变量的 常量指针int c = 10;int* const p2 = &c; // 存储地址不可修改cout << *p2 << endl;return 0;
}
- 数组名称为指向内部首元素的地址,即首地址;
- 指针数组,指针组成的数组,int* arr[5];
- 数组指针,代表数组的指针;
int main() { int a = 1, b = 2, c = 3;// 指针组成的数组-->指针数组int* arr[5];arr[0] = &a;arr[1] = &b;arr[3] = &c;cout << *(arr[0]) << endl;cout << *(arr[1]) << endl;// 数组指针-- 指向一个数组的指针int arr2[3];int* p = arr2; // 或者 int(*p)[3]*p = 1;*(p + 1) = 2; // 地址偏移一个数据类型的长度*(p + 2) = 3;for (int e : arr2) {cout << e << endl;}// 数组指针int(*pp)[3]; // *pp 相当于arr2pp = &arr2; // 取地址cout << arr2 << endl; // 数组的首地址cout << pp << endl; // 数组的首地址cout << *pp << endl; // *pp 为arr2 还是首地址cout << **pp << endl; // 解引用首个元素cout << *(*pp + 1) << endl; // 解引用第二个元素return 0;
}
引用
- 引用,是给一个变量起别名,一旦绑定一个变量,再不可绑定其他变量;
- 定义引用, 如 int&
int a = 10;
// 定义引用(必须引用变量)
int& af = a; // 必须 声明同时 初始化,指向同一个内存地址
af = 20;
cout << a << endl; // 20int& aaf = af; // 引用 的引用 使用同引用;
- 常量引用
const int aa = 20;// 常量的引用
const int& aaref = aa; // 引用常量
const int& bbref = 10; // 引用字面量int a = 10;
const int& ccref = a; // 引用变量
- 引用相当于指针常量;
综合案例
- 反转一个数组
- 思路:两边对称的元素互换;
int main() { // 定义数组容器array<int, 5> arr = { 4,3,2,1,5 }; // 两边对换int temp;int n = arr.size();for (int i = 0; i < n / 2; i++) {temp = arr[i];arr[i] = arr[n - 1 - i];arr[n - 1 - i] = temp;}for (int e : arr) {cout << e << " ";}cout << endl;return 0;
}
- 两个字符串相加
- 从个位逐位,没有的一方用0代替;
- label表示进位,有进位则为1(进位最多为1),无进位则为0;
- 从字符串的最后一个索引开始向索引0方向,循环处理;
- 字符串通过索引访问每一个字符,数值字符减去‘0’字符得到其代表的整数值;
- int转为字符串使用 to_string(int);
- 字符串的拼接必须字符串对象在左;
int main() { // 字符串相加string s1 = "39999"; // 可变容器,索引访问,获取一个字符 '2' - '0' 得到对应的数值2string s2 = "2"; // 字符串-->int stoi("5793") stof stodstring result = "";int temp;int s1Idx = s1.size() - 1;int s2Idx = s2.size() - 1;// 表示是否有进位 为1有进位 为0无进位int mid = 0;int a, b;while (s1Idx >= 0 || s2Idx >= 0 || mid) { // 逐位相加,没有则用0代替,特殊情况:两者长度相同,且最后有进位a = s1Idx >= 0 ? s1[s1Idx] - '0' : 0; // 当前字符 减去 '0'字符 得到自己的整数值b = s2Idx >= 0 ? s2[s2Idx] - '0' : 0;// 求和temp = a + b + mid;if (temp <= 9) {// 本次求和没有进位result = to_string(temp) + result; // int 转为 stringmid = 0;}else {// 有进位mid = temp / 10;result = to_string(temp % 10) + result;}s1Idx--;s2Idx--;}cout << "计算结果:" << result << endl;return 0;
}
- 反转一个单向链表,应用的知识点如下。
- 包含自定义的头文件使用#include “xxx.h”
- 空指针初始化 NULL/nullptr,值为0;
- 指针的解引用+调用属性等价于 指针 -> 调用属性;
定义结构体
// 自定义一个头文件lauf.h , 并定义结构体
struct LinkNode {int value;LinkNode* next;
};
主程序
#include <iostream>
#include "lauf.h" // 包含自定义的头文件
using namespace std;// 入口函数
int main() {// 创建单链表 7->8->9->NULL 空指针为0LinkNode* myLink;LinkNode node9 = { 9, nullptr }; // nullptr 空指针 值为0LinkNode node8 = { 8, &node9 };LinkNode node7 = { 7, &node8 };myLink = &node7;// 双指针 方式反转LinkNode* curPtr = myLink;LinkNode* prePtr = nullptr;LinkNode* temp;while (curPtr) { // 指针存在 temp = (*curPtr).next; // 解引用 再调用属性 等价于 curPtr -> nextcurPtr->next = prePtr;// 移动指针prePtr = curPtr;curPtr = temp;}LinkNode* reversedLink = prePtr; // 指针变量赋值 // 打印反转后的链表while (reversedLink) {cout << reversedLink->value << "->"; // -> 等价于 指针的解引用+调用属性reversedLink = reversedLink->next;}return 0;
}
上一篇:C++ 教程 - 01 基础篇
下一篇:函数